Optimization to reduce almost to zero allocations during frame rendering in ecode (this gives around 6% perf gains).

This commit is contained in:
Martín Lucas Golini
2024-10-29 02:11:33 -03:00
parent cac43d0276
commit 0e0ce71609
15 changed files with 337 additions and 203 deletions
+54
View File
@@ -899,6 +899,60 @@ class EE_API String {
String::View view() const;
// No allocation int to str
template <typename IntType, typename StrType>
static const StrType* intToStrBuf( IntType value, StrType* buffer, size_t bufferSize,
size_t padding, StrType padChar ) {
static_assert( std::is_integral<IntType>::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<IntType>::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 );
+2
View File
@@ -56,6 +56,8 @@ class EE_API ActionManager {
std::vector<Action*> mActionsRemoveList;
mutable Mutex mMutex;
std::atomic<bool> mUpdating;
void update( const Time& time, Action** actions, size_t count );
};
}} // namespace EE::Scene
@@ -196,6 +196,8 @@ class EE_API UIAbstractTableView : public UIAbstractView {
virtual UIWidget* updateCell( const Vector2<Int64>& 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,
+13 -2
View File
@@ -141,8 +141,6 @@ class EE_API UITreeView : public UIAbstractTableView {
const Float& )>
TreeViewCallback;
void traverseTree( TreeViewCallback ) const;
mutable std::unordered_map<void*, MetadataForIndex> 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
+4 -2
View File
@@ -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<std::string>& classes );
@@ -177,13 +179,13 @@ class EE_API UIWidget : public UINode {
UIWidget* removeClasses( const std::vector<std::string>& 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<std::string> getClasses() const;
const std::vector<std::string>& getClasses() const;
const std::string& getElementTag() const;
+27 -3
View File
@@ -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;
}
+41 -15
View File
@@ -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<Action*> removeList;
mUpdating = true;
// Actions can be added during action updates, we need to only iterate the current actions
std::vector<Action*> 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<Action*> actions;
{
Lock l( mMutex );
actions = mActions;
}
update( time, actions.data(), size );
}
}
std::size_t ActionManager::count() const {
Lock l( mMutex );
return mActions.size();
+1 -1
View File
@@ -1227,7 +1227,7 @@ void Node::clearEventListener() {
void Node::sendEvent( const Event* event ) {
if ( 0 != mEvents.count( event->getType() ) ) {
std::map<Uint32, EventCallback> eventMap = mEvents[event->getType()];
auto& eventMap = mEvents[event->getType()];
if ( eventMap.begin() != eventMap.end() ) {
std::map<Uint32, EventCallback>::iterator it;
for ( it = eventMap.begin(); it != eventMap.end(); ++it ) {
+54 -41
View File
@@ -582,47 +582,7 @@ UIWidget* UIAbstractTableView::updateCell( const Vector2<Int64>& posIndex, const
widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } );
if ( widget->isType( UI_TYPE_TABLECELL ) ) {
UITableCell* cell = widget->asType<UITableCell>();
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<Int64>& 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;
+56 -36
View File
@@ -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<int, String::StringBaseType>( eeabs( i - selection.start().line() ),
pos, 16, lineNumberDigits, ' ' );
} else {
pos = String( String::toString( i + 1 ) ).padLeft( lineNumberDigits, ' ' );
String::intToStrBuf<int, String::StringBaseType>( 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<Int64>( rangeEnd.visibleIndex ) ||
endidx < static_cast<Int64>( rangeStart.visibleIndex ) )
if ( v.minimapStartLine > static_cast<Int64>( rangeEnd.visibleIndex ) ||
v.endidx < static_cast<Int64>( rangeStart.visibleIndex ) )
continue;
if ( ranges.isSorted() && static_cast<Int64>( rangeStart.visibleIndex ) > endidx &&
static_cast<Int64>( rangeEnd.visibleIndex ) > endidx )
if ( ranges.isSorted() && static_cast<Int64>( rangeStart.visibleIndex ) > v.endidx &&
static_cast<Int64>( rangeEnd.visibleIndex ) > v.endidx )
break;
if ( lineSkip == static_cast<Int64>( rangeStart.visibleIndex ) )
continue;
auto selRects = getTextRangeRectangles(
range, { 0, rect.Top - minimapStartLine * lineSpacing }, {}, lineSpacing,
DocumentViewLineRange{ static_cast<VisibleIndex>( minimapStartLine ),
static_cast<VisibleIndex>( endidx ) } );
range, { 0, v.rect.Top - v.minimapStartLine * v.lineSpacing }, {}, v.lineSpacing,
DocumentViewLineRange{ static_cast<VisibleIndex>( v.minimapStartLine ),
static_cast<VisibleIndex>( 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 ) {
+49 -93
View File
@@ -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<Model*>( getModel() )->resourceMutex() );
auto& model = *getModel();
int indentLevel = 0;
Float yOffset = getHeaderHeight();
int rowIndex = -1;
Float rowHeight = getRowHeight();
std::function<IterationDecision( const ModelIndex& )> 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<Int64>& posIndex, const ModelInd
widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } );
if ( widget->isType( UI_TYPE_TABLECELL ) ) {
UITableCell* cell = widget->asType<UITableCell>();
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;
} );
+22 -2
View File
@@ -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<std::string>& classes ) {
if ( mClasses != classes ) {
mClasses = classes;
@@ -949,7 +969,7 @@ UIWidget* UIWidget::removeClasses( const std::vector<std::string>& 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<std::string> UIWidget::getClasses() const {
const std::vector<std::string>& UIWidget::getClasses() const {
return mClasses;
}
@@ -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,
+5 -2
View File
@@ -258,8 +258,11 @@ void GitPlugin::initModelStyler() {
auto model = static_cast<const FileSystemModel*>( index.model() );
auto node = static_cast<const FileSystemModel::Node*>( 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 );
@@ -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 ) );