From dce9f1c285f030ede1503a29032469bd63544fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 26 Jul 2020 14:55:08 -0300 Subject: [PATCH] Improvements and fixes for FileSystemModel, ProjectDirectoryTree, FileInfo and more. --- bin/assets/ui/breeze.css | 3 +- include/eepp/system/fileinfo.hpp | 2 + include/eepp/system/filesystem.hpp | 15 ++- include/eepp/ui/models/filesystemmodel.hpp | 29 +++- include/eepp/ui/uiscrollablewidget.hpp | 2 +- src/eepp/system/fileinfo.cpp | 4 + src/eepp/system/filesystem.cpp | 100 ++++++++------ src/eepp/ui/abstract/uiabstracttableview.cpp | 5 +- src/eepp/ui/models/filesystemmodel.cpp | 43 +++--- src/eepp/ui/uinode.cpp | 5 +- src/eepp/ui/uiscrollablewidget.cpp | 16 ++- src/eepp/ui/uitableview.cpp | 16 ++- src/eepp/ui/uitreeview.cpp | 10 +- src/tools/codeeditor/codeeditor.cpp | 124 +++++++++--------- src/tools/codeeditor/codeeditor.hpp | 2 + src/tools/codeeditor/projectdirectorytree.cpp | 18 ++- src/tools/codeeditor/projectdirectorytree.hpp | 6 +- 17 files changed, 243 insertions(+), 157 deletions(-) diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index 02e53a2f7..c3ae979d6 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -173,8 +173,7 @@ ListBox::item { background-position: left bottom, right bottom; } -ListBox:hover, -Table::hover { +ListBox:hover { border-color: var(--primary); } diff --git a/include/eepp/system/fileinfo.hpp b/include/eepp/system/fileinfo.hpp index 903718e97..fe81d345f 100644 --- a/include/eepp/system/fileinfo.hpp +++ b/include/eepp/system/fileinfo.hpp @@ -40,6 +40,8 @@ class EE_API FileInfo { bool isLink() const; + bool isHidden() const; + std::string linksTo() const; bool exists() const; diff --git a/include/eepp/system/filesystem.hpp b/include/eepp/system/filesystem.hpp index cf607de51..44edc4d60 100644 --- a/include/eepp/system/filesystem.hpp +++ b/include/eepp/system/filesystem.hpp @@ -72,6 +72,10 @@ class EE_API FileSystem { /** @return If a file path is writeable */ static bool fileCanWrite( const std::string& filepath ); + /** @return If the file is hidden (hidden attribute in Windows, files starting with '.' in other + * systems */ + static bool fileIsHidden( const std::string& filepath ); + /** If the directory path not end with a slash, it will add it. */ static void dirAddSlashAtEnd( std::string& path ); @@ -84,16 +88,19 @@ class EE_API FileSystem { /** @return The files and sub directories contained by a directory */ static std::vector filesGetInPath( const std::string& path, const bool& sortByName = false, - const bool& foldersFirst = false ); + const bool& foldersFirst = false, + const bool& ignoreHidden = false ); /** @return The files and sub directories contained by a directory */ static std::vector filesGetInPath( const String& path, const bool& sortByName = false, - const bool& foldersFirst = false ); + const bool& foldersFirst = false, + const bool& ignoreHidden = false ); /** @return The file info of the files and sub directories contained in the directory path. */ - static std::vector filesInfoGetInPath( std::string path, + static std::vector filesInfoGetInPath( std::string path, bool linkInfo = false, const bool& sortByName = false, - const bool& foldersFirst = false ); + const bool& foldersFirst = false, + const bool& ignoreHidden = false ); /** @return The size of a file */ static Uint64 fileSize( const std::string& Filepath ); diff --git a/include/eepp/ui/models/filesystemmodel.hpp b/include/eepp/ui/models/filesystemmodel.hpp index 600eefdb6..d7ac53380 100644 --- a/include/eepp/ui/models/filesystemmodel.hpp +++ b/include/eepp/ui/models/filesystemmodel.hpp @@ -11,6 +11,20 @@ class EE_API FileSystemModel : public Model { public: enum class Mode { DirectoriesOnly, FilesAndDirectories }; + struct DisplayConfig { + DisplayConfig() {} + DisplayConfig( bool sortByName, bool foldersFirst, bool ignoreHidden ) : + sortByName( sortByName ), foldersFirst( foldersFirst ), ignoreHidden( ignoreHidden ) {} + bool sortByName{true}; + bool foldersFirst{true}; + bool ignoreHidden{false}; + bool operator==( const DisplayConfig& other ) { + return sortByName == other.sortByName && foldersFirst == other.foldersFirst && + ignoreHidden == other.ignoreHidden; + } + bool operator!=( const DisplayConfig& other ) { return !( *this == other ); } + }; + enum Column { Icon = 0, Name, @@ -58,8 +72,9 @@ class EE_API FileSystemModel : public Model { bool fetchData( const String& fullPath ); }; - static std::shared_ptr New( const std::string& rootPath, - const Mode& mode = Mode::FilesAndDirectories ); + static std::shared_ptr + New( const std::string& rootPath, const Mode& mode = Mode::FilesAndDirectories, + const DisplayConfig displayConfig = DisplayConfig() ); const Mode& getMode() const { return mMode; } @@ -85,22 +100,22 @@ class EE_API FileSystemModel : public Model { void setMode( const Mode& mode ); - void updateNodeSelection( const ModelIndex& index, const bool selected ); + const DisplayConfig& getDisplayConfig() const; - ModelIndex getPreviouslySelectedIndex() const; - - void setPreviouslySelectedIndex( const ModelIndex& previouslySelectedIndex ); + void setDisplayConfig( const DisplayConfig& displayConfig ); protected: std::string mRootPath; std::unique_ptr mRoot{nullptr}; Mode mMode{Mode::FilesAndDirectories}; + DisplayConfig mDisplayConfig; ModelIndex mPreviouslySelectedIndex{}; Node& nodeRef( const ModelIndex& index ) const; - FileSystemModel( const std::string& rootPath, const Mode& mode ); + FileSystemModel( const std::string& rootPath, const Mode& mode, + const DisplayConfig displayConfig ); }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/uiscrollablewidget.hpp b/include/eepp/ui/uiscrollablewidget.hpp index 399bbfb3d..84adf61cd 100644 --- a/include/eepp/ui/uiscrollablewidget.hpp +++ b/include/eepp/ui/uiscrollablewidget.hpp @@ -42,7 +42,7 @@ class EE_API UIScrollableWidget : public UIWidget { void scrollToBottom(); - void scrollToPosition( const Vector2f& pos, const bool& scrollVertically = true, + void scrollToPosition( const Rectf& pos, const bool& scrollVertically = true, const bool& scrollHorizontally = false ); Sizef getScrollableArea() const; diff --git a/src/eepp/system/fileinfo.cpp b/src/eepp/system/fileinfo.cpp index 6bae8532f..320b9e72a 100644 --- a/src/eepp/system/fileinfo.cpp +++ b/src/eepp/system/fileinfo.cpp @@ -203,6 +203,10 @@ bool FileInfo::isLink() const { #endif } +bool FileInfo::isHidden() const { + return FileSystem::fileIsHidden( mFilepath ); +} + std::string FileInfo::linksTo() const { #if EE_PLATFORM != EE_PLATFORM_WIN if ( isLink() ) { diff --git a/src/eepp/system/filesystem.cpp b/src/eepp/system/filesystem.cpp index 54315c721..b95eae2ee 100644 --- a/src/eepp/system/filesystem.cpp +++ b/src/eepp/system/filesystem.cpp @@ -214,6 +214,20 @@ bool FileSystem::fileCanWrite( const std::string& filepath ) { #endif } +bool FileSystem::fileIsHidden( const std::string& filepath ) { +#if EE_PLATFORM == EE_PLATFORM_WIN +#if UNICODE + return 0 == ( GetFileAttributes( String::fromUtf8( filepath ).toWideString().c_str() ) & + FILE_ATTRIBUTE_HIDDEN ); +#else + return 0 == ( GetFileAttributes( (LPCTSTR)filepath.c_str() ) & FILE_ATTRIBUTE_HIDDEN ); +#endif +#else + std::string filename( fileNameFromPath( filepath ) ); + return filename.empty() ? false : filename[0] == '.'; +#endif +} + void FileSystem::dirAddSlashAtEnd( std::string& path ) { if ( path.size() && path[path.size() - 1] != '/' && path[path.size() - 1] != '\\' ) path += getOSSlash(); @@ -310,7 +324,8 @@ std::string FileSystem::getRealPath( const std::string& path ) { } std::vector FileSystem::filesGetInPath( const String& path, const bool& sortByName, - const bool& foldersFirst ) { + const bool& foldersFirst, + const bool& ignoreHidden ) { std::vector files; #ifdef EE_COMPILER_MSVC @@ -395,19 +410,16 @@ std::vector FileSystem::filesGetInPath( const String& path, const bool& closedir( dp ); #endif - if ( sortByName == true ) { + if ( sortByName ) { std::sort( files.begin(), files.end() ); } - if ( foldersFirst == true ) { + if ( foldersFirst ) { String fpath( path ); - if ( fpath[fpath.size() - 1] != '/' && fpath[fpath.size() - 1] != '\\' ) fpath += getOSSlash(); - - std::list folders; - std::list file; - + std::vector folders; + std::vector file; for ( size_t i = 0; i < files.size(); i++ ) { if ( FileSystem::isDirectory( fpath + files[i] ) ) { folders.push_back( files[i] ); @@ -415,34 +427,43 @@ std::vector FileSystem::filesGetInPath( const String& path, const bool& file.push_back( files[i] ); } } - files.clear(); + for ( auto& folder : folders ) + files.push_back( folder ); + for ( auto& f : file ) + files.push_back( f ); + } - std::list::iterator it; - - for ( it = folders.begin(); it != folders.end(); ++it ) - files.push_back( *it ); - - for ( it = file.begin(); it != file.end(); ++it ) - files.push_back( *it ); + if ( ignoreHidden ) { + String fpath( path ); + if ( fpath[fpath.size() - 1] != '/' && fpath[fpath.size() - 1] != '\\' ) + fpath += getOSSlash(); + std::vector filtered; + for ( size_t i = 0; i < files.size(); i++ ) + if ( !FileSystem::fileIsHidden( fpath + files[i] ) ) + filtered.push_back( files[i] ); + return filtered; } return files; } -std::vector FileSystem::filesInfoGetInPath( std::string path, const bool& sortByName, - const bool& foldersFirst ) { +std::vector FileSystem::filesInfoGetInPath( std::string path, bool linkInfo, + const bool& sortByName, + const bool& foldersFirst, + const bool& ignoreHidden ) { dirAddSlashAtEnd( path ); std::vector fileInfo; - auto files = filesGetInPath( path, sortByName, foldersFirst ); + auto files = filesGetInPath( path, sortByName, foldersFirst, ignoreHidden ); for ( auto file : files ) - fileInfo.emplace_back( FileInfo( path + file ) ); + fileInfo.emplace_back( FileInfo( path + file, linkInfo ) ); return fileInfo; } std::vector FileSystem::filesGetInPath( const std::string& path, const bool& sortByName, - const bool& foldersFirst ) { + const bool& foldersFirst, + const bool& ignoreHidden ) { std::vector files; #ifdef EE_COMPILER_MSVC @@ -516,19 +537,15 @@ std::vector FileSystem::filesGetInPath( const std::string& path, closedir( dp ); #endif - if ( sortByName == true ) { + if ( sortByName ) { std::sort( files.begin(), files.end() ); } - if ( foldersFirst == true ) { - String fpath( path ); - - if ( fpath[fpath.size() - 1] != '/' && fpath[fpath.size() - 1] != '\\' ) - fpath += getOSSlash(); - - std::list folders; - std::list file; - + if ( foldersFirst ) { + std::string fpath( path ); + dirAddSlashAtEnd( fpath ); + std::vector folders; + std::vector file; for ( size_t i = 0; i < files.size(); i++ ) { if ( FileSystem::isDirectory( fpath + files[i] ) ) { folders.push_back( files[i] ); @@ -536,16 +553,21 @@ std::vector FileSystem::filesGetInPath( const std::string& path, file.push_back( files[i] ); } } - files.clear(); + for ( auto& folder : folders ) + files.push_back( folder ); + for ( auto& f : file ) + files.push_back( f ); + } - std::list::iterator it; - - for ( it = folders.begin(); it != folders.end(); ++it ) - files.push_back( *it ); - - for ( it = file.begin(); it != file.end(); ++it ) - files.push_back( *it ); + if ( ignoreHidden ) { + std::string fpath( path ); + dirAddSlashAtEnd( fpath ); + std::vector filtered; + for ( size_t i = 0; i < files.size(); i++ ) + if ( !FileSystem::fileIsHidden( fpath + files[i] ) ) + filtered.push_back( files[i] ); + return filtered; } return files; diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 54e15eff6..6de41efa9 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -303,7 +303,6 @@ UITableRow* UIAbstractTableView::updateRow( const int& rowIndex, const ModelInde void UIAbstractTableView::onScrollChange() { mHeader->setPixelsPosition( -mScrollOffset.x, 0 ); - invalidateDraw(); } UIWidget* UIAbstractTableView::createCell( UIWidget* rowWidget, const ModelIndex& ) { @@ -336,7 +335,6 @@ UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex } widget->setPixelsSize( columnData( index.column() ).width, getRowHeight() ); widget->setPixelsPosition( {getColumnPosition( index.column() ).x, 0} ); - if ( widget->isType( UI_TYPE_PUSHBUTTON ) ) { UIPushButton* pushButton = widget->asType(); @@ -373,7 +371,8 @@ void UIAbstractTableView::moveSelection( int steps ) { } if ( model.isValid( newIndex ) ) { getSelection().set( newIndex ); - scrollToPosition( {mScrollOffset.x, getHeaderHeight() + newIndex.row() * getRowHeight()} ); + scrollToPosition( {{mScrollOffset.x, getHeaderHeight() + newIndex.row() * getRowHeight()}, + {columnData( newIndex.column() ).width, getRowHeight()}} ); } } diff --git a/src/eepp/ui/models/filesystemmodel.cpp b/src/eepp/ui/models/filesystemmodel.cpp index 64fb59a7c..6a1507e3c 100644 --- a/src/eepp/ui/models/filesystemmodel.cpp +++ b/src/eepp/ui/models/filesystemmodel.cpp @@ -50,7 +50,9 @@ void FileSystemModel::Node::traverseIfNeeded( const FileSystemModel& model ) { return; mHasTraversed = true; - auto files = FileSystem::filesInfoGetInPath( mInfo.getFilepath(), true, true ); + auto files = FileSystem::filesInfoGetInPath( + mInfo.getFilepath(), true, model.getDisplayConfig().sortByName, + model.getDisplayConfig().foldersFirst, model.getDisplayConfig().ignoreHidden ); for ( auto file : files ) { if ( ( model.getMode() == Mode::DirectoriesOnly && file.isDirectory() ) || @@ -74,12 +76,14 @@ bool FileSystemModel::Node::fetchData( const String& fullPath ) { } std::shared_ptr FileSystemModel::New( const std::string& rootPath, - const FileSystemModel::Mode& mode ) { - return std::shared_ptr( new FileSystemModel( rootPath, mode ) ); + const FileSystemModel::Mode& mode, + const DisplayConfig displayConfig ) { + return std::shared_ptr( new FileSystemModel( rootPath, mode, displayConfig ) ); } -FileSystemModel::FileSystemModel( const std::string& rootPath, const FileSystemModel::Mode& mode ) : - mRootPath( rootPath ), mMode( mode ) { +FileSystemModel::FileSystemModel( const std::string& rootPath, const FileSystemModel::Mode& mode, + const DisplayConfig displayConfig ) : + mRootPath( rootPath ), mMode( mode ), mDisplayConfig( displayConfig ) { update(); } @@ -199,10 +203,10 @@ Variant FileSystemModel::data( const ModelIndex& index, Model::Role role ) const return node.info().getModificationTime(); case Column::Inode: return node.info().getInode(); - case Column::SymlinkTarget: - return Variant( node.info().linksTo() ); case Column::Path: return Variant( node.info().getFilepath().c_str() ); + case Column::SymlinkTarget: + return node.info().isLink() ? Variant( node.info().linksTo() ) : Variant( "" ); default: eeASSERT( false ); } @@ -211,7 +215,7 @@ Variant FileSystemModel::data( const ModelIndex& index, Model::Role role ) const if ( role == Role::Display ) { switch ( index.column() ) { case Column::Icon: - return !node.getMimeType().empty() ? Variant( iconFor( node, index ) ) : Variant(); + return iconFor( node, index ); case Column::Name: return Variant( node.getName().c_str() ); case Column::Size: @@ -226,10 +230,10 @@ Variant FileSystemModel::data( const ModelIndex& index, Model::Role role ) const return Variant( timestampString( node.info().getModificationTime() ) ); case Column::Inode: return Variant( String::toString( node.info().getInode() ) ); - case Column::SymlinkTarget: - return node.info().isLink() ? Variant( node.info().linksTo() ) : Variant(); case Column::Path: return Variant( node.info().getFilepath().c_str() ); + case Column::SymlinkTarget: + return node.info().isLink() ? Variant( node.info().linksTo() ) : Variant( "" ); } } @@ -261,7 +265,7 @@ ModelIndex FileSystemModel::index( int row, int column, const ModelIndex& parent } Drawable* FileSystemModel::iconFor( const Node& node, const ModelIndex& index ) const { - if ( index.column() == (Int64)treeColumn() ) { + if ( index.column() == (Int64)treeColumn() || Column::Icon == index.column() ) { auto* scene = SceneManager::instance()->getUISceneNode(); Drawable* d = scene->findIcon( node.getMimeType() ); if ( !d ) { @@ -283,18 +287,15 @@ void FileSystemModel::setMode( const Mode& mode ) { } } -void FileSystemModel::updateNodeSelection( const ModelIndex& index, const bool selected ) { - Node& node = const_cast( this->node( index ) ); - node.setSelected( selected ); - setPreviouslySelectedIndex( index ); +const FileSystemModel::DisplayConfig& FileSystemModel::getDisplayConfig() const { + return mDisplayConfig; } -ModelIndex FileSystemModel::getPreviouslySelectedIndex() const { - return mPreviouslySelectedIndex; -} - -void FileSystemModel::setPreviouslySelectedIndex( const ModelIndex& previouslySelectedIndex ) { - mPreviouslySelectedIndex = previouslySelectedIndex; +void FileSystemModel::setDisplayConfig( const DisplayConfig& displayConfig ) { + if ( mDisplayConfig != displayConfig ) { + mDisplayConfig = displayConfig; + reload(); + } } }}} // namespace EE::UI::Models diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 8f7c809cc..545e9ce58 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -343,8 +343,9 @@ void UINode::updateDebugData() { text += "Classes: " + String::join( widget->getStyleSheetClasses(), ' ' ) + "\n"; } - text += String::format( "X: %.2f Y: %.2f\nW: %.2f (%.2f) H: %.2f (%.2f)", mSize.x, mDpPos.x, - mSize.y, mDpPos.y, mDpSize.x, mDpSize.y ); + text += String::format( + "X: %.2fpx (%.2fdp) Y: %.2fpx (%.2fdp)\nW: %.2fpx (%.2fdp) H: %.2fpx (%.2fdp)", + mPosition.x, mDpPos.x, mPosition.y, mDpPos.y, mSize.x, mDpSize.y, mSize.y, mDpSize.y ); if ( widget->getPadding() != Rectf( 0, 0, 0, 0 ) ) { Rectf p( widget->getPadding() ); diff --git a/src/eepp/ui/uiscrollablewidget.cpp b/src/eepp/ui/uiscrollablewidget.cpp index 424c0e1ef..946a493f3 100644 --- a/src/eepp/ui/uiscrollablewidget.cpp +++ b/src/eepp/ui/uiscrollablewidget.cpp @@ -242,21 +242,27 @@ void UIScrollableWidget::scrollToBottom() { mVScroll->setValue( 1 ); } -void UIScrollableWidget::scrollToPosition( const Vector2f& pos, const bool& scrollVertically, +void UIScrollableWidget::scrollToPosition( const Rectf& pos, const bool& scrollVertically, const bool& scrollHorizontally ) { Rectf visibleRect( getVisibleRect() ); if ( visibleRect.contains( pos ) ) return; if ( scrollVertically ) { - if ( pos.y < visibleRect.Top || pos.y > visibleRect.Bottom ) { - mVScroll->setValue( pos.y / getContentSize().y ); + if ( pos.getPosition().y <= visibleRect.Top ) { + mVScroll->setValue( pos.getPosition().y / getContentSize().y ); + } else if ( pos.getPosition().y + pos.getSize().getHeight() >= visibleRect.Bottom ) { + mVScroll->setValue( ( pos.getPosition().y + pos.getSize().getHeight() ) / + getContentSize().y ); } } if ( scrollHorizontally ) { - if ( pos.x < visibleRect.Left || pos.x > visibleRect.Right ) { - mHScroll->setValue( pos.x / getContentSize().x ); + if ( pos.getPosition().x <= visibleRect.Left ) { + mHScroll->setValue( pos.getPosition().x / getContentSize().x ); + } else if ( pos.getPosition().x + pos.getSize().getWidth() >= visibleRect.Right ) { + mHScroll->setValue( ( pos.getPosition().x + pos.getSize().getWidth() ) / + getContentSize().x ); } } } diff --git a/src/eepp/ui/uitableview.cpp b/src/eepp/ui/uitableview.cpp index 2c662f1b8..fe315892a 100644 --- a/src/eepp/ui/uitableview.cpp +++ b/src/eepp/ui/uitableview.cpp @@ -149,11 +149,21 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) { switch ( event.getKeyCode() ) { case KEY_PAGEUP: { - moveSelection( -pageSize ); + if ( curIndex.row() - pageSize < 0 ) { + getSelection().set( getModel()->index( 0, 0 ) ); + scrollToTop(); + } else { + moveSelection( -pageSize ); + } break; } case KEY_PAGEDOWN: { - moveSelection( pageSize ); + if ( curIndex.row() + pageSize >= (Int64)getModel()->rowCount() ) { + getSelection().set( getModel()->index( getItemCount() - 1 ) ); + scrollToBottom(); + } else { + moveSelection( pageSize ); + } break; } case KEY_UP: { @@ -175,7 +185,7 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) { break; } case KEY_RETURN: - case KEY_SPACE: { + case KEY_KP_ENTER: { if ( curIndex.isValid() ) onOpenModelIndex( curIndex ); break; diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 431c15162..14eb4d28d 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -14,6 +14,7 @@ UITreeView* UITreeView::New() { UITreeView::UITreeView() : UIAbstractTableView( "treeview" ), mIndentWidth( PixelDensity::dpToPx( 12 ) ) { + clipEnable(); mExpandIcon = getUISceneNode()->findIcon( "tree-expanded" ); mContractIcon = getUISceneNode()->findIcon( "tree-contracted" ); } @@ -81,8 +82,8 @@ template void UITreeView::traverseTree( Callback callback ) void UITreeView::createOrUpdateColumns() { if ( !getModel() ) return; - UIAbstractTableView::createOrUpdateColumns(); updateContentSize(); + UIAbstractTableView::createOrUpdateColumns(); } size_t UITreeView::getItemCount() const { @@ -460,7 +461,9 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { } ); curY = deque.front().second - getHeaderHeight(); getSelection().set( deque.front().first ); - scrollToPosition( {mScrollOffset.x, curY} ); + scrollToPosition( + {{mScrollOffset.x, curY}, + {columnData( deque.front().first.column() ).width, getRowHeight()}} ); break; } case KEY_PAGEDOWN: { @@ -495,7 +498,8 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { } curY += getRowHeight(); getSelection().set( foundIndex ); - scrollToPosition( {mScrollOffset.x, curY} ); + scrollToPosition( {{mScrollOffset.x, curY}, + {columnData( foundIndex.column() ).width, getRowHeight()}} ); break; } case KEY_UP: { diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index dace65553..ddf926b48 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -434,7 +434,7 @@ void App::showLocateBar() { mLocateBarLayout->setVisible( true ); mLocateInput->setFocus(); mLocateTable->setVisible( true ); - if ( !mLocateTable->getModel() ) { + if ( mDirTree && !mLocateTable->getModel() ) { mLocateTable->setModel( mDirTree->asModel( MAX_RESULT_ITEMS ) ); mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) ); } @@ -1456,6 +1456,69 @@ void App::updateEditorState() { } } +void App::loadDirTree( const std::string& path ) { + Clock* clock = eeNew( Clock, () ); + mDirTree = std::make_unique( path, mThreadPool ); + eePRINTL( "Loading DirTree: %s", path.c_str() ); + mDirTree->scan( + [&, clock]( ProjectDirectoryTree& dirTree ) { + eePRINTL( "DirTree read in: %.2fms. Found %ld files.", + clock->getElapsedTime().asMilliseconds(), dirTree.getFilesCount() ); + eeDelete( clock ); + mDirTreeReady = true; + }, + SyntaxDefinitionManager::instance()->getExtensionsPatternsSupported() ); +} + +void App::initProjectTreeView( const std::string& path ) { + mProjectTreeView = mUISceneNode->find( "project_view" ); + mProjectTreeView->setColumnsHidden( + {FileSystemModel::Icon, FileSystemModel::Size, FileSystemModel::Group, + FileSystemModel::Inode, FileSystemModel::Owner, FileSystemModel::SymlinkTarget, + FileSystemModel::Permissions, FileSystemModel::ModificationTime, FileSystemModel::Path}, + true ); + mProjectTreeView->setHeadersVisible( false ); + mProjectTreeView->setExpandersAsIcons( true ); + mProjectTreeView->addEventListener( Event::OnModelEvent, [&]( const Event* event ) { + const ModelEvent* modelEvent = static_cast( event ); + if ( modelEvent->getModelEventType() == ModelEventType::Open ) { + Variant vPath( + modelEvent->getModel()->data( modelEvent->getModelIndex(), Model::Role::Custom ) ); + if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { + std::string path( vPath.asCStr() ); + UITab* tab = mEditorSplitter->isDocumentOpen( path ); + if ( !tab ) { + FileInfo fileInfo( path ); + if ( fileInfo.exists() && fileInfo.isRegularFile() ) + mEditorSplitter->loadFileFromPathInNewTab( path ); + } else { + tab->getTabWidget()->setTabSelected( tab ); + } + } + } + } ); + + if ( !path.empty() && FileSystem::fileExists( path ) ) { + if ( FileSystem::isDirectory( path ) ) { + loadDirTree( FileSystem::getRealPath( path ) ); + mProjectTreeView->setModel( FileSystemModel::New( + path, FileSystemModel::Mode::FilesAndDirectories, {true, true, true} ) ); + } else { + std::string rpath( FileSystem::getRealPath( path ) ); + mProjectTreeView->setModel( FileSystemModel::New( + FileSystem::fileRemoveFileName( rpath ), FileSystemModel::Mode::FilesAndDirectories, + {true, true, true} ) ); + mEditorSplitter->loadFileFromPath( rpath ); + } + } else { + loadDirTree( FileSystem::getRealPath( "." ) ); + mProjectTreeView->setModel( FileSystemModel::New( + ".", FileSystemModel::Mode::FilesAndDirectories, {true, true, true} ) ); + } + + mProjectTreeView->setAutoExpandOnSingleColumn( true ); +} + void App::init( const std::string& file, const Float& pidelDensity ) { DisplayManager* displayManager = Engine::instance()->getDisplayManager(); Display* currentDisplay = displayManager->getDisplayIndex( 0 ); @@ -1713,69 +1776,12 @@ void App::init( const std::string& file, const Float& pidelDensity ) { mConsole = eeNew( Console, ( fontMono, true, true, 1024 * 1000, 0, mWindow ) ); - mProjectTreeView = mUISceneNode->find( "project_view" ); - mProjectTreeView->setColumnsHidden( - {FileSystemModel::Icon, FileSystemModel::Size, FileSystemModel::Group, - FileSystemModel::Inode, FileSystemModel::Owner, FileSystemModel::SymlinkTarget, - FileSystemModel::Permissions, FileSystemModel::ModificationTime, - FileSystemModel::Path}, - true ); - mProjectTreeView->setHeadersVisible( false ); - mProjectTreeView->setExpandersAsIcons( true ); - mProjectTreeView->addEventListener( Event::OnModelEvent, [&]( const Event* event ) { - const ModelEvent* modelEvent = static_cast( event ); - if ( modelEvent->getModelEventType() == ModelEventType::Open ) { - Variant vPath( modelEvent->getModel()->data( modelEvent->getModelIndex(), - Model::Role::Custom ) ); - if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { - std::string path( vPath.asCStr() ); - UITab* tab = mEditorSplitter->isDocumentOpen( path ); - if ( !tab ) { - FileInfo fileInfo( path ); - if ( fileInfo.exists() && fileInfo.isRegularFile() ) - mEditorSplitter->loadFileFromPathInNewTab( path ); - } else { - tab->getTabWidget()->setTabSelected( tab ); - } - } - } - } ); - - if ( !file.empty() && FileSystem::fileExists( file ) ) { - if ( FileSystem::isDirectory( file ) ) { - loadDirTree( FileSystem::getRealPath( file ) ); - mProjectTreeView->setModel( FileSystemModel::New( file ) ); - } else { - std::string rpath( FileSystem::getRealPath( file ) ); - mProjectTreeView->setModel( - FileSystemModel::New( FileSystem::fileRemoveFileName( rpath ) ) ); - mEditorSplitter->loadFileFromPath( rpath ); - } - } else { - loadDirTree( FileSystem::getRealPath( "." ) ); - mProjectTreeView->setModel( FileSystemModel::New( "." ) ); - } - - mProjectTreeView->setAutoExpandOnSingleColumn( true ); + initProjectTreeView( file ); mWindow->runMainLoop( &appLoop ); } } -void App::loadDirTree( const std::string& path ) { - Clock* clock = eeNew( Clock, () ); - mDirTree = std::make_unique( path, mThreadPool ); - eePRINTL( "Loading DirTree: %s", path.c_str() ); - mDirTree->scan( - [&, clock]( ProjectDirectoryTree& dirTree ) { - eePRINTL( "DirTree read in: %.2fms. Found %ld files.", - clock->getElapsedTime().asMilliseconds(), dirTree.getFilesCount() ); - eeDelete( clock ); - mDirTreeReady = true; - }, - SyntaxDefinitionManager::instance()->getExtensionsPatternsSupported() ); -} - EE_MAIN_FUNC int main( int argc, char* argv[] ) { args::ArgumentParser parser( "ecode" ); args::HelpFlag help( parser, "help", "Display this help menu", {'h', "help"} ); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index 416d7e662..cee72c307 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -209,6 +209,8 @@ class App : public UICodeEditorSplitter::Client { void initLocateBar(); + void initProjectTreeView( const std::string& path ); + void loadDirTree( const std::string& path ); void showSidePanel( bool show ); diff --git a/src/tools/codeeditor/projectdirectorytree.cpp b/src/tools/codeeditor/projectdirectorytree.cpp index 772338985..e85c5847a 100644 --- a/src/tools/codeeditor/projectdirectorytree.cpp +++ b/src/tools/codeeditor/projectdirectorytree.cpp @@ -9,7 +9,8 @@ ProjectDirectoryTree::ProjectDirectoryTree( const std::string& path, } void ProjectDirectoryTree::scan( const ProjectDirectoryTree::ScanCompleteEvent& scanComplete, - const std::vector& acceptedPattern ) { + const std::vector& acceptedPattern, + const bool& ignoreHidden ) { #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN mPool->run( [&, acceptedPattern] { @@ -22,7 +23,7 @@ void ProjectDirectoryTree::scan( const ProjectDirectoryTree::ScanCompleteEvent& for ( auto& strPattern : acceptedPattern ) patterns.emplace_back( LuaPattern( strPattern ) ); std::set info; - getDirectoryFiles( files, names, mPath, info ); + getDirectoryFiles( files, names, mPath, info, ignoreHidden ); size_t namesCount = names.size(); bool found; for ( size_t i = 0; i < namesCount; i++ ) { @@ -40,7 +41,7 @@ void ProjectDirectoryTree::scan( const ProjectDirectoryTree::ScanCompleteEvent& } } else { std::set info; - getDirectoryFiles( mFiles, mNames, mPath, info ); + getDirectoryFiles( mFiles, mNames, mPath, info, ignoreHidden ); } mIsReady = true; #if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN @@ -93,6 +94,9 @@ std::shared_ptr ProjectDirectoryTree::matchTree( const std::strin } std::shared_ptr ProjectDirectoryTree::asModel( const size_t& max ) const { + if ( mNames.empty() ) + return std::make_shared( std::vector(), + std::vector() ); size_t rmax = eemin( mNames.size(), max ); std::vector files( rmax ); std::vector names( rmax ); @@ -110,9 +114,11 @@ size_t ProjectDirectoryTree::getFilesCount() const { void ProjectDirectoryTree::getDirectoryFiles( std::vector& files, std::vector& names, std::string directory, - std::set currentDirs ) { + std::set currentDirs, + const bool& ignoreHidden ) { currentDirs.insert( directory ); - std::vector pathFiles = FileSystem::filesGetInPath( directory ); + std::vector pathFiles = + FileSystem::filesGetInPath( directory, false, false, ignoreHidden ); for ( auto& file : pathFiles ) { std::string fullpath( directory + file ); if ( FileSystem::isDirectory( fullpath ) ) { @@ -124,7 +130,7 @@ void ProjectDirectoryTree::getDirectoryFiles( std::vector& files, if ( currentDirs.find( fullpath ) == currentDirs.end() ) continue; } - getDirectoryFiles( files, names, fullpath, currentDirs ); + getDirectoryFiles( files, names, fullpath, currentDirs, ignoreHidden ); } else { files.emplace_back( fullpath ); names.emplace_back( file ); diff --git a/src/tools/codeeditor/projectdirectorytree.hpp b/src/tools/codeeditor/projectdirectorytree.hpp index e8fa09b5e..12897c5a3 100644 --- a/src/tools/codeeditor/projectdirectorytree.hpp +++ b/src/tools/codeeditor/projectdirectorytree.hpp @@ -50,7 +50,8 @@ class ProjectDirectoryTree { ProjectDirectoryTree( const std::string& path, std::shared_ptr threadPool ); void scan( const ScanCompleteEvent& scanComplete, - const std::vector& acceptedPattern = {} ); + const std::vector& acceptedPattern = {}, + const bool& ignoreHidden = true ); std::shared_ptr fuzzyMatchTree( const std::string& match, const size_t& max ) const; @@ -70,7 +71,8 @@ class ProjectDirectoryTree { Mutex mFilesMutex; void getDirectoryFiles( std::vector& files, std::vector& names, - std::string directory, std::set currentDirs ); + std::string directory, std::set currentDirs, + const bool& ignoreHidden ); }; #endif // EE_TOOLS_PROJECTDIRECTORYTREE_HPP