diff --git a/include/eepp/ui/css/stylesheet.hpp b/include/eepp/ui/css/stylesheet.hpp index 07a39733c..a0932d77c 100644 --- a/include/eepp/ui/css/stylesheet.hpp +++ b/include/eepp/ui/css/stylesheet.hpp @@ -60,7 +60,7 @@ class EE_API StyleSheet { void removeAllWithoutMarker( const Uint32& marker ); - void setSelectorSpecificity( const Uint32& specificity ); + void setSelectorSpecificity( const Int64& specificity ); bool markerExists( const Uint32& marker ) const; diff --git a/include/eepp/ui/css/stylesheetproperty.hpp b/include/eepp/ui/css/stylesheetproperty.hpp index 6874ad0d0..c9af26ce3 100644 --- a/include/eepp/ui/css/stylesheetproperty.hpp +++ b/include/eepp/ui/css/stylesheetproperty.hpp @@ -39,11 +39,11 @@ class EE_API StyleSheetProperty { bool cachedProperty = false ); explicit StyleSheetProperty( const std::string& name, const std::string& value, - bool trimValue = true, const Uint64& specificity = 0, + bool trimValue = true, const Int64& specificity = 0, const Uint32& index = 0 ); explicit StyleSheetProperty( const std::string& name, const std::string& value, - const Uint64& specificity, bool isVolatile = false, + const Int64& specificity, bool isVolatile = false, const Uint32& index = 0 ); Uint32 getId() const; @@ -56,9 +56,9 @@ class EE_API StyleSheetProperty { const std::string& value() const; - const Uint64& getSpecificity() const; + const Int64& getSpecificity() const; - void setSpecificity( const Uint64& specificity ); + void setSpecificity( const Int64& specificity ); bool isEmpty() const; @@ -193,7 +193,7 @@ class EE_API StyleSheetProperty { String::HashType mNameHash; std::string mValue; String::HashType mValueHash; - Uint64 mSpecificity; + Int64 mSpecificity; Uint32 mIndex; bool mVolatile : 1 { false }; bool mImportant : 1 { false }; @@ -206,7 +206,7 @@ class EE_API StyleSheetProperty { std::vector mVarCache; explicit StyleSheetProperty( bool isVolatile, const PropertyDefinition* definition, - const std::string& value, const Uint64& specificity = 0, + const std::string& value, const Int64& specificity = 0, const Uint32& index = 0 ); void cleanValue(); diff --git a/include/eepp/ui/css/stylesheetselector.hpp b/include/eepp/ui/css/stylesheetselector.hpp index eb1aa7c35..55c229e7c 100644 --- a/include/eepp/ui/css/stylesheetselector.hpp +++ b/include/eepp/ui/css/stylesheetselector.hpp @@ -17,9 +17,9 @@ class EE_API StyleSheetSelector { const std::string& getName() const; - const Uint32& getSpecificity() const; + const Int64& getSpecificity() const; - void setSpecificity( const Uint32& specificity ); + void setSpecificity( const Int64& specificity ); bool select( UIWidget* element, const bool& applyPseudo = true ) const; @@ -39,7 +39,7 @@ class EE_API StyleSheetSelector { protected: std::string mName; - Uint32 mSpecificity; + Int64 mSpecificity; std::vector mSelectorRules; bool mCacheable; bool mStructurallyVolatile; diff --git a/include/eepp/ui/css/stylesheetselectorrule.hpp b/include/eepp/ui/css/stylesheetselectorrule.hpp index f549f763f..86e45ff98 100644 --- a/include/eepp/ui/css/stylesheetselectorrule.hpp +++ b/include/eepp/ui/css/stylesheetselectorrule.hpp @@ -45,15 +45,17 @@ class EE_API StyleSheetSelectorRule { Attribute = 1 << 5, }; - enum SpecificityVal : Uint64 { - SpecificityImportant = 1000000000000000ULL, - SpecificityInline = 1000000000000ULL, - SpecificityId = 1000000ULL, - SpecificityClass = 100000ULL, - SpecificityTag = 10000ULL, - SpecificityPseudoClass = 100ULL, - SpecificityStructuralPseudoClass = 50ULL, - SpecificityGlobal = 1ULL + // Packed CSS specificity tuple. This matches lexicographic specificity comparison while + // selector buckets remain below SpecificityClass. + enum SpecificityVal : Int64 { + SpecificityImportant = 1000000000000000LL, + SpecificityInline = 1000000000000LL, + SpecificityId = 1048576LL, + SpecificityClass = 1024LL, + SpecificityTag = 1LL, + SpecificityPseudoClass = SpecificityClass, + SpecificityStructuralPseudoClass = SpecificityClass, + SpecificityGlobal = 0LL }; enum PatternMatch { @@ -128,7 +130,7 @@ class EE_API StyleSheetSelectorRule { const PatternMatch& getPatternMatch() const { return mPatternMatch; } - const Uint64& getSpecificity() const { return mSpecificity; } + const Int64& getSpecificity() const { return mSpecificity; } bool matches( UIWidget* element, const bool& applyPseudo = true ) const; @@ -151,7 +153,7 @@ class EE_API StyleSheetSelectorRule { const std::string& getId() const; protected: - Uint64 mSpecificity{ 0 }; + Int64 mSpecificity{ 0 }; PatternMatch mPatternMatch; std::string mTagName; std::string mId; diff --git a/include/eepp/ui/css/stylesheetstyle.hpp b/include/eepp/ui/css/stylesheetstyle.hpp index 4ad4ebe33..816de7f9b 100644 --- a/include/eepp/ui/css/stylesheetstyle.hpp +++ b/include/eepp/ui/css/stylesheetstyle.hpp @@ -67,7 +67,7 @@ class EE_API StyleSheetStyle { void setMarker( const Uint32& marker ); - void setSelectorSpecificity( const Uint32& specificity ); + void setSelectorSpecificity( const Int64& specificity ); bool updatePropertyValue( const std::string& name, const std::string& value ); diff --git a/include/eepp/ui/css/stylesheetvariable.hpp b/include/eepp/ui/css/stylesheetvariable.hpp index ee521fa2b..2a075f2f2 100644 --- a/include/eepp/ui/css/stylesheetvariable.hpp +++ b/include/eepp/ui/css/stylesheetvariable.hpp @@ -14,7 +14,7 @@ class EE_API StyleSheetVariable { explicit StyleSheetVariable( const std::string& name, const std::string& value ); explicit StyleSheetVariable( const std::string& name, const std::string& value, - const Uint32& specificity ); + const Int64& specificity ); const std::string& getName() const; @@ -24,9 +24,9 @@ class EE_API StyleSheetVariable { const std::string& value() const; - const Uint32& getSpecificity() const; + const Int64& getSpecificity() const; - void setSpecificity( const Uint32& specificity ); + void setSpecificity( const Int64& specificity ); bool isEmpty() const; @@ -40,7 +40,7 @@ class EE_API StyleSheetVariable { std::string mName; String::HashType mNameHash; std::string mValue; - Uint32 mSpecificity; + Int64 mSpecificity; }; typedef UnorderedMap StyleSheetVariables; diff --git a/include/eepp/ui/tools/uiwidgetinspector.hpp b/include/eepp/ui/tools/uiwidgetinspector.hpp index 847017376..d901ed1aa 100644 --- a/include/eepp/ui/tools/uiwidgetinspector.hpp +++ b/include/eepp/ui/tools/uiwidgetinspector.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace EE { namespace UI { class UISceneNode; @@ -21,8 +22,11 @@ class EE_API UIWidgetInspector { std::function drawDebugDataToggle = std::function() ); protected: + struct PickHighlightOverState; + static void checkWidgetPick( UISceneNode* sceneNode, UITreeView* widgetTree, - bool wasHighlightOver, UITableView* tableView ); + std::shared_ptr highlightOverState, + UITableView* tableView ); }; }}} // namespace EE::UI::Tools diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 299564b14..1b0b599fe 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -154,6 +154,12 @@ class EE_API UISceneNode : public SceneNode { */ void initializeEmbeddedFromHost( UISceneNode* hostScene ); + /** @return Direct embedded UI scenes hosted below this scene's node tree. */ + const std::vector& getChildUISceneNodes() const; + + /** Enables or disables mouse-over highlighting in this scene and embedded UI scenes. */ + void setHighlightOverRecursive( bool highlight ); + /** * @brief Gets the size in density-independent pixels (dp). * @@ -845,12 +851,14 @@ class EE_API UISceneNode : public SceneNode { std::shared_ptr getAsyncResourceLoadState() const; - static bool isAsyncResourceLoadCurrent( - const std::shared_ptr& resourceState, Uint64 generation ); + static bool + isAsyncResourceLoadCurrent( const std::shared_ptr& resourceState, + Uint64 generation ); - static void runAsyncResourceOnMainThread( - const std::shared_ptr& resourceState, Uint64 generation, - AsyncResourceMainThreadFunc func, const Time& delay = Seconds( 0 ) ); + static void + runAsyncResourceOnMainThread( const std::shared_ptr& resourceState, + Uint64 generation, AsyncResourceMainThreadFunc func, + const Time& delay = Seconds( 0 ) ); protected: friend class EE::UI::UIWindow; @@ -878,10 +886,12 @@ class EE_API UISceneNode : public SceneNode { UnorderedSet mDirtyLayouts; SmallVector mDirtyLayoutsSnapshot; std::vector> mTimes; + std::vector mChildUISceneNodes; ColorSchemePreference mColorSchemePreference{ ColorSchemePreference::Dark }; ContrastPreference mContrastPreference{ ContrastPreference::NoPreference }; Uint32 mMaxInvalidationDepth{ 3 }; Node* mCurParent{ nullptr }; + UISceneNode* mHostUISceneNode{ nullptr }; Uint32 mCurOnSizeChangeListener{ 0 }; Uint32 mCurrentMarker{ 0 }; Sizef mViewportPixelsSize; @@ -944,6 +954,9 @@ class EE_API UISceneNode : public SceneNode { void onViewportPixelsSizeChange(); const Sizef& getRootPixelsSize() const; UISceneNode* getHostUISceneNode() const; + void updateHostUISceneNode(); + void registerChildUISceneNode( UISceneNode* sceneNode ); + void unregisterChildUISceneNode( UISceneNode* sceneNode ); /** * @brief Sets the internal pixel size without triggering update cycles. diff --git a/src/eepp/ui/css/stylesheet.cpp b/src/eepp/ui/css/stylesheet.cpp index 65bf591ff..f68b64909 100644 --- a/src/eepp/ui/css/stylesheet.cpp +++ b/src/eepp/ui/css/stylesheet.cpp @@ -95,7 +95,7 @@ void StyleSheet::removeAllWithoutMarker( const Uint32& marker ) { invalidateCache(); } -void StyleSheet::setSelectorSpecificity( const Uint32& specificity ) { +void StyleSheet::setSelectorSpecificity( const Int64& specificity ) { for ( auto& node : mNodes ) node->setSelectorSpecificity( specificity ); invalidateCache(); diff --git a/src/eepp/ui/css/stylesheetproperty.cpp b/src/eepp/ui/css/stylesheetproperty.cpp index 9157d0d14..7df4a0639 100644 --- a/src/eepp/ui/css/stylesheetproperty.cpp +++ b/src/eepp/ui/css/stylesheetproperty.cpp @@ -48,7 +48,7 @@ StyleSheetProperty::StyleSheetProperty( const PropertyDefinition* definition, } StyleSheetProperty::StyleSheetProperty( bool isVolatile, const PropertyDefinition* definition, - const std::string& value, const Uint64& /*specificity*/, + const std::string& value, const Int64& /*specificity*/, const Uint32& index ) : mName( definition->getName() ), mNameHash( definition->getId() ), @@ -72,7 +72,7 @@ StyleSheetProperty::StyleSheetProperty( bool isVolatile, const PropertyDefinitio } StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::string& value, - bool trimValue, const Uint64& specificity, + bool trimValue, const Int64& specificity, const Uint32& index ) : mName( String::toLower( String::trim( name ) ) ), mNameHash( String::hash( mName ) ), @@ -99,7 +99,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri } StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::string& value, - const Uint64& specificity, bool isVolatile, + const Int64& specificity, bool isVolatile, const Uint32& index ) : mName( String::toLower( String::trim( name ) ) ), mNameHash( String::hash( mName ) ), @@ -143,11 +143,11 @@ const std::string& StyleSheetProperty::value() const { return mValue; } -const Uint64& StyleSheetProperty::getSpecificity() const { +const Int64& StyleSheetProperty::getSpecificity() const { return mSpecificity; } -void StyleSheetProperty::setSpecificity( const Uint64& specificity ) { +void StyleSheetProperty::setSpecificity( const Int64& specificity ) { mSpecificity = specificity; if ( mImportant ) mSpecificity += StyleSheetSelectorRule::SpecificityImportant; diff --git a/src/eepp/ui/css/stylesheetselector.cpp b/src/eepp/ui/css/stylesheetselector.cpp index 4dc391ca7..c7ff29844 100644 --- a/src/eepp/ui/css/stylesheetselector.cpp +++ b/src/eepp/ui/css/stylesheetselector.cpp @@ -16,11 +16,11 @@ const std::string& StyleSheetSelector::getName() const { return mName; } -const Uint32& StyleSheetSelector::getSpecificity() const { +const Int64& StyleSheetSelector::getSpecificity() const { return mSpecificity; } -void StyleSheetSelector::setSpecificity( const Uint32& specificity ) { +void StyleSheetSelector::setSpecificity( const Int64& specificity ) { mSpecificity = specificity; } diff --git a/src/eepp/ui/css/stylesheetstyle.cpp b/src/eepp/ui/css/stylesheetstyle.cpp index 6b3d04fe3..3732666ef 100644 --- a/src/eepp/ui/css/stylesheetstyle.cpp +++ b/src/eepp/ui/css/stylesheetstyle.cpp @@ -23,7 +23,7 @@ StyleSheetStyle::StyleSheetStyle( const std::string& selector, } } -void StyleSheetStyle::setSelectorSpecificity( const Uint32& specificity ) { +void StyleSheetStyle::setSelectorSpecificity( const Int64& specificity ) { const_cast( mSelector ).setSpecificity( specificity ); for ( auto& it : mProperties ) it.second.setSpecificity( specificity ); @@ -156,9 +156,8 @@ void StyleSheetStyle::clearProperties() { void StyleSheetStyle::clearCachedProperties() { StyleSheetProperties::iterator it; do { - it = std::find_if( - mProperties.begin(), mProperties.end(), - []( const auto& model ) { return model.second.isCachedProperty(); } ); + it = std::find_if( mProperties.begin(), mProperties.end(), + []( const auto& model ) { return model.second.isCachedProperty(); } ); if ( it != mProperties.end() ) mProperties.erase( it ); } while ( it != mProperties.end() ); diff --git a/src/eepp/ui/css/stylesheetvariable.cpp b/src/eepp/ui/css/stylesheetvariable.cpp index c83507189..943f06b48 100644 --- a/src/eepp/ui/css/stylesheetvariable.cpp +++ b/src/eepp/ui/css/stylesheetvariable.cpp @@ -12,7 +12,7 @@ StyleSheetVariable::StyleSheetVariable( const std::string& name, const std::stri mSpecificity( 0 ) {} StyleSheetVariable::StyleSheetVariable( const std::string& name, const std::string& value, - const Uint32& specificity ) : + const Int64& specificity ) : mName( String::toLower( String::trim( name ) ) ), mNameHash( String::hash( mName ) ), mValue( String::trim( value ) ), @@ -30,11 +30,11 @@ const std::string& StyleSheetVariable::value() const { return mValue; } -const Uint32& StyleSheetVariable::getSpecificity() const { +const Int64& StyleSheetVariable::getSpecificity() const { return mSpecificity; } -void StyleSheetVariable::setSpecificity( const Uint32& specificity ) { +void StyleSheetVariable::setSpecificity( const Int64& specificity ) { mSpecificity = specificity; } diff --git a/src/eepp/ui/tools/uiwidgetinspector.cpp b/src/eepp/ui/tools/uiwidgetinspector.cpp index 23c63f807..94dc0b057 100644 --- a/src/eepp/ui/tools/uiwidgetinspector.cpp +++ b/src/eepp/ui/tools/uiwidgetinspector.cpp @@ -13,12 +13,33 @@ #include #include +#include + using namespace EE::Window; using namespace EE::UI::Models; using namespace EE::Scene; namespace EE { namespace UI { namespace Tools { +struct UIWidgetInspector::PickHighlightOverState { + std::vector> sceneStates; + + void capture( UISceneNode* sceneNode ) { + if ( !sceneNode ) + return; + + sceneStates.emplace_back( sceneNode, sceneNode->getHighlightOver() ); + + for ( auto* childSceneNode : sceneNode->getChildUISceneNodes() ) + capture( childSceneNode ); + } + + void restore() { + for ( auto& sceneState : sceneStates ) + sceneState.first->setHighlightOver( sceneState.second ); + } +}; + UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIconSize, std::function highlightToggle, std::function drawBoxesToggle, @@ -90,6 +111,7 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc stylesEditor->setLineWrapType( LineWrapType::Viewport ); stylesEditor->setLineWrapMode( LineWrapMode::Word ); stylesEditor->setLineWrapKeepIndentation( true ); + stylesEditor->setColorPreview( true ); stylesEditor->setColorScheme( sceneNode->getColorSchemePreference() == ColorSchemePreference::Dark ? SyntaxColorScheme::getDefaultDark() @@ -135,11 +157,12 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc button->on( Event::MouseClick, [sceneNode, nodeTree, computedView]( const Event* event ) { if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK ) { - bool wasHighlightOver = sceneNode->getHighlightOver(); - sceneNode->setHighlightOver( true ); + auto highlightOverState = std::make_shared(); + highlightOverState->capture( sceneNode ); + sceneNode->setHighlightOverRecursive( true ); sceneNode->getEventDispatcher()->setDisableMousePress( true ); - sceneNode->runOnMainThread( [sceneNode, nodeTree, computedView, wasHighlightOver]() { - checkWidgetPick( sceneNode, nodeTree, wasHighlightOver, computedView ); + sceneNode->runOnMainThread( [sceneNode, nodeTree, computedView, highlightOverState]() { + checkWidgetPick( sceneNode, nodeTree, highlightOverState, computedView ); } ); } } ); @@ -221,18 +244,19 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc } void UIWidgetInspector::checkWidgetPick( UISceneNode* sceneNode, UITreeView* widgetTree, - bool wasHighlightOver, UITableView* tableView ) { + std::shared_ptr highlightOverState, + UITableView* tableView ) { Input* input = sceneNode->getWindow()->getInput(); if ( input->getClickTrigger() & EE_BUTTON_LMASK ) { Node* node = sceneNode->getEventDispatcher()->getMouseOverNode(); WidgetTreeModel* model = static_cast( widgetTree->getModel() ); ModelIndex index( model->getModelIndex( node ) ); widgetTree->setSelection( index ); - sceneNode->setHighlightOver( wasHighlightOver ); + highlightOverState->restore(); sceneNode->getEventDispatcher()->setDisableMousePress( false ); } else { - sceneNode->runOnMainThread( [sceneNode, widgetTree, wasHighlightOver, tableView]() { - checkWidgetPick( sceneNode, widgetTree, wasHighlightOver, tableView ); + sceneNode->runOnMainThread( [sceneNode, widgetTree, highlightOverState, tableView]() { + checkWidgetPick( sceneNode, widgetTree, highlightOverState, tableView ); } ); } } diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 452c77bbd..3b7f3d8f5 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #define PUGIXML_HEADER_ONLY #include @@ -158,6 +158,9 @@ UISceneNode::~UISceneNode() { mAsyncResourceLoadState->generation.fetch_add( 1, std::memory_order_acq_rel ); } + if ( mHostUISceneNode ) + mHostUISceneNode->unregisterChildUISceneNode( this ); + clearFontFaces(); eeSAFE_DELETE( mUIThemeManager ); @@ -238,6 +241,7 @@ void UISceneNode::onParentChange() { eeSAFE_DELETE( mEventDispatcher ); mCurParent = mParentNode; + updateHostUISceneNode(); if ( !mParentNode ) { setEventDispatcher( UIEventDispatcher::New( this ) ); @@ -245,7 +249,7 @@ void UISceneNode::onParentChange() { return; } - initializeEmbeddedFromHost( getHostUISceneNode() ); + initializeEmbeddedFromHost( mHostUISceneNode ); setDirty(); updateParentSizeListener(); @@ -254,7 +258,8 @@ void UISceneNode::onParentChange() { void UISceneNode::onSceneChange() { mSceneNode = this; eeASSERT( !removeFromCloseQueue( this ) ); - initializeEmbeddedFromHost( getHostUISceneNode() ); + updateHostUISceneNode(); + initializeEmbeddedFromHost( mHostUISceneNode ); Node* child = getFirstChild(); while ( NULL != child ) { @@ -308,6 +313,48 @@ void UISceneNode::initializeEmbeddedFromHost( UISceneNode* hostScene ) { mUIIconThemeManager->setFallbackThemeManager( mUIThemeManager ); } +const std::vector& UISceneNode::getChildUISceneNodes() const { + return mChildUISceneNodes; +} + +void UISceneNode::setHighlightOverRecursive( bool highlight ) { + setHighlightOver( highlight ); + + for ( auto* sceneNode : mChildUISceneNodes ) + sceneNode->setHighlightOverRecursive( highlight ); +} + +void UISceneNode::updateHostUISceneNode() { + UISceneNode* hostScene = getHostUISceneNode(); + + if ( mHostUISceneNode == hostScene ) + return; + + if ( mHostUISceneNode ) + mHostUISceneNode->unregisterChildUISceneNode( this ); + + mHostUISceneNode = hostScene; + + if ( mHostUISceneNode ) + mHostUISceneNode->registerChildUISceneNode( this ); +} + +void UISceneNode::registerChildUISceneNode( UISceneNode* sceneNode ) { + if ( !sceneNode || sceneNode == this || + std::find( mChildUISceneNodes.begin(), mChildUISceneNodes.end(), sceneNode ) != + mChildUISceneNodes.end() ) + return; + + mChildUISceneNodes.push_back( sceneNode ); +} + +void UISceneNode::unregisterChildUISceneNode( UISceneNode* sceneNode ) { + auto it = std::find( mChildUISceneNodes.begin(), mChildUISceneNodes.end(), sceneNode ); + + if ( it != mChildUISceneNodes.end() ) + mChildUISceneNodes.erase( it ); +} + void UISceneNode::updateParentSizeListener() { if ( !mParentNode || !mFollowParentSize ) return; @@ -1659,8 +1706,8 @@ void UISceneNode::loadCSS( URI uri, std::optional