diff --git a/bin/unit_tests/assets/html/inline_block_wrap.html b/bin/unit_tests/assets/html/inline_block_wrap.html new file mode 100644 index 000000000..06588f2b6 --- /dev/null +++ b/bin/unit_tests/assets/html/inline_block_wrap.html @@ -0,0 +1,128 @@ + + + + + + +
+
+

It's Mostly Just Text and Media

+

+ Most apps are just that. Text and media in a never-ending, + all-consuming feed or a multi-page form, cleverly disguised by the + user interface. +

+

+ Excluding heavy 3D gaming or utilities that genuinely require deep + integration with your phone's hardware (like accessing the LiDAR + scanner for AR), what are we actually left with? A thin client whose + main job is to fetch data from an API and render it onto native views. +

+

+ Why do I need to download a 100+ MB app, give it permission to track + my location, and let it run background processes just to browse + through a restaurant menu, buy a ticket, or scroll through a list of + posts? At the end of the day, it is almost always just JSON being + parsed and rendered. Yet, companies insist on rebuilding their basic + content as native shells just to claim a permanent square of real + estate on my home screen. +

+

The Enshittification Loop

+

+ When that full-screen modal pops up demanding you download the app to + read the rest of a thread, users choose the path of least resistance. + They download and they move on. +

