mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-26 16:17:57 +03:00
Optimize UITableView and UITreeView by only allocating as many cells as needed to cover the viewport.
This commit is contained in:
@@ -108,6 +108,8 @@ class EE_API Node : public Transformable {
|
||||
|
||||
Node* setVisible( const bool& visible );
|
||||
|
||||
Node* setChildsVisibility( bool visible, bool emitEventNotification = true );
|
||||
|
||||
bool isVisible() const;
|
||||
|
||||
bool isHided() const;
|
||||
|
||||
@@ -183,7 +183,7 @@ class EE_API UIAbstractTableView : public UIAbstractView {
|
||||
virtual UITableRow* updateRow( const int& rowIndex, const ModelIndex& index,
|
||||
const Float& yOffset );
|
||||
|
||||
virtual UIWidget* updateCell( const int& rowIndex, const ModelIndex& index,
|
||||
virtual UIWidget* updateCell( const Vector2<Int64>& posIndex, const ModelIndex& index,
|
||||
const size_t& indentLevel, const Float& yOffset );
|
||||
|
||||
virtual UIWidget* createCell( UIWidget* rowWidget, const ModelIndex& index );
|
||||
|
||||
@@ -144,7 +144,7 @@ class EE_API UITreeView : public UIAbstractTableView {
|
||||
|
||||
virtual void onColumnSizeChange( const size_t& colIndex, bool fromUserInteraction = false );
|
||||
|
||||
virtual UIWidget* updateCell( const int& rowIndex, const ModelIndex& index,
|
||||
virtual UIWidget* updateCell( const Vector2<Int64>& posIndex, const ModelIndex& index,
|
||||
const size_t& indentLevel, const Float& yOffset );
|
||||
|
||||
virtual UIWidget* createCell( UIWidget* rowWidget, const ModelIndex& index );
|
||||
|
||||
@@ -181,6 +181,22 @@ Node* Node::setVisible( const bool& visible ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Node* Node::setChildsVisibility( bool visible, bool emitEventNotification ) {
|
||||
Node* child = mChild;
|
||||
if ( emitEventNotification ) {
|
||||
while ( child ) {
|
||||
child->setVisible( visible );
|
||||
child = child->mNext;
|
||||
}
|
||||
} else {
|
||||
while ( child ) {
|
||||
child->mVisible = visible;
|
||||
child = child->mNext;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
bool Node::isVisible() const {
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
@@ -577,21 +577,23 @@ UIWidget* UIAbstractTableView::setupCell( UITableCell* widget, UIWidget* rowWidg
|
||||
return widget;
|
||||
}
|
||||
|
||||
UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex& index,
|
||||
UIWidget* UIAbstractTableView::updateCell( const Vector2<Int64>& posIndex, const ModelIndex& index,
|
||||
const size_t&, const Float& yOffset ) {
|
||||
if ( rowIndex >= (int)mWidgets.size() )
|
||||
mWidgets.resize( rowIndex + 1 );
|
||||
auto* widget = mWidgets[rowIndex][index.column()];
|
||||
if ( posIndex.y >= (int)mWidgets.size() )
|
||||
mWidgets.resize( posIndex.y + 1 );
|
||||
auto* widget = mWidgets[posIndex.y][posIndex.x];
|
||||
if ( !widget ) {
|
||||
UIWidget* rowWidget = updateRow( rowIndex, index, yOffset );
|
||||
UIWidget* rowWidget = updateRow( posIndex.y, index, yOffset );
|
||||
widget = createCell( rowWidget, index );
|
||||
mWidgets[rowIndex][index.column()] = widget;
|
||||
mWidgets[posIndex.y][posIndex.x] = widget;
|
||||
widget->reloadStyle( true, true, true );
|
||||
}
|
||||
const auto& colData = columnData( index.column() );
|
||||
if ( !colData.visible ) {
|
||||
widget->setVisible( false );
|
||||
return widget;
|
||||
} else {
|
||||
widget->setVisible( true );
|
||||
}
|
||||
widget->setPixelsSize( colData.width, getRowHeight() );
|
||||
widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } );
|
||||
|
||||
@@ -355,21 +355,30 @@ bool UIScrollableWidget::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
Uint32 UIScrollableWidget::onMessage( const NodeMessage* Msg ) {
|
||||
switch ( Msg->getMsg() ) {
|
||||
case NodeMessage::MouseUp: {
|
||||
bool moved = false;
|
||||
if ( mVScroll->isEnabled() ) {
|
||||
|
||||
if ( Msg->getFlags() & EE_BUTTON_WUMASK ) {
|
||||
mVScroll->setValue( mVScroll->getValue() - mVScroll->getClickStep() );
|
||||
return 1;
|
||||
moved = true;
|
||||
} else if ( Msg->getFlags() & EE_BUTTON_WDMASK ) {
|
||||
mVScroll->setValue( mVScroll->getValue() + mVScroll->getClickStep() );
|
||||
return 1;
|
||||
} else if ( Msg->getFlags() & EE_BUTTON_WLMASK ) {
|
||||
mHScroll->setValue( mHScroll->getValue() - mHScroll->getClickStep() );
|
||||
return 1;
|
||||
} else if ( Msg->getFlags() & EE_BUTTON_WRMASK ) {
|
||||
mHScroll->setValue( mHScroll->getValue() + mHScroll->getClickStep() );
|
||||
return 1;
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mHScroll->isEnabled() ) {
|
||||
if ( Msg->getFlags() & EE_BUTTON_WLMASK ) {
|
||||
mHScroll->setValue( mHScroll->getValue() - mHScroll->getClickStep() );
|
||||
moved = true;
|
||||
} else if ( Msg->getFlags() & EE_BUTTON_WRMASK ) {
|
||||
mHScroll->setValue( mHScroll->getValue() + mHScroll->getClickStep() );
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( moved )
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return UIWidget::onMessage( Msg );
|
||||
|
||||
+74
-61
@@ -27,28 +27,48 @@ bool UITableView::isType( const Uint32& type ) const {
|
||||
}
|
||||
|
||||
void UITableView::drawChilds() {
|
||||
int realIndex = 0;
|
||||
int realRowIndex = 0;
|
||||
int realColIndex = 0;
|
||||
ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr );
|
||||
size_t start = mScrollOffset.y / getRowHeight();
|
||||
size_t end =
|
||||
eemin<size_t>( (size_t)eeceil( ( mScrollOffset.y + mSize.getHeight() ) / getRowHeight() ),
|
||||
getItemCount() );
|
||||
Float yOffset;
|
||||
for ( size_t i = start; i < end; i++ ) {
|
||||
yOffset = getHeaderHeight() + i * getRowHeight();
|
||||
ModelIndex index( getModel()->index( i ) );
|
||||
if ( yOffset - mScrollOffset.y > mSize.getHeight() )
|
||||
break;
|
||||
if ( yOffset - mScrollOffset.y + getRowHeight() < 0 )
|
||||
continue;
|
||||
for ( size_t colIndex = 0; colIndex < getModel()->columnCount(); colIndex++ ) {
|
||||
updateCell( realIndex, getModel()->index( index.row(), colIndex, index.parent() ), 0,
|
||||
yOffset );
|
||||
if ( getModel() ) {
|
||||
Float rowHeight = getRowHeight();
|
||||
size_t start = mScrollOffset.y / rowHeight;
|
||||
size_t end = eemin<size_t>(
|
||||
(size_t)eeceil( ( mScrollOffset.y + mSize.getHeight() ) / rowHeight ), getItemCount() );
|
||||
Float yOffset = 0;
|
||||
Float xOffset;
|
||||
auto colCount = getModel()->columnCount();
|
||||
auto headerHeight = getHeaderHeight();
|
||||
for ( size_t i = start; i < end; i++ ) {
|
||||
xOffset = mPaddingPx.Left;
|
||||
yOffset = headerHeight + i * rowHeight;
|
||||
ModelIndex rowIndex( getModel()->index( i ) );
|
||||
if ( yOffset - mScrollOffset.y > mSize.getHeight() )
|
||||
break;
|
||||
if ( yOffset - mScrollOffset.y + rowHeight < 0 )
|
||||
continue;
|
||||
UITableRow* rowNode = updateRow( realRowIndex, rowIndex, yOffset );
|
||||
rowNode->setChildsVisibility( false, false );
|
||||
realColIndex = 0;
|
||||
for ( size_t colIndex = 0; colIndex < colCount; colIndex++ ) {
|
||||
auto& colData = columnData( colIndex );
|
||||
if ( !colData.visible || ( xOffset + colData.width ) - mScrollOffset.x < 0 ) {
|
||||
if ( colData.visible )
|
||||
xOffset += colData.width;
|
||||
continue;
|
||||
}
|
||||
if ( xOffset - mScrollOffset.x > mSize.getWidth() )
|
||||
break;
|
||||
xOffset += colData.width;
|
||||
updateCell( { realColIndex, realRowIndex },
|
||||
getModel()->index( rowIndex.row(), colIndex, rowIndex.parent() ), 0,
|
||||
yOffset );
|
||||
realColIndex++;
|
||||
}
|
||||
rowNode->nodeDraw();
|
||||
realRowIndex++;
|
||||
}
|
||||
updateRow( realIndex, index, yOffset )->nodeDraw();
|
||||
realIndex++;
|
||||
}
|
||||
|
||||
if ( mHeader && mHeader->isVisible() )
|
||||
mHeader->nodeDraw();
|
||||
if ( mHScroll->isVisible() )
|
||||
@@ -61,49 +81,42 @@ Node* UITableView::overFind( const Vector2f& point ) {
|
||||
ScopedOp op( [this] { mUISceneNode->setIsLoading( true ); },
|
||||
[this] { mUISceneNode->setIsLoading( false ); } );
|
||||
Node* pOver = NULL;
|
||||
if ( mEnabled && mVisible ) {
|
||||
ConditionalLock l( getModel() != nullptr,
|
||||
getModel() ? &getModel()->resourceMutex() : nullptr );
|
||||
updateWorldPolygon();
|
||||
if ( mWorldBounds.contains( point ) && mPoly.pointInside( point ) ) {
|
||||
writeNodeFlag( NODE_FLAG_MOUSEOVER_ME_OR_CHILD, 1 );
|
||||
mSceneNode->addMouseOverNode( this );
|
||||
if ( mHScroll->isVisible() && ( pOver = mHScroll->overFind( point ) ) )
|
||||
return pOver;
|
||||
if ( mVScroll->isVisible() && ( pOver = mVScroll->overFind( point ) ) )
|
||||
return pOver;
|
||||
if ( mHeader && ( pOver = mHeader->overFind( point ) ) )
|
||||
return pOver;
|
||||
int realIndex = 0;
|
||||
Float yOffset;
|
||||
size_t start = mScrollOffset.y / getRowHeight();
|
||||
size_t end = eemin<size_t>(
|
||||
(size_t)eeceil( ( mScrollOffset.y + mSize.getHeight() ) / getRowHeight() ),
|
||||
getItemCount() );
|
||||
for ( size_t i = start; i < end; i++ ) {
|
||||
yOffset = getHeaderHeight() + i * getRowHeight();
|
||||
ModelIndex index( getModel()->index( i ) );
|
||||
if ( yOffset - mScrollOffset.y > mSize.getHeight() )
|
||||
break;
|
||||
if ( yOffset - mScrollOffset.y + getRowHeight() < 0 )
|
||||
continue;
|
||||
for ( size_t colIndex = 0; colIndex < getModel()->columnCount(); colIndex++ ) {
|
||||
if ( columnData( colIndex ).visible ) {
|
||||
updateCell( realIndex,
|
||||
getModel()->index( index.row(), colIndex, index.parent() ), 0,
|
||||
yOffset );
|
||||
}
|
||||
}
|
||||
pOver = updateRow( realIndex, index, yOffset )->overFind( point );
|
||||
if ( pOver )
|
||||
break;
|
||||
realIndex++;
|
||||
}
|
||||
if ( !pOver )
|
||||
pOver = this;
|
||||
if ( !mEnabled || !mVisible )
|
||||
return pOver;
|
||||
ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr );
|
||||
updateWorldPolygon();
|
||||
if ( mWorldBounds.contains( point ) && mPoly.pointInside( point ) ) {
|
||||
writeNodeFlag( NODE_FLAG_MOUSEOVER_ME_OR_CHILD, 1 );
|
||||
mSceneNode->addMouseOverNode( this );
|
||||
if ( mHScroll->isVisible() && ( pOver = mHScroll->overFind( point ) ) )
|
||||
return pOver;
|
||||
if ( mVScroll->isVisible() && ( pOver = mVScroll->overFind( point ) ) )
|
||||
return pOver;
|
||||
if ( mHeader && ( pOver = mHeader->overFind( point ) ) )
|
||||
return pOver;
|
||||
Float rowHeight = getRowHeight();
|
||||
Float headerHeight = getHeaderHeight();
|
||||
Float itemCount = getItemCount();
|
||||
int realIndex = 0;
|
||||
Float yOffset;
|
||||
size_t start = mScrollOffset.y / rowHeight;
|
||||
size_t end = eemin<size_t>(
|
||||
(size_t)eeceil( ( mScrollOffset.y + mSize.getHeight() ) / rowHeight ), itemCount );
|
||||
for ( size_t i = start; i < end; i++ ) {
|
||||
yOffset = headerHeight + i * rowHeight;
|
||||
ModelIndex index( getModel()->index( i ) );
|
||||
if ( yOffset - mScrollOffset.y > mSize.getHeight() )
|
||||
break;
|
||||
if ( yOffset - mScrollOffset.y + rowHeight < 0 )
|
||||
continue;
|
||||
pOver = updateRow( realIndex, index, yOffset )->overFind( point );
|
||||
if ( pOver )
|
||||
break;
|
||||
realIndex++;
|
||||
}
|
||||
if ( !pOver )
|
||||
pOver = this;
|
||||
}
|
||||
|
||||
return pOver;
|
||||
}
|
||||
|
||||
@@ -116,7 +129,7 @@ Float UITableView::getMaxColumnContentWidth( const size_t& colIndex, bool bestGu
|
||||
[this] { mUISceneNode->setIsLoading( false ); } );
|
||||
Float yOffset = getHeaderHeight();
|
||||
auto worstCaseFunc = [&]( const ModelIndex& index ) {
|
||||
UIWidget* widget = updateCell( index.row(), index, 0, yOffset );
|
||||
UIWidget* widget = updateCell( { (Int64)0, (Int64)0 }, index, 0, yOffset );
|
||||
if ( widget->isType( UI_TYPE_PUSHBUTTON ) ) {
|
||||
Float w = widget->asType<UIPushButton>()->getContentSize().getWidth();
|
||||
if ( w > lWidth )
|
||||
|
||||
+42
-24
@@ -215,21 +215,23 @@ UIWidget* UITreeView::createCell( UIWidget* rowWidget, const ModelIndex& index )
|
||||
return setupCell( widget, rowWidget, index );
|
||||
}
|
||||
|
||||
UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index,
|
||||
UIWidget* UITreeView::updateCell( const Vector2<Int64>& posIndex, const ModelIndex& index,
|
||||
const size_t& indentLevel, const Float& yOffset ) {
|
||||
if ( rowIndex >= (int)mWidgets.size() )
|
||||
mWidgets.resize( rowIndex + 1 );
|
||||
auto* widget = mWidgets[rowIndex][index.column()];
|
||||
if ( posIndex.y >= (int)mWidgets.size() )
|
||||
mWidgets.resize( posIndex.y + 1 );
|
||||
auto* widget = mWidgets[posIndex.y][index.column()];
|
||||
if ( !widget ) {
|
||||
UIWidget* rowWidget = updateRow( rowIndex, index, yOffset );
|
||||
UIWidget* rowWidget = updateRow( posIndex.y, index, yOffset );
|
||||
widget = createCell( rowWidget, index );
|
||||
mWidgets[rowIndex][index.column()] = widget;
|
||||
mWidgets[posIndex.y][index.column()] = widget;
|
||||
widget->reloadStyle( true, true, true );
|
||||
}
|
||||
const auto& colData = columnData( index.column() );
|
||||
if ( !colData.visible ) {
|
||||
widget->setVisible( false );
|
||||
return widget;
|
||||
} else {
|
||||
widget->setVisible( true );
|
||||
}
|
||||
widget->setPixelsSize( colData.width, getRowHeight() );
|
||||
widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } );
|
||||
@@ -346,33 +348,48 @@ Sizef UITreeView::getContentSize() const {
|
||||
}
|
||||
|
||||
void UITreeView::drawChilds() {
|
||||
int realIndex = 0;
|
||||
int realRowIndex = 0;
|
||||
int realColIndex = 0;
|
||||
Float rowHeight = getRowHeight();
|
||||
|
||||
traverseTree( [this, &realIndex, rowHeight]( const int&, const ModelIndex& index,
|
||||
const size_t& indentLevel, const Float& yOffset ) {
|
||||
traverseTree( [this, &realRowIndex, &realColIndex,
|
||||
rowHeight]( 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 )
|
||||
return IterationDecision::Continue;
|
||||
Float xOffset = mPaddingPx.Left;
|
||||
UITableRow* rowNode = updateRow( realRowIndex, index, yOffset );
|
||||
rowNode->setChildsVisibility( false, false );
|
||||
realColIndex = 0;
|
||||
for ( size_t colIndex = 0; colIndex < getModel()->columnCount(); colIndex++ ) {
|
||||
if ( columnData( colIndex ).visible ) {
|
||||
if ( (Int64)colIndex != index.column() ) {
|
||||
updateCell( realIndex,
|
||||
getModel()->index( index.row(), colIndex, index.parent() ),
|
||||
indentLevel, yOffset );
|
||||
} else {
|
||||
auto* cell = updateCell( realIndex, index, indentLevel, yOffset );
|
||||
auto& colData = columnData( colIndex );
|
||||
if ( !colData.visible || ( xOffset + colData.width ) - mScrollOffset.x < 0 ) {
|
||||
if ( colData.visible )
|
||||
xOffset += colData.width;
|
||||
continue;
|
||||
}
|
||||
if ( xOffset - mScrollOffset.x > mSize.getWidth() )
|
||||
break;
|
||||
xOffset += colData.width;
|
||||
if ( (Int64)colIndex != index.column() ) {
|
||||
updateCell( { realColIndex, realRowIndex },
|
||||
getModel()->index( index.row(), colIndex, index.parent() ), indentLevel,
|
||||
yOffset );
|
||||
} else {
|
||||
auto* cell =
|
||||
updateCell( { realColIndex, realRowIndex }, index, indentLevel, yOffset );
|
||||
|
||||
if ( mFocusSelectionDirty && index == getSelection().first() ) {
|
||||
cell->setFocus();
|
||||
mFocusSelectionDirty = false;
|
||||
}
|
||||
if ( mFocusSelectionDirty && index == getSelection().first() ) {
|
||||
cell->setFocus();
|
||||
mFocusSelectionDirty = false;
|
||||
}
|
||||
}
|
||||
realColIndex++;
|
||||
}
|
||||
updateRow( realIndex, index, yOffset )->nodeDraw();
|
||||
realIndex++;
|
||||
rowNode->nodeDraw();
|
||||
realRowIndex++;
|
||||
return IterationDecision::Continue;
|
||||
} );
|
||||
|
||||
@@ -511,8 +528,9 @@ Float UITreeView::getMaxColumnContentWidth( const size_t& colIndex, bool ) {
|
||||
[this] { mUISceneNode->setIsLoading( false ); } );
|
||||
traverseTree( [&, colIndex]( const int&, const ModelIndex& index, const size_t& indentLevel,
|
||||
const Float& yOffset ) {
|
||||
UIWidget* widget = updateCell(
|
||||
0, getModel()->index( index.row(), colIndex, index.parent() ), indentLevel, yOffset );
|
||||
UIWidget* widget = updateCell( { (Int64)0, (Int64)0 },
|
||||
getModel()->index( index.row(), colIndex, index.parent() ),
|
||||
indentLevel, yOffset );
|
||||
if ( widget->isType( UI_TYPE_PUSHBUTTON ) ) {
|
||||
Float w = widget->asType<UIPushButton>()->getContentSize().getWidth();
|
||||
if ( w > lWidth )
|
||||
|
||||
@@ -119,7 +119,9 @@ std::shared_ptr<Formula> FormulaParser::formula() {
|
||||
nextToken();
|
||||
double val = 0;
|
||||
String::fromString( val, n );
|
||||
return std::make_shared<Number>( val );
|
||||
if ( lookahead.token == TokenType::EPSILON )
|
||||
return std::make_shared<Number>( val );
|
||||
break;
|
||||
}
|
||||
case TokenType::EQUALS:
|
||||
nextToken();
|
||||
@@ -129,6 +131,7 @@ std::shared_ptr<Formula> FormulaParser::formula() {
|
||||
default:
|
||||
return std::make_shared<Textual>( formulaString );
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Formula> FormulaParser::parseFormula( std::string _formulaString ) {
|
||||
|
||||
@@ -86,6 +86,13 @@ GitPlugin::~GitPlugin() {
|
||||
{ Lock l( mGitStatusMutex ); }
|
||||
{ Lock l( mRepoMutex ); }
|
||||
{ Lock l( mReposMutex ); }
|
||||
|
||||
// TODO: Add a signal for this waits
|
||||
while ( mRunningUpdateStatus )
|
||||
Sys::sleep( 1.f );
|
||||
|
||||
while ( mRunningUpdateBranches )
|
||||
Sys::sleep( 1.f );
|
||||
}
|
||||
|
||||
void GitPlugin::load( PluginManager* pluginManager ) {
|
||||
|
||||
Reference in New Issue
Block a user