From 43a1dca16c5bb2cd8c08e1742387f937e857be03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 27 Mar 2026 00:01:09 -0300 Subject: [PATCH] Layouting improvements for UIImage and HTML elements. Default StyleSheetUnit is now Dp when it's not specified (this is not used very often but in HTML mode we need to respect the DPI). Fix MarkdownView fonts color when on Light theme. --- bin/assets/layouts/test.css | 1 + bin/assets/ui/breeze.css | 13 +++++ include/eepp/ui/uiimage.hpp | 2 + include/eepp/ui/uilayout.hpp | 2 + include/eepp/ui/uistyle.hpp | 2 + include/eepp/ui/uiwidget.hpp | 1 + src/eepp/ui/css/stylesheetlength.cpp | 2 +- src/eepp/ui/doc/markdownhelper.cpp | 1 - src/eepp/ui/uihtmltable.cpp | 7 +++ src/eepp/ui/uiimage.cpp | 79 +++++++++++++++++++++++----- src/eepp/ui/uilayout.cpp | 4 ++ src/eepp/ui/uinode.cpp | 20 ++++--- src/eepp/ui/uirichtext.cpp | 3 ++ src/eepp/ui/uistyle.cpp | 9 ++++ src/eepp/ui/uiwidget.cpp | 10 ++++ src/eepp/ui/uiwidgetcreator.cpp | 6 ++- src/tools/ecode/ecode.cpp | 3 ++ 17 files changed, 143 insertions(+), 22 deletions(-) diff --git a/bin/assets/layouts/test.css b/bin/assets/layouts/test.css index 37c362df4..722a1426d 100644 --- a/bin/assets/layouts/test.css +++ b/bin/assets/layouts/test.css @@ -309,6 +309,7 @@ CheckBox:checked { } #test_4 > RelativeLayout > TextView { + margin-left: 0dp; transition: all 0.2s; } diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index 9115d325a..c24662e92 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -52,6 +52,11 @@ droppable-hovering-color: #FFFFFF20; } +markdownview > *, +body { + color: var(--font); +} + b, strong { font-style: bold; @@ -149,6 +154,13 @@ br { img { scale-type: fit-inside; + layout-width: wrap_content; + layout-height: wrap_content; +} + +markdownview { + background-color: var(--list-back); + padding: 4dp; } markdownview h1, @@ -157,6 +169,7 @@ markdownview h2 { } markdownview img { + max-width: 100%; max-height: 100vh; } diff --git a/include/eepp/ui/uiimage.hpp b/include/eepp/ui/uiimage.hpp index b7dd8fec2..666424cbd 100644 --- a/include/eepp/ui/uiimage.hpp +++ b/include/eepp/ui/uiimage.hpp @@ -59,6 +59,8 @@ class EE_API UIImage : public UIWidget { virtual void onSizeChange(); + virtual void onSizePolicyChange(); + virtual void onAlignChange(); void onAutoSize(); diff --git a/include/eepp/ui/uilayout.hpp b/include/eepp/ui/uilayout.hpp index 419dc8dbd..9eed3cfed 100644 --- a/include/eepp/ui/uilayout.hpp +++ b/include/eepp/ui/uilayout.hpp @@ -48,6 +48,8 @@ class EE_API UILayout : public UIWidget { void setLayoutDirty(); bool setMatchParentIfNeededVerticalGrowth(); + + void onAutoSizeChild( UIWidget* child ); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uistyle.hpp b/include/eepp/ui/uistyle.hpp index ba5c7c623..f64a3f2d0 100644 --- a/include/eepp/ui/uistyle.hpp +++ b/include/eepp/ui/uistyle.hpp @@ -71,6 +71,8 @@ class EE_API UIStyle : public UIState { UnorderedSet& getStructurallyVolatileChildren(); + const CSS::StyleSheetProperty* getProperty( const CSS::PropertyId& id ); + bool hasProperty( const CSS::PropertyId& propertyId ) const; bool hasLocalProperty( CSS::PropertyId propId ) const; diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 96706d87e..da167ff2c 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -1272,6 +1272,7 @@ class EE_API UIWidget : public UINode { friend class UIManager; friend class UISceneNode; friend class UIEventDispatcher; + friend class UILayout; std::string mTag; UITheme* mTheme; diff --git a/src/eepp/ui/css/stylesheetlength.cpp b/src/eepp/ui/css/stylesheetlength.cpp index 6d4d0390d..96368328c 100644 --- a/src/eepp/ui/css/stylesheetlength.cpp +++ b/src/eepp/ui/css/stylesheetlength.cpp @@ -117,7 +117,7 @@ StyleSheetLength::Unit StyleSheetLength::unitFromString( std::string unitStr ) { case UnitHashes::Dpr: return Unit::Dpr; } - return Unit::Px; + return Unit::Dp; } std::string StyleSheetLength::unitToString( const StyleSheetLength::Unit& unit ) { diff --git a/src/eepp/ui/doc/markdownhelper.cpp b/src/eepp/ui/doc/markdownhelper.cpp index 91c6fe759..7d4e8b57c 100644 --- a/src/eepp/ui/doc/markdownhelper.cpp +++ b/src/eepp/ui/doc/markdownhelper.cpp @@ -14,7 +14,6 @@ std::string Markdown::toXHTML( std::string_view markdown, Dialect dialect, int f ( dialect == Dialect::CommonMark ? MD_DIALECT_COMMONMARK : MD_DIALECT_GITHUB ) | flags; md_html( markdown.data(), markdown.size(), process_output, &out, dialectFlag, MD_HTML_FLAG_XHTML ); - return out; } diff --git a/src/eepp/ui/uihtmltable.cpp b/src/eepp/ui/uihtmltable.cpp index 7f0209bec..2d0a244e1 100644 --- a/src/eepp/ui/uihtmltable.cpp +++ b/src/eepp/ui/uihtmltable.cpp @@ -1,3 +1,4 @@ +#include "eepp/ui/uistyle.hpp" #include #include @@ -27,6 +28,12 @@ void UIHTMLTable::updateLayout() { mPacking = true; setMatchParentIfNeededVerticalGrowth(); + const StyleSheetProperty* prop = nullptr; + if ( getLayoutWidthPolicy() == SizePolicy::Fixed && mStyle && + ( prop = mStyle->getProperty( PropertyId::Width ) ) ) { + setInternalPixelsSize( { lengthFromValue( *prop, mSize.x ), mSize.getHeight() } ); + } + UIHTMLTableHead* head = nullptr; UIHTMLTableBody* body = nullptr; UIHTMLTableFooter* footer = nullptr; diff --git a/src/eepp/ui/uiimage.cpp b/src/eepp/ui/uiimage.cpp index e486bd59d..dc64b8150 100644 --- a/src/eepp/ui/uiimage.cpp +++ b/src/eepp/ui/uiimage.cpp @@ -88,24 +88,70 @@ UIImage* UIImage::setDrawable( Drawable* drawable, bool ownIt ) { } void UIImage::onAutoSize() { - if ( NULL != mDrawable ) { - if ( ( mFlags & UI_AUTO_SIZE ) && Sizef::Zero == getPixelsSize() ) - setInternalPixelsSize( mDrawable->getPixelsSize().asInt().asFloat() ); + if ( nullptr == mDrawable ) + return; - Sizef size( getPixelsSize() ); + Sizef drawableSize = mDrawable->getPixelsSize(); + if ( drawableSize.getWidth() <= 0 || drawableSize.getHeight() <= 0 ) + return; - if ( mWidthPolicy == SizePolicy::WrapContent ) { - size.x = - ( (int)mDrawable->getPixelsSize().getWidth() + mPaddingPx.Left + mPaddingPx.Right ); + Sizef size( getPixelsSize() ); + Sizef initialSize( size ); + + if ( ( mFlags & UI_AUTO_SIZE ) && Sizef::Zero == getPixelsSize() ) + size = drawableSize.asInt().asFloat(); + + if ( mWidthPolicy == SizePolicy::WrapContent && mHeightPolicy == SizePolicy::WrapContent ) { + size.x = (int)drawableSize.getWidth() + mPaddingPx.Left + mPaddingPx.Right; + size.y = (int)drawableSize.getHeight() + mPaddingPx.Top + mPaddingPx.Bottom; + + if ( !mMaxWidthEq.empty() ) { + Float maxWidth = + lengthFromValue( mMaxWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth ); + + if ( size.x > maxWidth ) { + Float scale = + ( maxWidth - mPaddingPx.Left - mPaddingPx.Right ) / drawableSize.getWidth(); + size.x = maxWidth; + size.y = + (int)( drawableSize.getHeight() * scale ) + mPaddingPx.Top + mPaddingPx.Bottom; + } } - if ( mHeightPolicy == SizePolicy::WrapContent ) { - size.y = ( (int)mDrawable->getPixelsSize().getHeight() + mPaddingPx.Top + - mPaddingPx.Bottom ); - } + if ( !mMaxHeightEq.empty() ) { + Float maxHeight = + lengthFromValue( mMaxHeightEq, CSS::PropertyRelativeTarget::ContainingBlockHeight ); - setPixelsSize( size ); + if ( size.y > maxHeight ) { + Float scale = + ( maxHeight - mPaddingPx.Top - mPaddingPx.Bottom ) / drawableSize.getHeight(); + size.y = maxHeight; + size.x = + (int)( drawableSize.getWidth() * scale ) + mPaddingPx.Left + mPaddingPx.Right; + } + } + } else if ( mWidthPolicy == SizePolicy::WrapContent ) { + Float contentHeight = std::max( 0.f, size.y - mPaddingPx.Top - mPaddingPx.Bottom ); + size.x = (int)( contentHeight * ( drawableSize.getWidth() / drawableSize.getHeight() ) ) + + mPaddingPx.Left + mPaddingPx.Right; + if ( !mMaxWidthEq.empty() ) { + size.x = std::min( + size.x, + lengthFromValue( mMaxWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth ) ); + } + } else if ( mHeightPolicy == SizePolicy::WrapContent ) { + Float contentWidth = std::max( 0.f, size.x - mPaddingPx.Left - mPaddingPx.Right ); + size.y = (int)( contentWidth * ( drawableSize.getHeight() / drawableSize.getWidth() ) ) + + mPaddingPx.Top + mPaddingPx.Bottom; + if ( !mMaxHeightEq.empty() ) { + size.y = std::min( + size.y, lengthFromValue( mMaxHeightEq, + CSS::PropertyRelativeTarget::ContainingBlockHeight ) ); + } } + + if ( initialSize != size ) + setInternalPixelsSize( size ); } void UIImage::calcDestSize() { @@ -234,6 +280,11 @@ void UIImage::onSizeChange() { UIWidget::onSizeChange(); } +void UIImage::onSizePolicyChange() { + onAutoSize(); + UIWidget::onSizePolicyChange(); +} + void UIImage::onAlignChange() { UIWidget::onAlignChange(); onAutoSize(); @@ -352,6 +403,10 @@ bool UIImage::applyProperty( const StyleSheetProperty& attribute ) { case PropertyId::Tint: setColor( attribute.asColor() ); break; + case PropertyId::Width: + case PropertyId::Height: + unsetFlags( UI_AUTO_SIZE ); + return UIWidget::applyProperty( attribute ); default: return UIWidget::applyProperty( attribute ); } diff --git a/src/eepp/ui/uilayout.cpp b/src/eepp/ui/uilayout.cpp index 62ce1a3b9..b55b95e24 100644 --- a/src/eepp/ui/uilayout.cpp +++ b/src/eepp/ui/uilayout.cpp @@ -122,4 +122,8 @@ bool UILayout::setMatchParentIfNeededVerticalGrowth() { return sizeChanged; } +void UILayout::onAutoSizeChild( UIWidget* child ) { + child->onAutoSize(); +} + }} // namespace EE::UI diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 907f8994f..786534fc3 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -332,7 +332,7 @@ void UINode::setMaxSizeEq( const std::string& maxWidthEq, const std::string& max void UINode::setMaxWidthEq( const std::string& maxWidthEq ) { if ( mMaxWidthEq != maxWidthEq ) { mMaxWidthEq = maxWidthEq; - setSize( mDpSize ); + onSizeChange(); } } @@ -343,7 +343,7 @@ const std::string& UINode::getMaxHeightEq() const { void UINode::setMaxHeightEq( const std::string& maxHeightEq ) { if ( mMaxHeightEq != maxHeightEq ) { mMaxHeightEq = maxHeightEq; - setSize( mDpSize ); + onSizeChange(); } } @@ -1576,12 +1576,20 @@ Float UINode::getPropertyRelativeTargetContainerLength( const Uint32& propertyIndex ) const { Float containerLength = defaultValue; switch ( relativeTarget ) { - case PropertyRelativeTarget::ContainingBlockWidth: - containerLength = getParent() ? getParent()->getPixelsSize().getWidth() : 0; + case PropertyRelativeTarget::ContainingBlockWidth: { + Node* parent = getParent(); // Text spans cannot be considered containing blocks + while ( parent->isType( UI_TYPE_TEXTSPAN ) ) + parent = parent->getParent(); + containerLength = parent ? parent->getPixelsSize().getWidth() : 0; break; - case PropertyRelativeTarget::ContainingBlockHeight: - containerLength = getParent() ? getParent()->getPixelsSize().getHeight() : 0; + } + case PropertyRelativeTarget::ContainingBlockHeight: { + Node* parent = getParent(); // Text spans cannot be considered containing blocks + while ( parent->isType( UI_TYPE_TEXTSPAN ) ) + parent = parent->getParent(); + containerLength = parent ? parent->getPixelsSize().getHeight() : 0; break; + } case PropertyRelativeTarget::LocalBlockWidth: containerLength = getPixelsSize().getWidth(); break; diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 72d6aabc1..e809a2c4b 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -492,6 +492,9 @@ void UIRichText::rebuildRichText() { widget->getLayoutWidthPolicy() == SizePolicy::MatchParent ) { widget->setPixelsSize( mSize.getWidth() - margin.Left - margin.Right, widget->getPixelsSize().getHeight() ); + } else if ( widget->getLayoutWidthPolicy() == SizePolicy::WrapContent || + widget->getLayoutHeightPolicy() == SizePolicy::WrapContent ) { + onAutoSizeChild( widget ); } Sizef size = widget->getPixelsSize(); diff --git a/src/eepp/ui/uistyle.cpp b/src/eepp/ui/uistyle.cpp index e9e9b32e4..06f408cfa 100644 --- a/src/eepp/ui/uistyle.cpp +++ b/src/eepp/ui/uistyle.cpp @@ -209,6 +209,15 @@ UnorderedSet& UIStyle::getStructurallyVolatileChildren() { return mStructurallyVolatileChildren; } +const CSS::StyleSheetProperty* UIStyle::getProperty( const CSS::PropertyId& id ) { + const CSS::StyleSheetProperty* prop = nullptr; + if ( mGlobalDefinition && ( prop = mGlobalDefinition->getProperty( (Uint32)id ) ) ) + return prop; + if ( mElementStyle ) + prop = mElementStyle->getPropertyById( id ); + return prop; +} + bool UIStyle::hasProperty( const CSS::PropertyId& propertyId ) const { return ( mGlobalDefinition && mGlobalDefinition->getProperty( (Uint32)propertyId ) ) || ( mElementStyle && mElementStyle->getPropertyById( propertyId ) ); diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 1d901d01c..f53db96b6 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -1640,11 +1640,21 @@ bool UIWidget::applyProperty( const StyleSheetProperty& attribute ) { notifyLayoutAttrChange(); break; case PropertyId::Width: + if ( mStyle ) { + mStyle->setStyleSheetProperty( + StyleSheetProperty( "layout-width", attribute.value(), true, + StyleSheetSelectorRule::SpecificityImportant ) ); + } setLayoutWidthPolicy( SizePolicy::Fixed ); setSize( eefloor( lengthFromValueAsDp( attribute ) ), getSize().getHeight() ); notifyLayoutAttrChange(); break; case PropertyId::Height: + if ( mStyle ) { + mStyle->setStyleSheetProperty( + StyleSheetProperty( "layout-height", attribute.value(), true, + StyleSheetSelectorRule::SpecificityImportant ) ); + } setLayoutHeightPolicy( SizePolicy::Fixed ); setSize( getSize().getWidth(), eefloor( lengthFromValueAsDp( attribute ) ) ); notifyLayoutAttrChange(); diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 810ce6b2a..a1550c477 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -1,6 +1,6 @@ +#include #include #include -#include #include #include #include @@ -165,7 +165,9 @@ void UIWidgetCreator::createBaseWidgetList() { return UILinearLayout::NewVerticalWidthMatchParent( "article" ); }; registeredWidget["center"] = [] { - return UILinearLayout::NewVerticalWidthMatchParent( "center" ); + auto center = UIRichText::NewWithTag( "center" ); + center->setLayoutWidthPolicy( SizePolicy::WrapContent ); + return center; }; registeredWidget["html"] = [] { return UILinearLayout::NewVerticalWidthMatchParent( "html" ); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 5253d1f77..e96923929 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2290,6 +2290,9 @@ void App::closeEditors() { saveProject(); + mSplitter->setCurrentEditor( nullptr ); + mSplitter->setCurrentWidget( nullptr ); + std::vector editors = mSplitter->getAllEditors(); while ( !editors.empty() ) { UICodeEditor* editor = editors[0];