+
+
+ + diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 21c554d50..5947347e3 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -21,6 +21,13 @@ namespace EE { namespace UI { class UITooltip; class UIStyle; +struct MarginAuto { + static constexpr auto Left = ( 1 << 0 ); + static constexpr auto Right = ( 1 << 1 ); + static constexpr auto Top = ( 1 << 2 ); + static constexpr auto Bottom = ( 1 << 3 ); +}; + /** * @brief Base class for all UI widgets in the eepp framework. * @@ -1324,10 +1331,21 @@ class EE_API UIWidget : public UINode { */ virtual void onWidgetCreated(); + /**@return The property `width` converted as length */ Float getPropertyWidth() const; + /**@return The property `height` converted as length */ Float getPropertyHeight() const; + /* @return The width of the widget when size policy is match_parent */ + Float getMatchParentWidth() const; + + /* @return The height of the widget when size policy is match_parent */ + Float getMatchParentHeight() const; + + /* @return The size of the widget when size policy is match_parent */ + Sizef getSizeFromLayoutPolicy(); + protected: friend class UIManager; friend class UISceneNode; @@ -1359,11 +1377,6 @@ class EE_API UIWidget : public UINode { mutable bool mIntrinsicWidthsDirty{ true }; Uint8 mMarginAuto{ 0 }; - static constexpr Uint8 MarginAutoLeft = ( 1 << 0 ); - static constexpr Uint8 MarginAutoRight = ( 1 << 1 ); - static constexpr Uint8 MarginAutoTop = ( 1 << 2 ); - static constexpr Uint8 MarginAutoBottom = ( 1 << 3 ); - void calculateAutoMargin(); /** @@ -1707,15 +1720,6 @@ class EE_API UIWidget : public UINode { */ void reloadFontFamily(); - /* @return The width of the widget when size policy is match_parent */ - Float getMatchParentWidth() const; - - /* @return The height of the widget when size policy is match_parent */ - Float getMatchParentHeight() const; - - /* @return The size of the widget when size policy is match_parent */ - Sizef getSizeFromLayoutPolicy(); - UIWidget* setLayoutMarginAuto( Uint32 dir, bool isAuto ); }; diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 4630f03a3..199513322 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -598,9 +598,17 @@ void UIRichText::onAlphaChange() { void UIRichText::rebuildRichText( UILayout* container, RichText& richText, IntrinsicMode mode ) { richText.clear(); - Float maxWidth = container->getPixelsSize().getWidth() - - container->getPixelsContentOffset().Left - - container->getPixelsContentOffset().Right; + Float maxWidth = 0; + if ( container->getLayoutWidthPolicy() == SizePolicy::WrapContent ) { + maxWidth = container->getMatchParentWidth() - + container->getPixelsContentOffset().Left - + container->getPixelsContentOffset().Right; + } else { + maxWidth = container->getPixelsSize().getWidth() - + container->getPixelsContentOffset().Left - + container->getPixelsContentOffset().Right; + } + if ( maxWidth < 0 ) maxWidth = 0; diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 41960f721..2164df19a 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -171,19 +171,19 @@ UIWidget* UIWidget::setLayoutMarginAuto( Uint32 dir, bool isAuto ) { } UIWidget* UIWidget::setLayoutMarginLeftAuto( bool isAuto ) { - return setLayoutMarginAuto( MarginAutoLeft, isAuto ); + return setLayoutMarginAuto( MarginAuto::Left, isAuto ); } UIWidget* UIWidget::setLayoutMarginRightAuto( bool isAuto ) { - return setLayoutMarginAuto( MarginAutoRight, isAuto ); + return setLayoutMarginAuto( MarginAuto::Right, isAuto ); } UIWidget* UIWidget::setLayoutMarginTopAuto( bool isAuto ) { - return setLayoutMarginAuto( MarginAutoTop, isAuto ); + return setLayoutMarginAuto( MarginAuto::Top, isAuto ); } UIWidget* UIWidget::setLayoutMarginBottomAuto( bool isAuto ) { - return setLayoutMarginAuto( MarginAutoTop, isAuto ); + return setLayoutMarginAuto( MarginAuto::Top, isAuto ); } UIWidget* UIWidget::setLayoutMarginAuto( bool left, bool right, bool top, bool bottom ) { @@ -195,19 +195,19 @@ UIWidget* UIWidget::setLayoutMarginAuto( bool left, bool right, bool top, bool b } bool UIWidget::hasLayoutMarginLeftAuto() const { - return mMarginAuto & MarginAutoLeft; + return mMarginAuto & MarginAuto::Left; } bool UIWidget::hasLayoutMarginRightAuto() const { - return mMarginAuto & MarginAutoRight; + return mMarginAuto & MarginAuto::Right; } bool UIWidget::hasLayoutMarginTopAuto() const { - return mMarginAuto & MarginAutoTop; + return mMarginAuto & MarginAuto::Top; } bool UIWidget::hasLayoutMarginBottomAuto() const { - return mMarginAuto & MarginAutoBottom; + return mMarginAuto & MarginAuto::Bottom; } UIWidget* UIWidget::setLayoutPixelsMargin( const Rectf& margin ) { @@ -596,7 +596,7 @@ void UIWidget::calculateAutoMargin() { Rectf parentContentOffset = parent->getPixelsContentOffset(); bool changed = false; - if ( ( mMarginAuto & MarginAutoLeft ) && ( mMarginAuto & MarginAutoRight ) ) { + if ( ( mMarginAuto & MarginAuto::Left ) && ( mMarginAuto & MarginAuto::Right ) ) { Float availableWidth = parentSize.getWidth() - parentContentOffset.Left - parentContentOffset.Right - getPixelsSize().getWidth(); Float newMarginLeft = availableWidth > 0 ? availableWidth / 2.f : 0.f; @@ -606,7 +606,7 @@ void UIWidget::calculateAutoMargin() { mLayoutMarginPx.Right = newMarginRight; changed = true; } - } else if ( mMarginAuto & MarginAutoLeft ) { + } else if ( mMarginAuto & MarginAuto::Left ) { Float availableWidth = parentSize.getWidth() - parentContentOffset.Left - parentContentOffset.Right - getPixelsSize().getWidth() - mLayoutMarginPx.Right; @@ -615,7 +615,7 @@ void UIWidget::calculateAutoMargin() { mLayoutMarginPx.Left = newMarginLeft; changed = true; } - } else if ( mMarginAuto & MarginAutoRight ) { + } else if ( mMarginAuto & MarginAuto::Right ) { Float availableWidth = parentSize.getWidth() - parentContentOffset.Left - parentContentOffset.Right - getPixelsSize().getWidth() - mLayoutMarginPx.Left; @@ -626,7 +626,7 @@ void UIWidget::calculateAutoMargin() { } } - if ( ( mMarginAuto & MarginAutoTop ) && ( mMarginAuto & MarginAutoBottom ) ) { + if ( ( mMarginAuto & MarginAuto::Top ) && ( mMarginAuto & MarginAuto::Bottom ) ) { Float availableHeight = parentSize.getHeight() - parentContentOffset.Top - parentContentOffset.Bottom - getPixelsSize().getHeight(); Float newMarginTop = availableHeight > 0 ? availableHeight / 2.f : 0.f; @@ -636,7 +636,7 @@ void UIWidget::calculateAutoMargin() { mLayoutMarginPx.Bottom = newMarginBottom; changed = true; } - } else if ( mMarginAuto & MarginAutoTop ) { + } else if ( mMarginAuto & MarginAuto::Top ) { Float availableHeight = parentSize.getHeight() - parentContentOffset.Top - parentContentOffset.Bottom - getPixelsSize().getHeight() - mLayoutMarginPx.Bottom; @@ -645,7 +645,7 @@ void UIWidget::calculateAutoMargin() { mLayoutMarginPx.Top = newMarginTop; changed = true; } - } else if ( mMarginAuto & MarginAutoBottom ) { + } else if ( mMarginAuto & MarginAuto::Bottom ) { Float availableHeight = parentSize.getHeight() - parentContentOffset.Top - parentContentOffset.Bottom - getPixelsSize().getHeight() - mLayoutMarginPx.Top; @@ -2002,40 +2002,40 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { } case PropertyId::MarginLeft: { if ( attribute.asString() == "auto" ) { - mMarginAuto |= MarginAutoLeft; + mMarginAuto |= MarginAuto::Left; calculateAutoMargin(); } else { - mMarginAuto &= ~MarginAutoLeft; + mMarginAuto &= ~MarginAuto::Left; setLayoutMarginLeft( lengthFromValueAsDp( attribute ) ); } break; } case PropertyId::MarginRight: { if ( attribute.asString() == "auto" ) { - mMarginAuto |= MarginAutoRight; + mMarginAuto |= MarginAuto::Right; calculateAutoMargin(); } else { - mMarginAuto &= ~MarginAutoRight; + mMarginAuto &= ~MarginAuto::Right; setLayoutMarginRight( lengthFromValueAsDp( attribute ) ); } break; } case PropertyId::MarginTop: { if ( attribute.asString() == "auto" ) { - mMarginAuto |= MarginAutoTop; + mMarginAuto |= MarginAuto::Top; calculateAutoMargin(); } else { - mMarginAuto &= ~MarginAutoTop; + mMarginAuto &= ~MarginAuto::Top; setLayoutMarginTop( lengthFromValueAsDp( attribute ) ); } break; } case PropertyId::MarginBottom: { if ( attribute.asString() == "auto" ) { - mMarginAuto |= MarginAutoBottom; + mMarginAuto |= MarginAuto::Bottom; calculateAutoMargin(); } else { - mMarginAuto &= ~MarginAutoBottom; + mMarginAuto &= ~MarginAuto::Bottom; setLayoutMarginBottom( lengthFromValueAsDp( attribute ) ); } break; @@ -2596,8 +2596,8 @@ Float UIWidget::getMatchParentWidth() const { if ( getParent()->isWidget() ) padding = static_cast( getParent() )->getPixelsContentOffset(); - Float marginLeft = ( mMarginAuto & MarginAutoLeft ) ? 0.f : mLayoutMarginPx.Left; - Float marginRight = ( mMarginAuto & MarginAutoRight ) ? 0.f : mLayoutMarginPx.Right; + Float marginLeft = ( mMarginAuto & MarginAuto::Left ) ? 0.f : mLayoutMarginPx.Left; + Float marginRight = ( mMarginAuto & MarginAuto::Right ) ? 0.f : mLayoutMarginPx.Right; Float width = getParent()->getPixelsSize().getWidth() - marginLeft - marginRight - padding.Left - padding.Right; @@ -2617,8 +2617,8 @@ Float UIWidget::getMatchParentHeight() const { if ( getParent()->isWidget() ) padding = static_cast( getParent() )->getPixelsContentOffset(); - Float marginTop = ( mMarginAuto & MarginAutoTop ) ? 0.f : mLayoutMarginPx.Top; - Float marginBottom = ( mMarginAuto & MarginAutoBottom ) ? 0.f : mLayoutMarginPx.Bottom; + Float marginTop = ( mMarginAuto & MarginAuto::Top ) ? 0.f : mLayoutMarginPx.Top; + Float marginBottom = ( mMarginAuto & MarginAuto::Bottom ) ? 0.f : mLayoutMarginPx.Bottom; Float height = getParent()->getPixelsSize().getHeight() - marginTop - marginBottom - padding.Top - padding.Bottom; diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index d52ade259..fe69939bb 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -1091,3 +1091,27 @@ UTEST( UIHTML, InlineBlockMixedContent ) { Engine::destroySingleton(); } + +UTEST( UIHTML, InlineBlockWrapIssue ) { + Engine::instance()->createWindow( WindowSettings( 1024, 768, "Inline Block Wrap Issue Test", + WindowStyle::Default, WindowBackend::Default, + 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UI::UISceneNode* sceneNode = init_test_inline_block(); + + std::string html; + FileSystem::fileGet( "assets/html/inline_block_wrap.html", html ); + + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ) ); + sceneNode->update( Seconds( 1 ) ); + + auto h2 = sceneNode->getRoot()->find( "h2-wrap" ); + ASSERT_TRUE( h2 != nullptr ); + + auto rt = h2->asType()->getRichTextPtr(); + + EXPECT_EQ( (size_t)1, rt->getLines().size() ); + + Engine::destroySingleton(); +}