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];