| 847 | } |
| 848 | |
| 849 | void UISceneNode::invalidateLayout( UILayout* node ) { |
| 850 | eeASSERT( NULL != node ); |
| 851 | |
| 852 | if ( node->isClosing() ) |
| 853 | return; |
| 854 | |
| 855 | if ( mDirtyLayouts.count( node ) > 0 ) |
| 856 | return; |
| 857 | |
| 858 | // 1. Walk UP the tree. |
| 859 | // If any ancestor is already dirty AND the path to it is entirely layouts, |
| 860 | // we can early-out because that ancestor will naturally update this node. |
| 861 | Node* ancestorIt = node->getParent(); |
| 862 | while ( ancestorIt != nullptr ) { |
| 863 | if ( !ancestorIt->isLayout() ) { |
| 864 | // The invalidation path is broken by a non-layout node. |
| 865 | // Any dirty layouts above this won't automatically trickle down to 'node'. |
| 866 | break; |
| 867 | } |
| 868 | |
| 869 | if ( mDirtyLayouts.count( ancestorIt->asType<UILayout>() ) > 0 ) |
| 870 | return; // A valid ancestor is already dirty! Skip adding this node. |
| 871 | |
| 872 | ancestorIt = ancestorIt->getParent(); |
| 873 | } |
| 874 | |
| 875 | // 2. Walk DOWN the dirty list. |
| 876 | // Remove any already-dirty layouts that will be naturally updated by THIS node. |
| 877 | SmallVector<UILayout*> eraseList; |
| 878 | |
| 879 | for ( auto layout : mDirtyLayouts ) { |
| 880 | if ( NULL == layout ) { |
| 881 | eraseList.push_back( layout ); |
| 882 | continue; |
| 883 | } |
| 884 | |
| 885 | // Traverse up from 'layout' to 'node'. |
| 886 | Node* it = layout->getParent(); |
| 887 | bool isValidPath = false; |
| 888 | |
| 889 | while ( it != nullptr ) { |
| 890 | if ( it == node ) { |
| 891 | // We reached 'node', and every node in between was a layout! |
| 892 | isValidPath = true; |
| 893 | break; |
| 894 | } |
| 895 | if ( !it->isLayout() ) { |
| 896 | // The invalidation path is broken, or 'node' isn't an ancestor. |
| 897 | break; |
| 898 | } |
| 899 | it = it->getParent(); |
| 900 | } |
| 901 | |
| 902 | if ( isValidPath ) |
| 903 | eraseList.push_back( layout ); |
| 904 | } |
| 905 | |
| 906 | // 3. Clean up and insert |