diff --git a/include/eepp/core/memorymanager.hpp b/include/eepp/core/memorymanager.hpp index 870bcf9cb..f43f7da19 100644 --- a/include/eepp/core/memorymanager.hpp +++ b/include/eepp/core/memorymanager.hpp @@ -5,9 +5,8 @@ #include #include #include -#include #include - +#include namespace EE { @@ -23,10 +22,9 @@ class EE_API AllocatedPointer { bool mTrack; }; -typedef std::map AllocatedPointerMap; +typedef std::unordered_map AllocatedPointerMap; typedef AllocatedPointerMap::iterator AllocatedPointerMapIt; - #if defined( __GNUC__ ) && __GNUC__ >= 12 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuse-after-free" @@ -163,7 +161,6 @@ class EE_API MemoryManager { #endif - } // namespace EE #endif diff --git a/include/eepp/scene/action.hpp b/include/eepp/scene/action.hpp index 6d9202cf3..2384f2009 100644 --- a/include/eepp/scene/action.hpp +++ b/include/eepp/scene/action.hpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace EE::System; namespace EE { namespace Scene { diff --git a/include/eepp/system/pack.hpp b/include/eepp/system/pack.hpp index 57b7dc1ae..9aba5b6f2 100644 --- a/include/eepp/system/pack.hpp +++ b/include/eepp/system/pack.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace EE { namespace System { diff --git a/include/eepp/ui.hpp b/include/eepp/ui.hpp index 34d94851d..46eb641d2 100644 --- a/include/eepp/ui.hpp +++ b/include/eepp/ui.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eepp/ui/uihelper.hpp b/include/eepp/ui/uihelper.hpp index 973ec90e9..c512f929b 100644 --- a/include/eepp/ui/uihelper.hpp +++ b/include/eepp/ui/uihelper.hpp @@ -100,6 +100,7 @@ enum UINodeType { UI_TYPE_TABLECELL, UI_TYPE_LISTVIEW, UI_TYPE_CONSOLE, + UI_TYPE_STACK_LAYOUT, UI_TYPE_MODULES = 10000, UI_TYPE_TERMINAL = 10001, UI_TYPE_USER = 100000 diff --git a/include/eepp/ui/uilayout.hpp b/include/eepp/ui/uilayout.hpp index a202a171a..447482117 100644 --- a/include/eepp/ui/uilayout.hpp +++ b/include/eepp/ui/uilayout.hpp @@ -7,10 +7,6 @@ namespace EE { namespace UI { class EE_API UILayout : public UIWidget { public: - static UILayout* New(); - - UILayout(); - virtual Uint32 getType() const; virtual bool isType( const Uint32& type ) const; @@ -23,10 +19,12 @@ class EE_API UILayout : public UIWidget { void setGravityOwner( bool gravityOwner ); + bool isPacking() const { return mPacking; } + protected: friend class UISceneNode; - UILayout( const std::string& tag ); + explicit UILayout( const std::string& tag ); virtual void onSizeChange(); @@ -48,6 +46,8 @@ class EE_API UILayout : public UIWidget { bool mDirtyLayout{ false }; bool mPacking{ false }; bool mGravityOwner{ false }; + + Sizef getSizeFromLayoutPolicy(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uilinearlayout.hpp b/include/eepp/ui/uilinearlayout.hpp index 45e00cf4b..7232a261e 100644 --- a/include/eepp/ui/uilinearlayout.hpp +++ b/include/eepp/ui/uilinearlayout.hpp @@ -15,10 +15,6 @@ class EE_API UILinearLayout : public UILayout { static UILinearLayout* NewHorizontal(); - UILinearLayout(); - - UILinearLayout( const std::string& tag, const UIOrientation& orientation ); - virtual Uint32 getType() const; virtual bool isType( const Uint32& type ) const; @@ -27,8 +23,6 @@ class EE_API UILinearLayout : public UILayout { UILinearLayout* setOrientation( const UIOrientation& getOrientation ); - UILinearLayout* add( UIWidget* widget ); - virtual bool applyProperty( const StyleSheetProperty& attribute ); virtual std::string getPropertyString( const PropertyDefinition* propertyDef, @@ -38,11 +32,13 @@ class EE_API UILinearLayout : public UILayout { void updateLayout(); - bool isPacking() const; - protected: UIOrientation mOrientation; + UILinearLayout(); + + UILinearLayout( const std::string& tag, const UIOrientation& orientation ); + virtual Uint32 onMessage( const NodeMessage* Msg ); void packVertical(); diff --git a/include/eepp/ui/uistacklayout.hpp b/include/eepp/ui/uistacklayout.hpp new file mode 100644 index 000000000..2e75252d9 --- /dev/null +++ b/include/eepp/ui/uistacklayout.hpp @@ -0,0 +1,40 @@ +#ifndef EE_UI_UISTACKLAYOUT_HPP +#define EE_UI_UISTACKLAYOUT_HPP + +#include + +namespace EE { namespace UI { + +class EE_API UIStackLayout : public UILayout { + public: + static UIStackLayout* New(); + + static UIStackLayout* NewWithTag( const std::string& tag = "stacklayout" ); + + virtual Uint32 getType() const; + + virtual bool isType( const Uint32& type ) const; + + virtual bool applyProperty( const StyleSheetProperty& attribute ); + + virtual std::string getPropertyString( const PropertyDefinition* propertyDef, + const Uint32& propertyIndex = 0 ) const; + + virtual std::vector getPropertiesImplemented() const; + + void updateLayout(); + + protected: + UIStackLayout(); + + virtual Uint32 onMessage( const NodeMessage* Msg ); + + explicit UIStackLayout( const std::string& tag ); + + void applySizePolicyOnChilds(); + +}; + +}} // namespace EE::UI + +#endif // EE_UI_UISTACKLAYOUT_HPP diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index 32b60ea29..d5375868f 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -110,7 +110,7 @@ {388e5431-b31b-42b3-b9ad-9002d279d75d} 10 0 - 19 + 15 ../../make/linux @@ -187,7 +187,7 @@ true - gmake + --with-debug-symbols gmake premake4 %{buildDir}../../../ ProjectExplorer.ProcessStep diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 552a52e11..9152ddbb6 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -461,6 +461,7 @@ ../../include/eepp/window/window.hpp ../../Makefile ../../Makefile.base +../../include/eepp/ui/uistacklayout.hpp ../../premake4.lua ../../premake5.lua ../../src/eepp/audio/alcheck.cpp @@ -913,6 +914,7 @@ ../../src/eepp/ui/uispinbox.cpp ../../src/eepp/ui/uisplitter.cpp ../../src/eepp/ui/uisprite.cpp +../../src/eepp/ui/uistacklayout.cpp ../../src/eepp/ui/uistackwidget.cpp ../../src/eepp/ui/uistate.cpp ../../src/eepp/ui/uistyle.cpp diff --git a/src/eepp/ui/uiicontheme.cpp b/src/eepp/ui/uiicontheme.cpp index a2db5d7cc..5096debd9 100644 --- a/src/eepp/ui/uiicontheme.cpp +++ b/src/eepp/ui/uiicontheme.cpp @@ -15,6 +15,9 @@ UIIconTheme::~UIIconTheme() { UIIconTheme::UIIconTheme( const std::string& name ) : mName( name ) {} UIIconTheme* UIIconTheme::add( UIIcon* icon ) { + auto iconExists = mIcons.find( icon->getName() ); + if ( iconExists != mIcons.end() ) + eeDelete( iconExists->second ); mIcons[icon->getName()] = icon; return this; } diff --git a/src/eepp/ui/uilayout.cpp b/src/eepp/ui/uilayout.cpp index d8ad807d1..14e7faf7b 100644 --- a/src/eepp/ui/uilayout.cpp +++ b/src/eepp/ui/uilayout.cpp @@ -3,15 +3,6 @@ namespace EE { namespace UI { -UILayout* UILayout::New() { - return eeNew( UILayout, () ); -} - -UILayout::UILayout() : UIWidget( "layout" ) { - mNodeFlags |= NODE_FLAG_LAYOUT; - unsetFlags( UI_TAB_FOCUSABLE ); -} - UILayout::UILayout( const std::string& tag ) : UIWidget( tag ) { mNodeFlags |= NODE_FLAG_LAYOUT; unsetFlags( UI_TAB_FOCUSABLE ); @@ -77,6 +68,39 @@ void UILayout::setLayoutDirty() { } } +Sizef UILayout::getSizeFromLayoutPolicy() { + Sizef size( getPixelsSize() ); + + if ( getLayoutWidthPolicy() == SizePolicy::MatchParent ) { + Float w = + getParent()->getPixelsSize().getWidth() - mLayoutMarginPx.Left - mLayoutMarginPx.Right; + + if ( getParent()->isType( UI_TYPE_LAYOUT ) ) { + UILayout* pLay = static_cast( getParent() ); + w = w - pLay->getPixelsPadding().Left - pLay->getPixelsPadding().Right; + } + + if ( (int)w != (int)getPixelsSize().getWidth() ) + size.setWidth( w ); + } + + if ( getLayoutHeightPolicy() == SizePolicy::MatchParent ) { + Float h = + getParent()->getPixelsSize().getHeight() - mLayoutMarginPx.Top - mLayoutMarginPx.Bottom; + + if ( getParent()->isType( UI_TYPE_LAYOUT ) ) { + UILayout* pLay = static_cast( getParent() ); + h = h - pLay->getPixelsPadding().Top - pLay->getPixelsPadding().Bottom; + } + + if ( (int)h != (int)getPixelsSize().getHeight() ) { + size.setHeight( h ); + } + } + + return size; +} + bool UILayout::isGravityOwner() const { return mGravityOwner; } diff --git a/src/eepp/ui/uilinearlayout.cpp b/src/eepp/ui/uilinearlayout.cpp index 93b863691..dbc176117 100644 --- a/src/eepp/ui/uilinearlayout.cpp +++ b/src/eepp/ui/uilinearlayout.cpp @@ -50,11 +50,6 @@ UILinearLayout* UILinearLayout::setOrientation( const UIOrientation& orientation return this; } -UILinearLayout* UILinearLayout::add( UIWidget* widget ) { - widget->setParent( this ); - return this; -} - void UILinearLayout::updateLayout() { if ( mOrientation == UIOrientation::Vertical ) packVertical(); @@ -63,10 +58,6 @@ void UILinearLayout::updateLayout() { mDirtyLayout = false; } -bool UILinearLayout::isPacking() const { - return mPacking; -} - void UILinearLayout::applyWidthPolicyOnChilds() { Node* child = mChild; diff --git a/src/eepp/ui/uistacklayout.cpp b/src/eepp/ui/uistacklayout.cpp new file mode 100644 index 000000000..dbd80ac06 --- /dev/null +++ b/src/eepp/ui/uistacklayout.cpp @@ -0,0 +1,283 @@ +#include + +namespace EE { namespace UI { + +UIStackLayout* UIStackLayout::NewWithTag( const std::string& tag ) { + return eeNew( UIStackLayout, ( tag ) ); +} + +UIStackLayout* UIStackLayout::New() { + return eeNew( UIStackLayout, () ); +} + +UIStackLayout::UIStackLayout() : UILayout( "stacklayout" ) { + mFlags |= UI_OWNS_CHILDS_POSITION; + setClipType( ClipType::ContentBox ); +} + +UIStackLayout::UIStackLayout( const std::string& tag ) : UILayout( tag ) { + mFlags |= UI_OWNS_CHILDS_POSITION; + setClipType( ClipType::ContentBox ); +} + +Uint32 UIStackLayout::getType() const { + return UI_TYPE_STACK_LAYOUT; +} + +bool UIStackLayout::isType( const Uint32& type ) const { + return UIStackLayout::getType() == type ? true : UILayout::isType( type ); +} + +void UIStackLayout::applySizePolicyOnChilds() { + Node* child = mChild; + + while ( NULL != child ) { + if ( child->isWidget() && child->isVisible() ) { + UIWidget* widget = static_cast( child ); + + switch ( widget->getLayoutWidthPolicy() ) { + case SizePolicy::WrapContent: { + widget->setFlags( UI_AUTO_SIZE ); + break; + } + case SizePolicy::MatchParent: { + int w = getPixelsSize().getWidth() - widget->getLayoutPixelsMargin().Left - + widget->getLayoutPixelsMargin().Right - mPaddingPx.Left - + mPaddingPx.Right; + + if ( (int)widget->getPixelsSize().getWidth() != w && w > 0 ) + widget->setPixelsSize( w, widget->getPixelsSize().getHeight() ); + + break; + } + case SizePolicy::Fixed: + default: { + } + } + + switch ( widget->getLayoutHeightPolicy() ) { + case SizePolicy::WrapContent: { + widget->setFlags( UI_AUTO_SIZE ); + break; + } + case SizePolicy::MatchParent: { + int h = getPixelsSize().getHeight() - widget->getLayoutPixelsMargin().Top - + widget->getLayoutPixelsMargin().Bottom - mPaddingPx.Top - + mPaddingPx.Bottom; + + if ( h != (int)widget->getPixelsSize().getHeight() && h > 0 ) + widget->setPixelsSize( widget->getPixelsSize().getWidth(), h ); + + break; + } + case SizePolicy::Fixed: + default: { + } + } + } + + child = child->getNextNode(); + } +} + +std::string UIStackLayout::getPropertyString( const PropertyDefinition* propertyDef, + const Uint32& propertyIndex ) const { + if ( NULL == propertyDef ) + return ""; + + switch ( propertyDef->getPropertyId() ) { + case PropertyId::GravityOwner: + return isGravityOwner() ? "true" : "false"; + default: + return UILayout::getPropertyString( propertyDef, propertyIndex ); + } +} + +std::vector UIStackLayout::getPropertiesImplemented() const { + auto props = UILayout::getPropertiesImplemented(); + auto local = { PropertyId::GravityOwner }; + props.insert( props.end(), local.begin(), local.end() ); + return props; +} + +bool UIStackLayout::applyProperty( const StyleSheetProperty& attribute ) { + if ( !checkPropertyDefinition( attribute ) ) + return false; + + switch ( attribute.getPropertyDefinition()->getPropertyId() ) { + case PropertyId::GravityOwner: { + setGravityOwner( attribute.asBool() ); + break; + } + default: + return UILayout::applyProperty( attribute ); + } + + return true; +} + +Uint32 UIStackLayout::onMessage( const NodeMessage* Msg ) { + switch ( Msg->getMsg() ) { + case NodeMessage::LayoutAttributeChange: { + tryUpdateLayout(); + return 1; + } + } + + return 0; +} + +struct NodeLine { + std::vector nodes; + Float maxY{ 0 }; + Float width{ 0 }; +}; + +void UIStackLayout::updateLayout() { + if ( mPacking ) + return; + mPacking = true; + + Sizef size( getPixelsSize() ); + Sizef nsize( getSizeFromLayoutPolicy() ); + if ( size != nsize ) + setInternalPixelsSize( nsize ); + + applySizePolicyOnChilds(); + + Float curX = mPaddingPx.Left; + Node* child = mChild; + std::vector lines = { {} }; + Uint32 curLine = 0; + bool addedLine = false; + + auto addLine = [&]() { + curX = mPaddingPx.Left; + ++curLine; + lines.push_back( { {} } ); + addedLine = true; + }; + + while ( NULL != child ) { + if ( child->isWidget() && child->isVisible() ) { + UIWidget* widget = static_cast( child ); + const Rectf& margin = widget->getLayoutPixelsMargin(); + + if ( curX + margin.Left + widget->getPixelsSize().getWidth() >= mSize.getWidth() && + !addedLine && !lines[curLine].nodes.empty() ) + addLine(); + + addedLine = false; + + curX += eeceil( margin.Left ); + + Vector2f pos( curX, mPaddingPx.Top ); + + widget->setPixelsPosition( pos ); + + curX += eeceil( widget->getPixelsSize().getWidth() + margin.Right ); + + lines[curLine].nodes.push_back( widget ); + lines[curLine].width = curX; + lines[curLine].maxY = + eeceil( eemax( lines[curLine].maxY, ( widget->getPixelsSize().getHeight() + + widget->getLayoutPixelsMargin().Top + + widget->getLayoutPixelsMargin().Bottom ) ) ); + + if ( curX > mSize.getWidth() ) + addLine(); + } + + child = child->getNextNode(); + } + + Float maxY = mPaddingPx.Top; + Float height = 0.f; + Float totHeight = maxY; + for ( const auto& line : lines ) { + height += line.maxY; + totHeight += line.maxY; + } + totHeight += mPaddingPx.Bottom; + + if ( getLayoutHeightPolicy() == SizePolicy::WrapContent ) { + if ( totHeight != (int)getPixelsSize().getHeight() ) { + setInternalPixelsHeight( totHeight ); + notifyLayoutAttrChangeParent(); + } + } + + for ( const auto& line : lines ) { + Float xDisplacement = 0.f; + Float yDisplacement = 0.f; + + switch ( Font::getHorizontalAlign( getHorizontalAlign() ) ) { + case UI_HALIGN_CENTER: + xDisplacement = eeceil( ( getPixelsSize().getWidth() - line.width ) * 0.5f ); + break; + case UI_HALIGN_RIGHT: + xDisplacement = getPixelsSize().getWidth() - line.width; + break; + case UI_HALIGN_LEFT: + default: + break; + } + + Float innerHeight = getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom; + if ( height < innerHeight ) { + switch ( Font::getVerticalAlign( getVerticalAlign() ) ) { + case UI_VALIGN_CENTER: + yDisplacement = eeceil( ( innerHeight - height ) * 0.5f ); + break; + case UI_VALIGN_BOTTOM: + yDisplacement = ( innerHeight - height ); + break; + case UI_VALIGN_TOP: + default: + break; + } + } + + for ( const auto& widget : line.nodes ) { + Vector2f pos( widget->getPixelsPosition() ); + + switch ( Font::getHorizontalAlign( getHorizontalAlign() ) ) { + case UI_HALIGN_CENTER: + case UI_HALIGN_RIGHT: + pos.x = xDisplacement + widget->getPixelsPosition().x; + break; + case UI_HALIGN_LEFT: + default: + break; + } + + switch ( Font::getVerticalAlign( widget->getLayoutGravity() ) ) { + case UI_VALIGN_CENTER: + pos.y = yDisplacement + maxY + + eeceil( ( line.maxY - widget->getPixelsSize().getHeight() ) * 0.5f ); + break; + case UI_VALIGN_BOTTOM: + pos.y = yDisplacement + maxY + line.maxY - widget->getPixelsSize().getHeight(); + break; + case UI_VALIGN_TOP: + default: + pos.y = yDisplacement + maxY + widget->getLayoutPixelsMargin().Top; + break; + } + + widget->setPixelsPosition( pos ); + } + + maxY += line.maxY; + } + + if ( getParent()->isUINode() && + ( !getParent()->asType()->ownsChildPosition() || isGravityOwner() ) ) { + alignAgainstLayout(); + } + + mPacking = false; + mDirtyLayout = false; +} + +}} // namespace EE::UI diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 52da8b134..0811c7335 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -82,7 +83,7 @@ void UIWidgetCreator::createBaseWidgetList() { registeredWidget["textureregion"] = UITextureRegion::New; registeredWidget["touchdraggable"] = UITouchDraggableWidget::New; registeredWidget["gridlayout"] = UIGridLayout::New; - registeredWidget["layout"] = UILayout::New; + registeredWidget["stacklayout"] = UIStackLayout::New; registeredWidget["viewpager"] = UIViewPager::New; registeredWidget["codeeditor"] = UICodeEditor::New; registeredWidget["splitter"] = UISplitter::New;