diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index dc5fcb7b8..a492aa88f 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -899,6 +899,60 @@ class EE_API String { String::View view() const; + // No allocation int to str + template + static const StrType* intToStrBuf( IntType value, StrType* buffer, size_t bufferSize, + size_t padding, StrType padChar ) { + static_assert( std::is_integral::value, "Type must be an integer" ); + + if ( bufferSize <= 1 ) { + if ( bufferSize == 1 ) + *buffer = '\0'; + return buffer; + } + + StrType* ptr = buffer; + StrType* endPtr = buffer + bufferSize - 1; + + if constexpr ( std::is_signed::value ) { + if ( value < 0 ) { + if ( ptr == endPtr ) { + *buffer = '\0'; + return buffer; + } + *ptr++ = '-'; + value = -value; + padding--; + } + } + + StrType* start = ptr; + do { + if ( ptr == endPtr ) { // Out of buffer space + *buffer = '\0'; + return buffer; + } + *ptr++ = '0' + ( value % 10 ); + value /= 10; + padding--; + } while ( value > 0 ); + + while ( padding-- > 0 ) { + if ( ptr == endPtr ) { + *buffer = '\0'; + return buffer; + } + *ptr++ = padChar; + } + + StrType* reverseEnd = ptr - 1; + while ( start < reverseEnd ) + std::swap( *start++, *reverseEnd-- ); + + *ptr = '\0'; + return buffer; + } + private: friend EE_API bool operator==( const String& left, const String& right ); friend EE_API bool operator<( const String& left, const String& right ); diff --git a/include/eepp/scene/actionmanager.hpp b/include/eepp/scene/actionmanager.hpp index 25c323a16..eab2cc81f 100644 --- a/include/eepp/scene/actionmanager.hpp +++ b/include/eepp/scene/actionmanager.hpp @@ -56,6 +56,8 @@ class EE_API ActionManager { std::vector mActionsRemoveList; mutable Mutex mMutex; std::atomic mUpdating; + + void update( const Time& time, Action** actions, size_t count ); }; }} // namespace EE::Scene diff --git a/include/eepp/ui/abstract/uiabstracttableview.hpp b/include/eepp/ui/abstract/uiabstracttableview.hpp index 306a1952b..44cbc59c7 100644 --- a/include/eepp/ui/abstract/uiabstracttableview.hpp +++ b/include/eepp/ui/abstract/uiabstracttableview.hpp @@ -196,6 +196,8 @@ class EE_API UIAbstractTableView : public UIAbstractView { virtual UIWidget* updateCell( const Vector2& posIndex, const ModelIndex& index, const size_t& indentLevel, const Float& yOffset ); + virtual void updateTableCellData( UITableCell* cell, const ModelIndex& index ); + virtual UIWidget* createCell( UIWidget* rowWidget, const ModelIndex& index ); virtual UIWidget* setupCell( UITableCell* widget, UIWidget* rowWidget, diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index ea47b655d..1af43758b 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -141,8 +141,6 @@ class EE_API UITreeView : public UIAbstractTableView { const Float& )> TreeViewCallback; - void traverseTree( TreeViewCallback ) const; - mutable std::unordered_map mViewMetadata; virtual size_t getItemCount() const; @@ -168,6 +166,19 @@ class EE_API UITreeView : public UIAbstractTableView { virtual void onModelSelectionChange(); virtual void bindNavigationClick( UIWidget* widget ); + + struct TraverseTreeVars { + UITreeView::TreeViewCallback callback; + const Model& model; + int indentLevel = 0; + Float yOffset = 0; + int rowIndex = -1; + Float rowHeight = 0; + }; + + IterationDecision traverseIndex( TraverseTreeVars& v, const ModelIndex& index ) const; + + void traverseTree( TreeViewCallback ) const; }; }} // namespace EE::UI diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index c400968e6..398aa4441 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -166,6 +166,8 @@ class EE_API UIWidget : public UINode { /** Resets all classes and assign a class */ UIWidget* setClass( const std::string& cls ); + UIWidget* setClass( std::string&& cls ); + /** Resets all classes and assign vector of classes */ UIWidget* setClasses( const std::vector& classes ); @@ -177,13 +179,13 @@ class EE_API UIWidget : public UINode { UIWidget* removeClasses( const std::vector& classes ); - bool hasClass( const std::string& cls ) const; + bool hasClass( const std::string_view& cls ) const; void toggleClass( const std::string& cls ); void setElementTag( const std::string& tag ); - const std::vector getClasses() const; + const std::vector& getClasses() const; const std::string& getElementTag() const; diff --git a/src/eepp/core/memorymanager.cpp b/src/eepp/core/memorymanager.cpp index 99a08d022..4104a2668 100644 --- a/src/eepp/core/memorymanager.cpp +++ b/src/eepp/core/memorymanager.cpp @@ -9,6 +9,22 @@ using namespace EE::System; using namespace EE::Window; +#ifdef EE_MEMORY_MANAGER + +static bool sHasInit = false; +/* +void* operator new( std::size_t n ) { + return malloc( n ); +} + +void operator delete( void* p ) throw() { + free( p ); +} +*/ +#else +static bool sHasInit = true; +#endif + namespace EE { static AllocatedPointerMap sMapPointers; @@ -26,9 +42,13 @@ AllocatedPointer::AllocatedPointer( void* data, const std::string& file, int lin mTrack = track; } -void* MemoryManager::allocate( size_t size ) { return malloc( size ); } +void* MemoryManager::allocate( size_t size ) { + return malloc( size ); +} -void* MemoryManager::reallocate( void* ptr, size_t size ) { return realloc( ptr, size ); } +void* MemoryManager::reallocate( void* ptr, size_t size ) { + return realloc( ptr, size ); +} void* MemoryManager::addPointerInPlace( void* place, const AllocatedPointer& aAllocatedPointer ) { AllocatedPointerMapIt it = sMapPointers.find( place ); @@ -41,7 +61,7 @@ void* MemoryManager::addPointerInPlace( void* place, const AllocatedPointer& aAl } void* MemoryManager::addPointer( const AllocatedPointer& aAllocatedPointer ) { - Lock l( sAlloMutex ); + ConditionalLock l( sHasInit, &sAlloMutex ); sMapPointers.insert( AllocatedPointerMap::value_type( aAllocatedPointer.mData, aAllocatedPointer ) ); @@ -60,6 +80,10 @@ void* MemoryManager::addPointer( const AllocatedPointer& aAllocatedPointer ) { eePRINTL( "Allocating pointer %p at '%s' %d", aAllocatedPointer.mData, aAllocatedPointer.mFile.c_str(), aAllocatedPointer.mLine ); +#ifdef EE_MEMORY_MANAGER + sHasInit = true; +#endif + return aAllocatedPointer.mData; } diff --git a/src/eepp/scene/actionmanager.cpp b/src/eepp/scene/actionmanager.cpp index 09ee59c6b..5d9806ed4 100644 --- a/src/eepp/scene/actionmanager.cpp +++ b/src/eepp/scene/actionmanager.cpp @@ -105,23 +105,11 @@ bool ActionManager::removeActionsByTagFromTarget( Node* target, const Action::Un return !removeList.empty(); } -void ActionManager::update( const Time& time ) { - if ( isEmpty() ) - return; - +void ActionManager::update( const Time& time, Action** actions, size_t count ) { std::vector removeList; - mUpdating = true; - - // Actions can be added during action updates, we need to only iterate the current actions - std::vector actions; - { - Lock l( mMutex ); - actions = mActions; - } - - for ( auto it = actions.begin(); it != actions.end(); ++it ) { - Action* action = *it; + for ( size_t i = 0; i < count; i++ ) { + Action* action = actions[i]; if ( std::find( mActionsRemoveList.begin(), mActionsRemoveList.end(), action ) != mActionsRemoveList.end() ) @@ -147,6 +135,44 @@ void ActionManager::update( const Time& time ) { removeAction( *it ); } +void ActionManager::update( const Time& time ) { + if ( isEmpty() ) + return; + + mUpdating = true; + size_t size; + + { + Lock l( mMutex ); + size = mActions.size(); + } + + // Micro-optimization to avoid heap allocations during updates (which are done usually at 60 hz) + if ( size <= 8 ) { + Action* actions[8]; + { + Lock l( mMutex ); + std::copy( mActions.begin(), mActions.end(), actions ); + } + update( time, actions, size ); + } else if ( size <= 16 ) { + Action* actions[16]; + { + Lock l( mMutex ); + std::copy( mActions.begin(), mActions.end(), actions ); + } + update( time, actions, size ); + } else { + // Actions can be added during action updates, we need to only iterate the current actions + std::vector actions; + { + Lock l( mMutex ); + actions = mActions; + } + update( time, actions.data(), size ); + } +} + std::size_t ActionManager::count() const { Lock l( mMutex ); return mActions.size(); diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 174151bcd..8362c965f 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -1227,7 +1227,7 @@ void Node::clearEventListener() { void Node::sendEvent( const Event* event ) { if ( 0 != mEvents.count( event->getType() ) ) { - std::map eventMap = mEvents[event->getType()]; + auto& eventMap = mEvents[event->getType()]; if ( eventMap.begin() != eventMap.end() ) { std::map::iterator it; for ( it = eventMap.begin(); it != eventMap.end(); ++it ) { diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index db8d7925c..a8d4f8899 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -582,47 +582,7 @@ UIWidget* UIAbstractTableView::updateCell( const Vector2& posIndex, const widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } ); if ( widget->isType( UI_TYPE_TABLECELL ) ) { UITableCell* cell = widget->asType(); - cell->setCurIndex( index ); - - if ( getModel()->classModelRoleEnabled() ) { - bool needsReloadStyle = false; - Variant cls( getModel()->data( index, ModelRole::Class ) ); - cell->setLoadingState( true ); - if ( cls.isValid() ) { - std::string clsStr( cls.toString() ); - needsReloadStyle = cell->getClasses().empty() || cell->getClasses().size() != 1 || - clsStr != cell->getClasses()[0]; - cell->setClass( clsStr ); - } else { - needsReloadStyle = !cell->getClasses().empty(); - cell->resetClass(); - } - cell->setLoadingState( false ); - if ( needsReloadStyle ) - cell->reportStyleStateChangeRecursive(); - } - - if ( getModel()->tooltipModelRoleEnabled() ) { - Variant tooltip( getModel()->data( index, ModelRole::Tooltip ) ); - if ( tooltip.isValid() ) { - if ( tooltip.is( Variant::Type::String ) ) - cell->setTooltipText( tooltip.asString() ); - else if ( tooltip.is( Variant::Type::StringPtr ) ) - cell->setTooltipText( tooltip.asStringPtr() ); - else - cell->setTooltipText( tooltip.toString() ); - } - } - - Variant txt( getModel()->data( index, ModelRole::Display ) ); - if ( txt.isValid() ) { - if ( txt.is( Variant::Type::String ) ) - cell->setText( txt.asString() ); - else if ( txt.is( Variant::Type::StringPtr ) ) - cell->setText( txt.asStringPtr() ); - else - cell->setText( txt.toString() ); - } + updateTableCellData( cell, index ); bool isVisible = false; Variant icon( getModel()->data( index, ModelRole::Icon ) ); @@ -650,6 +610,59 @@ UIWidget* UIAbstractTableView::updateCell( const Vector2& posIndex, const return widget; } +void UIAbstractTableView::updateTableCellData( UITableCell* cell, const ModelIndex& index ) { + cell->setCurIndex( index ); + + if ( getModel()->classModelRoleEnabled() ) { + bool needsReloadStyle = false; + Variant cls( getModel()->data( index, ModelRole::Class ) ); + cell->setLoadingState( true ); + if ( cls.isValid() ) { + bool hasClass = false; + + hasClass = + ( cls.is( Variant::Type::cstr ) && + cell->hasClass( std::string_view{ cls.asCStr() } ) ) || + ( cls.is( Variant::Type::StdString ) && cell->hasClass( cls.asStdString() ) ) || + cell->hasClass( cls.toString() ); + + needsReloadStyle = + cell->getClasses().empty() || cell->getClasses().size() != 1 || !hasClass; + + if ( !hasClass ) + cell->setClass( cls.toString() ); + } else { + needsReloadStyle = !cell->getClasses().empty(); + cell->resetClass(); + } + cell->setLoadingState( false ); + if ( needsReloadStyle ) + cell->reportStyleStateChangeRecursive(); + } + + if ( getModel()->tooltipModelRoleEnabled() ) { + Variant tooltip( getModel()->data( index, ModelRole::Tooltip ) ); + if ( tooltip.isValid() ) { + if ( tooltip.is( Variant::Type::String ) ) + cell->setTooltipText( tooltip.asString() ); + else if ( tooltip.is( Variant::Type::StringPtr ) ) + cell->setTooltipText( tooltip.asStringPtr() ); + else + cell->setTooltipText( tooltip.toString() ); + } + } + + Variant txt( getModel()->data( index, ModelRole::Display ) ); + if ( txt.isValid() ) { + if ( txt.is( Variant::Type::String ) ) + cell->setText( txt.asString() ); + else if ( txt.is( Variant::Type::StringPtr ) ) + cell->setText( txt.asStringPtr() ); + else + cell->setText( txt.toString() ); + } +} + void UIAbstractTableView::moveSelection( int steps ) { if ( !getModel() ) return; diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 439cbacb3..51275fe7c 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -3837,19 +3837,22 @@ void UICodeEditor::drawLineNumbers( const DocumentLineRange& lineRange, const Ve for ( int i = lineRange.first; i <= lineRange.second; i++ ) { if ( !mDocView.isLineVisible( i ) ) continue; - String pos; + String::StringBaseType pos[16]; + if ( mShowLinesRelativePosition && selection.start().line() != i ) { - pos = String( String::toString( eeabs( i - selection.start().line() ) ) ) - .padLeft( lineNumberDigits, ' ' ); + String::intToStrBuf( eeabs( i - selection.start().line() ), + pos, 16, lineNumberDigits, ' ' ); } else { - pos = String( String::toString( i + 1 ) ).padLeft( lineNumberDigits, ' ' ); + String::intToStrBuf( i + 1, pos, 16, lineNumberDigits, + ' ' ); } + auto lnPos( Vector2f( screenStart.x + mLineNumberPaddingLeft, startScroll.y + mDocView.getLineYOffset( i, lineHeight ) + lineOffset ) ); if ( mShowLineNumber ) { - Text::draw( pos, lnPos, mFontStyleConfig.Font, fontSize, + Text::draw( String::View{ pos }, lnPos, mFontStyleConfig.Font, fontSize, ( i >= selection.start().line() && i <= selection.end().line() ) ? mLineNumberActiveFontColor : mLineNumberFontColor, @@ -4343,6 +4346,19 @@ Rectf UICodeEditor::getMinimapRect( const Vector2f& start ) const { static const SyntaxStyleType SYNTAX_NORMAL = SyntaxStyleTypes::Normal; +struct MinimapTextRangesVars { + BatchRenderer* BR; + Float minimapStart; + Float charHeight; + Int64 minimapStartLine; + Float lineSpacing; + Rectf rect; + Float minimapCutoffX; + Float widthScale; + Int64 endidx; + Int64 maxVisibleColumn; +}; + void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, const DocumentViewLineRange& visibleLineRange ) { Float charHeight = PixelDensity::getPixelDensity() * mMinimapConfig.scale; @@ -4437,15 +4453,17 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, Float minimapStart = rect.Left + gutterWidth; - const auto drawTextRanges = [this, &BR, &minimapStart, &charHeight, &minimapStartLine, - &lineSpacing, &rect, &minimapCutoffX, &widthScale, &endidx, - &maxVisibleColumn]( const TextRanges& ranges, - const Color& backgroundColor, - bool drawCompleteLine = false ) { - BR->quadsSetColor( backgroundColor ); + // Avoid heap allocating the lambda + MinimapTextRangesVars v{ BR, minimapStart, charHeight, minimapStartLine, lineSpacing, + rect, minimapCutoffX, widthScale, endidx, maxVisibleColumn }; + + const auto drawMinimapTextRanges = [this, &v]( const TextRanges& ranges, + const Color& backgroundColor, + bool drawCompleteLine = false ) { + v.BR->quadsSetColor( backgroundColor ); Int64 lineSkip = -1; for ( const auto& range : ranges ) { - if ( !mDocView.isWrapEnabled() && range.start().column() > maxVisibleColumn ) + if ( !mDocView.isWrapEnabled() && range.start().column() > v.maxVisibleColumn ) continue; auto rangeStart = mDocView.getVisibleLineRange( range.start() ); @@ -4456,39 +4474,39 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, if ( rangeEnd.visibleIndex == VisibleIndex::invalid ) continue; - if ( minimapStartLine > static_cast( rangeEnd.visibleIndex ) || - endidx < static_cast( rangeStart.visibleIndex ) ) + if ( v.minimapStartLine > static_cast( rangeEnd.visibleIndex ) || + v.endidx < static_cast( rangeStart.visibleIndex ) ) continue; - if ( ranges.isSorted() && static_cast( rangeStart.visibleIndex ) > endidx && - static_cast( rangeEnd.visibleIndex ) > endidx ) + if ( ranges.isSorted() && static_cast( rangeStart.visibleIndex ) > v.endidx && + static_cast( rangeEnd.visibleIndex ) > v.endidx ) break; if ( lineSkip == static_cast( rangeStart.visibleIndex ) ) continue; auto selRects = getTextRangeRectangles( - range, { 0, rect.Top - minimapStartLine * lineSpacing }, {}, lineSpacing, - DocumentViewLineRange{ static_cast( minimapStartLine ), - static_cast( endidx ) } ); + range, { 0, v.rect.Top - v.minimapStartLine * v.lineSpacing }, {}, v.lineSpacing, + DocumentViewLineRange{ static_cast( v.minimapStartLine ), + static_cast( v.endidx ) } ); for ( auto& selRect : selRects ) { - auto curLine = eefloor( selRect.Top / lineSpacing ); + auto curLine = eefloor( selRect.Top / v.lineSpacing ); if ( curLine == lineSkip ) continue; - selRect.Bottom = selRect.Top + charHeight; + selRect.Bottom = selRect.Top + v.charHeight; if ( drawCompleteLine ) { - selRect.Left = minimapStart; - selRect.Right = minimapStart + rect.getWidth(); + selRect.Left = v.minimapStart; + selRect.Right = v.minimapStart + v.rect.getWidth(); } else { - selRect.Left = minimapStart + selRect.Left * widthScale; - selRect.Right = minimapStart + selRect.Right * widthScale; + selRect.Left = v.minimapStart + selRect.Left * v.widthScale; + selRect.Right = v.minimapStart + selRect.Right * v.widthScale; } - if ( selRect.Left <= minimapCutoffX ) { - BR->batchQuad( selRect ); + if ( selRect.Left <= v.minimapCutoffX ) { + v.BR->batchQuad( selRect ); } else { lineSkip = curLine; } @@ -4496,7 +4514,7 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, } }; - auto drawWordMatch = [this, &drawTextRanges]( const String& text, const Int64& ln ) { + auto drawWordMatch = [this, &drawMinimapTextRanges]( const String& text, const Int64& ln ) { size_t pos = 0; const String& line( mDoc->line( ln ).getText() ); if ( line.size() > 300 ) @@ -4507,7 +4525,8 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, Int64 startCol = pos; Int64 endCol = pos + text.size(); TextRange range( { ln, startCol }, { ln, endCol } ); - drawTextRanges( { range }, Color( mMinimapHighlightColor ).blendAlpha( mAlpha ) ); + drawMinimapTextRanges( { range }, + Color( mMinimapHighlightColor ).blendAlpha( mAlpha ) ); pos = endCol; } else { break; @@ -4538,7 +4557,8 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, if ( !mHighlightWord.isEmpty() ) { Lock l( mHighlightWordCacheMutex ); - drawTextRanges( mHighlightWordCache, Color( mMinimapHighlightColor ).blendAlpha( mAlpha ) ); + drawMinimapTextRanges( mHighlightWordCache, + Color( mMinimapHighlightColor ).blendAlpha( mAlpha ) ); } Int64 minimapStartDocLine = @@ -4552,7 +4572,7 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, for ( auto* plugin : mPlugins ) { plugin->minimapDrawBefore( this, docRange, docViewRange, { rect.Left, lineY }, { rect.getWidth(), charHeight }, charSpacing, gutterWidth, - drawTextRanges ); + drawMinimapTextRanges ); } for ( Int64 line = minimapStartDocLine; line <= endDocIdx; line++ ) { @@ -4690,17 +4710,17 @@ void UICodeEditor::drawMinimap( const Vector2f& start, const DocumentLineRange&, for ( auto* plugin : mPlugins ) { plugin->minimapDrawAfter( this, docRange, docViewRange, { rect.Left, lineY }, { rect.getWidth(), charHeight }, charSpacing, gutterWidth, - drawTextRanges ); + drawMinimapTextRanges ); } if ( mHighlightTextRange.isValid() && mHighlightTextRange.hasSelection() ) { - drawTextRanges( { mHighlightTextRange }, - Color( mMinimapSelectionColor ).blendAlpha( mAlpha ) ); + drawMinimapTextRanges( { mHighlightTextRange }, + Color( mMinimapSelectionColor ).blendAlpha( mAlpha ) ); } if ( mDoc->hasSelection() ) { - drawTextRanges( mDoc->getSelectionsSorted(), - Color( mMinimapSelectionColor ).blendAlpha( mAlpha ) ); + drawMinimapTextRanges( mDoc->getSelectionsSorted(), + Color( mMinimapSelectionColor ).blendAlpha( mAlpha ) ); } for ( size_t i = 0; i < mDoc->getSelections().size(); ++i ) { diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 2eba4cf93..413140544 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -44,45 +44,44 @@ UITreeView::MetadataForIndex& UITreeView::getIndexMetadata( const ModelIndex& in return mViewMetadata[index.internalData()]; } +UITreeView::IterationDecision UITreeView::traverseIndex( TraverseTreeVars& v, + const ModelIndex& index ) const { + if ( index.isValid() ) { + const auto& metadata = getIndexMetadata( index ); + v.rowIndex++; + IterationDecision decision = v.callback( v.rowIndex, index, v.indentLevel, v.yOffset ); + if ( decision == IterationDecision::Break || decision == IterationDecision::Stop ) + return decision; + v.yOffset += v.rowHeight; + if ( !metadata.open ) { + return IterationDecision::Continue; + } + } + if ( v.indentLevel >= 0 && !index.isValid() ) + return IterationDecision::Continue; + ++v.indentLevel; + int rowCount = v.model.rowCount( index ); + for ( int i = 0; i < rowCount; ++i ) { + IterationDecision decision = + traverseIndex( v, v.model.index( i, v.model.treeColumn(), index ) ); + if ( decision == IterationDecision::Break || decision == IterationDecision::Stop ) + return decision; + } + --v.indentLevel; + return IterationDecision::Continue; +} + void UITreeView::traverseTree( TreeViewCallback callback ) const { if ( !getModel() ) return; Lock l( const_cast( getModel() )->resourceMutex() ); - auto& model = *getModel(); - int indentLevel = 0; - Float yOffset = getHeaderHeight(); - int rowIndex = -1; - Float rowHeight = getRowHeight(); - std::function traverseIndex = - [&]( const ModelIndex& index ) { - if ( index.isValid() ) { - const auto& metadata = getIndexMetadata( index ); - rowIndex++; - IterationDecision decision = callback( rowIndex, index, indentLevel, yOffset ); - if ( decision == IterationDecision::Break || decision == IterationDecision::Stop ) - return decision; - yOffset += rowHeight; - if ( !metadata.open ) { - return IterationDecision::Continue; - } - } - if ( indentLevel >= 0 && !index.isValid() ) - return IterationDecision::Continue; - ++indentLevel; - int rowCount = model.rowCount( index ); - for ( int i = 0; i < rowCount; ++i ) { - IterationDecision decision = - traverseIndex( model.index( i, model.treeColumn(), index ) ); - if ( decision == IterationDecision::Break || decision == IterationDecision::Stop ) - return decision; - } - --indentLevel; - return IterationDecision::Continue; - }; - int rootCount = model.rowCount(); + TraverseTreeVars v{ + std::move( callback ), *getModel(), 0, getHeaderHeight(), -1, getRowHeight(), + }; + int rootCount = v.model.rowCount(); for ( int rootIndex = 0; rootIndex < rootCount; ++rootIndex ) { IterationDecision decision = - traverseIndex( model.index( rootIndex, model.treeColumn(), ModelIndex() ) ); + traverseIndex( v, v.model.index( rootIndex, v.model.treeColumn(), ModelIndex() ) ); if ( decision == IterationDecision::Break || decision == IterationDecision::Stop ) break; } @@ -238,54 +237,7 @@ UIWidget* UITreeView::updateCell( const Vector2& posIndex, const ModelInd widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } ); if ( widget->isType( UI_TYPE_TABLECELL ) ) { UITableCell* cell = widget->asType(); - cell->setCurIndex( index ); - - if ( getModel()->classModelRoleEnabled() ) { - bool needsReloadStyle = false; - Variant cls( getModel()->data( index, ModelRole::Class ) ); - cell->setLoadingState( true ); - if ( cls.isValid() ) { - std::string clsStr( cls.toString() ); - needsReloadStyle = cell->getClasses().empty() || cell->getClasses().size() != 1 || - clsStr != cell->getClasses()[0]; - cell->setClass( clsStr ); - } else { - needsReloadStyle = !cell->getClasses().empty(); - cell->resetClass(); - } - cell->setLoadingState( false ); - if ( needsReloadStyle ) - cell->reportStyleStateChangeRecursive(); - } - - if ( getModel()->tooltipModelRoleEnabled() ) { - Variant cls( getModel()->data( index, ModelRole::TooltipClass ) ); - if ( cls.isValid() ) { - cell->createTooltip()->setClass( cls.toString() ); - } else { - cell->createTooltip()->resetClass(); - } - - Variant tooltip( getModel()->data( index, ModelRole::Tooltip ) ); - if ( tooltip.isValid() ) { - if ( tooltip.is( Variant::Type::String ) ) - cell->setTooltipText( tooltip.asString() ); - else if ( tooltip.is( Variant::Type::StringPtr ) ) - cell->setTooltipText( tooltip.asStringPtr() ); - else - cell->setTooltipText( tooltip.toString() ); - } - } - - Variant txt( getModel()->data( index, ModelRole::Display ) ); - if ( txt.isValid() ) { - if ( txt.is( Variant::Type::String ) ) - cell->setText( txt.asString() ); - else if ( txt.is( Variant::Type::StringPtr ) ) - cell->setText( txt.asStringPtr() ); - else - cell->setText( txt.toString() ); - } + updateTableCellData( cell, index ); bool hasChilds = false; @@ -373,22 +325,26 @@ Sizef UITreeView::getContentSize() const { return mContentSize; } -void UITreeView::drawChilds() { +struct DrawTraverseTreeVars { + UITreeView* tree; int realRowIndex = 0; int realColIndex = 0; - Float rowHeight = getRowHeight(); + Float rowHeight = 0; +}; - traverseTree( [this, &realRowIndex, &realColIndex, - rowHeight]( const int&, const ModelIndex& index, const size_t& indentLevel, - const Float& yOffset ) { +void UITreeView::drawChilds() { + DrawTraverseTreeVars v{ this, 0, 0, getRowHeight() }; // To avoid allocating the lambda + + traverseTree( [this, &v]( const int&, const ModelIndex& index, const size_t& indentLevel, + const Float& yOffset ) { if ( yOffset - mScrollOffset.y > mSize.getHeight() ) return IterationDecision::Stop; - if ( yOffset - mScrollOffset.y + rowHeight < 0 ) + if ( yOffset - mScrollOffset.y + v.rowHeight < 0 ) return IterationDecision::Continue; Float xOffset = 0; - UITableRow* rowNode = updateRow( realRowIndex, index, yOffset ); + UITableRow* rowNode = updateRow( v.realRowIndex, index, yOffset ); rowNode->setChildsVisibility( false, false ); - realColIndex = 0; + v.realColIndex = 0; for ( size_t colIndex = 0; colIndex < getModel()->columnCount(); colIndex++ ) { auto& colData = columnData( colIndex ); if ( !colData.visible || ( xOffset + colData.width ) - mScrollOffset.x < 0 ) { @@ -400,22 +356,22 @@ void UITreeView::drawChilds() { break; xOffset += colData.width; if ( (Int64)colIndex != index.column() ) { - updateCell( { realColIndex, realRowIndex }, + updateCell( { v.realColIndex, v.realRowIndex }, getModel()->index( index.row(), colIndex, index.parent() ), indentLevel, yOffset ); } else { auto* cell = - updateCell( { realColIndex, realRowIndex }, index, indentLevel, yOffset ); + updateCell( { v.realColIndex, v.realRowIndex }, index, indentLevel, yOffset ); if ( mFocusSelectionDirty && index == getSelection().first() ) { cell->setFocus(); mFocusSelectionDirty = false; } } - realColIndex++; + v.realColIndex++; } rowNode->nodeDraw(); - realRowIndex++; + v.realRowIndex++; return IterationDecision::Continue; } ); diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 908db7b31..da59f3b90 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -863,6 +863,26 @@ UIWidget* UIWidget::setClass( const std::string& cls ) { return this; } +UIWidget* UIWidget::setClass( std::string&& cls ) { + size_t oldClassesCount = mClasses.size(); + if ( mClasses.size() != 1 || mClasses[0] != cls ) { + bool isSet = false; + mClasses.clear(); + if ( !cls.empty() ) { + mClasses.emplace_back( std::move( cls ) ); + isSet = true; + + if ( !isSceneNodeLoading() && !isLoadingState() ) { + getUISceneNode()->invalidateStyle( this ); + getUISceneNode()->invalidateStyleState( this ); + } + } + if ( oldClassesCount != mClasses.size() || isSet ) + onClassChange(); + } + return this; +} + UIWidget* UIWidget::setClasses( const std::vector& classes ) { if ( mClasses != classes ) { mClasses = classes; @@ -949,7 +969,7 @@ UIWidget* UIWidget::removeClasses( const std::vector& classes ) { return this; } -bool UIWidget::hasClass( const std::string& cls ) const { +bool UIWidget::hasClass( const std::string_view& cls ) const { return std::find( mClasses.begin(), mClasses.end(), cls ) != mClasses.end(); } @@ -993,7 +1013,7 @@ void UIWidget::setElementTag( const std::string& tag ) { } } -const std::vector UIWidget::getClasses() const { +const std::vector& UIWidget::getClasses() const { return mClasses; } diff --git a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp index 46091e707..c8dd6b2f0 100644 --- a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp @@ -46,23 +46,27 @@ TerminalKeyMap::TerminalKeyMap( const TerminalKey keys[], size_t keysLen, const TerminalShortcut shortcuts[], size_t shortcutsLen, const TerminalMouseShortcut mouseShortcuts[], size_t mouseShortcutsLen ) { + mKeyMap.reserve( keysLen ); for ( size_t i = 0; i < keysLen; i++ ) { auto& e = mKeyMap[keys[i].keysym]; e.push_back( { keys[i].mask, keys[i].string, keys[i].appkey, keys[i].appcursor } ); } + mPlatformKeyMap.reserve( platformKeysLen ); for ( size_t i = 0; i < platformKeysLen; i++ ) { auto& e = mPlatformKeyMap[platformKeys[i].scancode]; e.push_back( { platformKeys[i].mask, platformKeys[i].string, platformKeys[i].appkey, platformKeys[i].appcursor } ); } + mShortcuts.reserve( shortcutsLen ); for ( size_t i = 0; i < shortcutsLen; i++ ) { auto& e = mShortcuts[shortcuts[i].keysym]; e.push_back( { shortcuts[i].mask, shortcuts[i].action, shortcuts[i].appkey, shortcuts[i].appcursor, shortcuts[i].altscrn } ); } + mMouseShortcuts.reserve( mouseShortcutsLen ); for ( size_t i = 0; i < mouseShortcutsLen; i++ ) { auto& e = mMouseShortcuts[mouseShortcuts[i].button]; e.push_back( { mouseShortcuts[i].mask, mouseShortcuts[i].action, mouseShortcuts[i].appkey, diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index d3ec62be5..5a9f9b7c8 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -258,8 +258,11 @@ void GitPlugin::initModelStyler() { auto model = static_cast( index.model() ); auto node = static_cast( data ); Lock l( mGitStatusFileCacheMutex ); - auto found = - mGitStatusFilesCache.find( std::string{ model->getNodeRelativePath( node ) } ); + std::string_view nodePath = model->getNodeRelativePath( node ); + auto found = std::find_if( mGitStatusFilesCache.begin(), mGitStatusFilesCache.end(), + [&nodePath]( const std::string& key ) { + return std::string_view{ key } == nodePath; + } ); if ( found != mGitStatusFilesCache.end() ) return Variant( STYLE_MODIFIED ); return Variant( STYLE_NONE ); diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index cf47be24a..ba83cd041 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -1905,12 +1905,9 @@ void LSPClientPlugin::drawTop( UICodeEditor* editor, const Vector2f& screenStart Float fontSize = editor->getUISceneNode()->getUIThemeManager()->getDefaultFontSize(); - bool isPath = true; - std::string path( editor->getDocument().getFilePath() ); - if ( path.empty() ) { - path = editor->getDocument().getFilename(); - isPath = false; - } + bool isPath = !editor->getDocument().getFilePath().empty(); + std::string path( !isPath ? editor->getDocument().getFilename() + : editor->getDocument().getFilePath() ); Color textColor( editor->getColorScheme().getEditorColor( mHoveringBreadcrumb == editor ? SyntaxStyleTypes::Text : SyntaxStyleTypes::LineNumber2 ) );