mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
Add anonymous flex item wrap support.
This commit is contained in:
@@ -330,14 +330,11 @@ void FlexLayouter::measureFlexItems( const Axis& mainAxis, const Axis& crossAxis
|
||||
item.minMainSize =
|
||||
item.widget->asType<UIHTMLWidget>()->getLayouter()->getMinIntrinsicWidth();
|
||||
else if ( item.widget->isType( UI_TYPE_TEXTNODE ) ) {
|
||||
// Text node min size = measured text width (content-based minimum)
|
||||
FontStyleConfig fontConfig;
|
||||
if ( getFontStyleFromAncestor( mContainer, fontConfig ) ) {
|
||||
item.minMainSize = Text::getTextWidth(
|
||||
item.widget->asType<UITextNode>()->getText(), fontConfig );
|
||||
} else {
|
||||
item.minMainSize = item.widget->getPixelsSize().getWidth();
|
||||
}
|
||||
// Text node with wrapping: minimum size = 0, since text can wrap
|
||||
// to any width and the cross size grows to accommodate the content.
|
||||
// Without wrapping, the minimum would be the full text width,
|
||||
// which prevents any flex-shrink.
|
||||
item.minMainSize = 0.f;
|
||||
} else
|
||||
item.minMainSize = item.widget->getPixelsSize().getWidth();
|
||||
if ( item.minMainSize < 0.f )
|
||||
@@ -724,6 +721,42 @@ void FlexLayouter::resolveCrossSizes( FlexLine& line, const Axis& crossAxis,
|
||||
}
|
||||
}
|
||||
|
||||
// For text nodes (anonymous flex items), configure a cached Text object for
|
||||
// multi-line word wrapping. In row direction, measure wrapped text height at
|
||||
// the resolved main size and use it as the cross size.
|
||||
for ( size_t idx : line.itemIndices ) {
|
||||
auto& item = mItems[idx];
|
||||
if ( item.widget->isType( UI_TYPE_TEXTNODE ) ) {
|
||||
auto* textNode = item.widget->asType<UITextNode>();
|
||||
if ( !textNode->getText().empty() ) {
|
||||
FontStyleConfig fontConfig;
|
||||
if ( getFontStyleFromAncestor( mContainer, fontConfig ) ) {
|
||||
Graphics::Text& flexText = textNode->getFlexText();
|
||||
flexText.setStyleConfig( fontConfig );
|
||||
flexText.setString( textNode->getText() );
|
||||
flexText.setLineWrapMode( LineWrapMode::Word );
|
||||
Float maxWidth;
|
||||
if ( mainAxis.horizontal ) {
|
||||
maxWidth = item.targetMainSize;
|
||||
} else {
|
||||
// Column: wrap at tentative cross-axis width
|
||||
maxWidth = item.widget->getPixelsSize().getWidth();
|
||||
}
|
||||
if ( maxWidth <= 0.f )
|
||||
maxWidth = 10000.f;
|
||||
flexText.setMaxWrapWidth( maxWidth );
|
||||
if ( mainAxis.horizontal ) {
|
||||
Float wrappedHeight = flexText.getTextHeight();
|
||||
if ( wrappedHeight <= 0.f )
|
||||
wrappedHeight =
|
||||
(Float)fontConfig.Font->getFontHeight( fontConfig.CharacterSize );
|
||||
item.widget->setInternalPixelsHeight( wrappedHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Float maxCross = 0.f;
|
||||
for ( size_t idx : line.itemIndices ) {
|
||||
auto& item = mItems[idx];
|
||||
|
||||
@@ -29,28 +29,33 @@ void UITextNode::draw() {
|
||||
if ( mText.empty() )
|
||||
return;
|
||||
|
||||
// In flex layout, text nodes are anonymous flex items. The parent flex
|
||||
// container does not render their text via RichText (it was cleared),
|
||||
// so the text node must draw itself.
|
||||
Node* parent = getParent();
|
||||
bool isFlexItem =
|
||||
parent && parent->isType( UI_TYPE_HTML_WIDGET ) && parent->asType<UIHTMLWidget>()->isFlex();
|
||||
if ( isFlexItem ) {
|
||||
// Walk up parent chain to find a UIRichText ancestor with font info
|
||||
Node* n = parent;
|
||||
while ( n ) {
|
||||
if ( n->isType( UI_TYPE_RICHTEXT ) ) {
|
||||
auto& fontConfig = n->asType<UIRichText>()->getRichText().getFontStyleConfig();
|
||||
if ( fontConfig.Font ) {
|
||||
FontStyleConfig fc = fontConfig;
|
||||
Float alpha = getAlpha();
|
||||
if ( alpha < 1.f )
|
||||
fc.FontColor.a = (Uint8)( (Float)fc.FontColor.a * alpha );
|
||||
Text::draw( mText, mScreenPos.trunc(), fc );
|
||||
if ( mFlexText.getFont() ) {
|
||||
mFlexText.setMaxWrapWidth( getPixelsSize().getWidth() );
|
||||
Float alpha = getAlpha();
|
||||
if ( alpha < 1.f )
|
||||
mFlexText.setAlpha( (Uint8)( 255.f * alpha ) );
|
||||
mFlexText.draw( mScreenPos.x, mScreenPos.y );
|
||||
} else {
|
||||
// Fallback: Text not yet configured by flex layouter — draw single-line
|
||||
Node* n = parent;
|
||||
while ( n ) {
|
||||
if ( n->isType( UI_TYPE_RICHTEXT ) ) {
|
||||
auto& fontConfig = n->asType<UIRichText>()->getRichText().getFontStyleConfig();
|
||||
if ( fontConfig.Font ) {
|
||||
FontStyleConfig fc = fontConfig;
|
||||
Float alpha = getAlpha();
|
||||
if ( alpha < 1.f )
|
||||
fc.FontColor.a = (Uint8)( (Float)fc.FontColor.a * alpha );
|
||||
Text::draw( mText, mScreenPos.trunc(), fc );
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
n = n->getParent();
|
||||
}
|
||||
n = n->getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1588,3 +1588,38 @@ UTEST( FlexContainer, anonymousTextNodeWithFixedSibling ) {
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( FlexContainer, anonymousTextNodeWrapping ) {
|
||||
Engine::instance()->createWindow( WindowSettings( 1024, 650, "Flex Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false,
|
||||
true ),
|
||||
ContextSettings( false, 0, 0, GLv_default, true, false ) );
|
||||
init_flex_test();
|
||||
UISceneNode* sceneNode = SceneManager::instance()->getUISceneNode();
|
||||
|
||||
UIRichText* flex = UIRichText::NewWithTag( "div" );
|
||||
flex->setParent( sceneNode->getRoot() );
|
||||
flex->setDisplay( CSSDisplay::Flex );
|
||||
flex->setPixelsSize( 100, 200 );
|
||||
flex->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
flex->applyProperty( StyleSheetProperty( "font-family", "NotoSans-Regular" ) );
|
||||
flex->applyProperty( StyleSheetProperty( "font-size", "16dp" ) );
|
||||
flex->applyProperty( StyleSheetProperty( "align-items", "flex-start" ) );
|
||||
|
||||
// Long text that should wrap within the 100px-wide flex container
|
||||
UITextNode* textNode = UITextNode::New();
|
||||
textNode->setParent( flex );
|
||||
textNode->setText( "This is a very long text that should wrap to multiple lines inside the narrow flex container." );
|
||||
|
||||
sceneNode->updateDirtyLayouts();
|
||||
|
||||
// The font height for NotoSans at 16dp is ~22px. If the text wraps, the total
|
||||
// height should be at least 2x the single-line font height.
|
||||
FontStyleConfig fontConfig = flex->getRichText().getFontStyleConfig();
|
||||
Float fontHeight = (Float)fontConfig.Font->getFontHeight( fontConfig.CharacterSize );
|
||||
EXPECT_TRUE( textNode->getPixelsSize().getWidth() > 0.f );
|
||||
EXPECT_TRUE( textNode->getPixelsSize().getHeight() >= fontHeight * 2.f );
|
||||
EXPECT_TRUE( textNode->getPixelsSize().getWidth() <= 100.f );
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user