diff --git a/include/eepp/core/memorymanager.hpp b/include/eepp/core/memorymanager.hpp index 443381f23..a977e60a1 100644 --- a/include/eepp/core/memorymanager.hpp +++ b/include/eepp/core/memorymanager.hpp @@ -8,6 +8,7 @@ #include #include + namespace EE { class EE_API AllocatedPointer { @@ -25,6 +26,8 @@ class EE_API AllocatedPointer { typedef std::map AllocatedPointerMap; typedef AllocatedPointerMap::iterator AllocatedPointerMapIt; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" class EE_API MemoryManager { public: static void* addPointer( const AllocatedPointer& aAllocatedPointer ); @@ -39,52 +42,22 @@ class EE_API MemoryManager { template static T* deletePtr( T* data ) { delete data; -#if defined( __GNUC__ ) && __GNUC__ >= 12 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuse-after-free" return data; -#pragma GCC diagnostic pop -#else - return data; -#endif } template static T* deleteArrayPtr( T* data ) { delete[] data; -#if defined( __GNUC__ ) && __GNUC__ >= 12 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuse-after-free" return data; -#pragma GCC diagnostic pop -#else - return data; -#endif } template static T* free( T* data ) { ::free( data ); -#if defined( __GNUC__ ) && __GNUC__ >= 12 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuse-after-free" return data; -#pragma GCC diagnostic pop -#else - return data; -#endif } inline static void* allocate( size_t size ) { return malloc( size ); } - inline static void* reallocate( void* ptr, size_t size ) { -#if defined( __GNUC__ ) && __GNUC__ >= 12 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuse-after-free" - return realloc( ptr, size ); -#pragma GCC diagnostic pop -#else - return realloc( ptr, size ); -#endif - } + inline static void* reallocate( void* ptr, size_t size ) { return realloc( ptr, size ); } static size_t getPeakMemoryUsage(); @@ -92,6 +65,7 @@ class EE_API MemoryManager { static const AllocatedPointer& getBiggestAllocation(); }; +#pragma GCC diagnostic pop #ifdef EE_MEMORY_MANAGER #define eeNewTracked( classType, constructor ) \ @@ -114,32 +88,42 @@ class EE_API MemoryManager { #define eeMalloc( amount ) \ EE::MemoryManager::addPointer( EE::AllocatedPointer( EE::MemoryManager::allocate( amount ), \ __FILE__, __LINE__, amount ) ) - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" #define eeRealloc( ptr, amount ) \ EE::MemoryManager::reallocPointer( \ ptr, EE::AllocatedPointer( EE::MemoryManager::reallocate( ptr, amount ), __FILE__, \ __LINE__, amount ) ) - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" #define eeDelete( data ) \ { \ if ( EE::MemoryManager::removePointer( EE::MemoryManager::deletePtr( data ), __FILE__, \ __LINE__ ) == false ) \ printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \ } +#pragma GCC diagnostic pop +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" #define eeDeleteArray( data ) \ { \ if ( EE::MemoryManager::removePointer( EE::MemoryManager::deleteArrayPtr( data ), \ __FILE__, __LINE__ ) == false ) \ printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \ } +#pragma GCC diagnostic pop +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" #define eeFree( data ) \ { \ if ( EE::MemoryManager::removePointer( EE::MemoryManager::free( data ), __FILE__, \ __LINE__ ) == false ) \ printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \ } +#pragma GCC diagnostic pop + #else #define eeNewTracked( classType, constructor ) new classType constructor @@ -162,6 +146,7 @@ class EE_API MemoryManager { #endif + } // namespace EE #endif diff --git a/include/eepp/system/filesystem.hpp b/include/eepp/system/filesystem.hpp index 9835b381e..9f72e998f 100644 --- a/include/eepp/system/filesystem.hpp +++ b/include/eepp/system/filesystem.hpp @@ -122,7 +122,8 @@ class EE_API FileSystem { static bool isDirectory( const String& path ); /** Creates a new directory */ - static bool makeDir( const std::string& path, const Uint16& mode = 0770 ); + static bool makeDir( const std::string& path, bool recursive = false, + const Uint16& mode = 0770 ); /** @return The absolute path of a relative path */ static std::string getRealPath( const std::string& path ); diff --git a/include/eepp/system/sys.hpp b/include/eepp/system/sys.hpp index 7b156aa0b..5a03e9a3b 100644 --- a/include/eepp/system/sys.hpp +++ b/include/eepp/system/sys.hpp @@ -75,6 +75,9 @@ class EE_API Sys { /** @return the argument list in a vector of std::strings in UTF-8, ignoring the first argument * (the binary name) */ static std::vector parseArguments( int argc, char* argv[] ); + + /** @return The OS logical drives */ + static std::vector getLogicalDrives(); }; }} // namespace EE::System diff --git a/include/eepp/ui/abstract/uiabstracttableview.hpp b/include/eepp/ui/abstract/uiabstracttableview.hpp index 6e5054c0c..b986024b7 100644 --- a/include/eepp/ui/abstract/uiabstracttableview.hpp +++ b/include/eepp/ui/abstract/uiabstracttableview.hpp @@ -37,7 +37,7 @@ class EE_API UIAbstractTableView : public UIAbstractView { void setColumnHidden( const size_t& column, bool hidden ); - void setColumnsHidden( const std::vector columns, bool hidden ); + void setColumnsHidden( const std::vector& columns, bool hidden ); virtual void selectAll(); @@ -152,7 +152,7 @@ class EE_API UIAbstractTableView : public UIAbstractView { virtual void onModelUpdate( unsigned flags ); - virtual void createOrUpdateColumns(); + virtual void createOrUpdateColumns( bool resetColumnData = false ); virtual void onSizeChange(); @@ -191,6 +191,10 @@ class EE_API UIAbstractTableView : public UIAbstractView { void updateHeaderSize(); int visibleColumn(); + + void updateCellsVisibility(); + + void resetColumnData(); }; }}} // namespace EE::UI::Abstract diff --git a/include/eepp/ui/abstract/uiabstractview.hpp b/include/eepp/ui/abstract/uiabstractview.hpp index a2ebc8c48..51f013189 100644 --- a/include/eepp/ui/abstract/uiabstractview.hpp +++ b/include/eepp/ui/abstract/uiabstractview.hpp @@ -45,7 +45,7 @@ class EE_API UIAbstractView : public UIScrollableWidget { bool isType( const Uint32& type ) const; - void setModel( std::shared_ptr ); + void setModel( const std::shared_ptr& ); Model* getModel() { return mModel.get(); } diff --git a/include/eepp/ui/models/filesystemmodel.hpp b/include/eepp/ui/models/filesystemmodel.hpp index 2ea0e73f8..814fa5012 100644 --- a/include/eepp/ui/models/filesystemmodel.hpp +++ b/include/eepp/ui/models/filesystemmodel.hpp @@ -197,9 +197,41 @@ class EE_API FileSystemModel : public Model { size_t getFileIndex( Node* parent, const FileInfo& file ); - bool handleFileEventLocked( const FileEvent& event ); +}; +class EE_API DiskDrivesModel : public Model { + public: + enum Column { + Icon = 0, + Name, + Count, + }; + + static std::shared_ptr create( const std::vector& data ); + + static std::shared_ptr create(); + + virtual ~DiskDrivesModel() {} + + virtual size_t rowCount( const ModelIndex& ) const { return mData.size(); } + + virtual size_t columnCount( const ModelIndex& ) const { return 2; } + + virtual std::string columnName( const size_t& index ) const { + return index == 0 ? "Icon" : "Name"; + } + + UIIcon* diskIcon() const; + + virtual Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const; + + virtual void update() { onModelUpdate(); } + + private: + explicit DiskDrivesModel( const std::vector& data ) : mData( data ) {} + + std::vector mData; }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/models/model.hpp b/include/eepp/ui/models/model.hpp index d1520b4fb..161f1068c 100644 --- a/include/eepp/ui/models/model.hpp +++ b/include/eepp/ui/models/model.hpp @@ -138,9 +138,9 @@ class EE_API Model { Mutex& resourceMutex(); - void acquireResourceMutex() { mResourceLock.lock(); } + void acquireResourceMutex(); - void releaseResourceMutex() { mResourceLock.unlock(); } + void releaseResourceMutex(); protected: Model(){}; diff --git a/include/eepp/ui/uifiledialog.hpp b/include/eepp/ui/uifiledialog.hpp index a291de002..c0a65de36 100644 --- a/include/eepp/ui/uifiledialog.hpp +++ b/include/eepp/ui/uifiledialog.hpp @@ -136,6 +136,8 @@ class EE_API UIFileDialog : public UIWindow { KeyBindings::Shortcut mCloseShortcut; KeyBindings::Shortcut mOpenShortut{ KEY_RETURN, KeyMod::getDefaultModifier() }; std::shared_ptr mModel; + std::shared_ptr mDiskDrivesModel; + bool mDisplayingDrives{ false }; UIFileDialog( Uint32 dialogFlags = UIFileDialog::DefaultFlags, const std::string& defaultFilePattern = "*", @@ -164,6 +166,10 @@ class EE_API UIFileDialog : public UIWindow { void setCurPath( const std::string& path ); const FileSystemModel::Node* getSelectionNode() const; + + ModelIndex getSelectionModelIndex() const; + + std::string getSelectedDrive() const; }; }} // namespace EE::UI diff --git a/include/eepp/ui/uitableview.hpp b/include/eepp/ui/uitableview.hpp index f50f0dd04..a48e2e62d 100644 --- a/include/eepp/ui/uitableview.hpp +++ b/include/eepp/ui/uitableview.hpp @@ -31,7 +31,7 @@ class EE_API UITableView : public UIAbstractTableView { UITableView( const std::string& tag ); - virtual void createOrUpdateColumns(); + virtual void createOrUpdateColumns( bool resetColumnData ); void updateContentSize(); diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index 5d839cdac..9a10b3649 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -160,7 +160,7 @@ class EE_API UITreeView : public UIAbstractTableView { UITreeView(); - virtual void createOrUpdateColumns(); + virtual void createOrUpdateColumns( bool resetColumnData ); struct MetadataForIndex { bool open{ false }; diff --git a/premake4.lua b/premake4.lua index c3e1deb28..4335dd82d 100644 --- a/premake4.lua +++ b/premake4.lua @@ -1272,14 +1272,22 @@ solution "eepp" links { "CoreFoundation.framework", "CoreServices.framework", "Cocoa.framework" } links { "ecode-macos-helper-static" } end + if _OPTIONS["with-debug-symbols"] then + defines { "ECODE_USE_BACKWARD" } + end if os.is_real("linux") then if _OPTIONS["with-debug-symbols"] then - defines { "ECODE_USE_BACKWARD" } links { "util", "bfd", "dw", "dl" } else links { "util" } end end + if (os.is_real("windows") or os.is_real("mingw32") or os.is_real("mingw64")) and _OPTIONS["with-debug-symbols"] then + links { "dbghelp", "psapi" } + if os.is_real("mingw32") or os.is_real("mingw64") then + links { "msvcr90" } + end + end if os.is("haiku") then links { "bsd" } end diff --git a/premake5.lua b/premake5.lua index 18cf5bf37..454474c9f 100644 --- a/premake5.lua +++ b/premake5.lua @@ -204,11 +204,11 @@ function build_base_cpp_configuration( package_name ) filter "configurations:release*" defines { "NDEBUG" } optimize "Speed" - if _OPTIONS["with-debug-symbols"] then - symbols "On" - end targetname ( package_name ) + filter { "configurations:release*", "options:with-debug-symbols" } + symbols "On" + filter "system:emscripten" buildoptions { "-O3 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=worker,web" } if _OPTIONS["with-emscripten-pthreads"] then @@ -668,11 +668,12 @@ workspace "eepp" filter "configurations:debug*" defines { "DEBUG" } symbols "On" + filter "configurations:release*" optimize "Speed" - if _OPTIONS["with-debug-symbols"] then - symbols "On" - end + + filter { "configurations:release*", "options:with-debug-symbols" } + symbols "On" filter { "system:windows", "action:vs*" } flags { "MultiProcessorCompile" } @@ -983,10 +984,9 @@ workspace "eepp" filter { "configurations:release*", "action:not vs*" } defines { "NDEBUG" } optimize "Speed" - if _OPTIONS["with-debug-symbols"] then - symbols "On" - end targetname ( "ecode-macos-helper-static" ) + filter { "configurations:release*", "action:not vs*", "options:with-debug-symbols" } + symbols "On" project "ecode" set_kind() @@ -995,18 +995,21 @@ workspace "eepp" incdirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/" } links { "efsw-static", "eterm-static" } build_link_configuration( "ecode", true ) + filter "options:with-debug-symbols" + defines { "ECODE_USE_BACKWARD" } filter "system:macosx" links { "CoreFoundation.framework", "CoreServices.framework", "Cocoa.framework" } links { "ecode-macos-helper-static" } filter { "system:not windows", "system:not haiku" } links { "pthread" } filter "system:linux" - if _OPTIONS["with-debug-symbols"] then - defines { "ECODE_USE_BACKWARD" } - links { "util", "bfd", "dw", "dl" } - else - links { "util" } - end + links { "util" } + filter { "system:windows", "options:with-debug-symbols" } + links { "dbghelp", "psapi" } + filter { "system:windows", "options:with-debug-symbols", "options:cc=mingw" } + links { "msvcr90" } + filter { "system:linux", "options:with-debug-symbols" } + links { "bfd", "dw", "dl" } filter "system:haiku" links { "bsd" } diff --git a/src/eepp/system/filesystem.cpp b/src/eepp/system/filesystem.cpp index 0f6e2ceaf..d61060419 100644 --- a/src/eepp/system/filesystem.cpp +++ b/src/eepp/system/filesystem.cpp @@ -296,8 +296,8 @@ bool FileSystem::isDirectory( const std::string& path ) { #endif } -bool FileSystem::makeDir( const std::string& path, const Uint16& mode ) { - Int16 v; +static inline bool eepp_mkdir( const std::string& path, const Uint16& mode ) { + int v; #if EE_PLATFORM == EE_PLATFORM_WIN #ifdef EE_COMPILER_MSVC v = _mkdir( path.c_str() ); @@ -310,6 +310,35 @@ bool FileSystem::makeDir( const std::string& path, const Uint16& mode ) { return v == 0; } +bool FileSystem::makeDir( const std::string& path, bool recursive, const Uint16& mode ) { + if ( recursive && path.size() > 1 ) { + size_t i = path.size() - 1; + for ( ; i >= 0; --i ) { + if ( path[i] == '/' || path[i] == '\\' ) { + if ( FileSystem::isDirectory( path.substr( 0, i ) ) ) { + break; + } + } + } + + if ( i == 0 ) + return false; + + i++; + for ( ; i < path.size(); ++i ) { + if ( path[i] == '/' || path[i] == '\\' ) { + if ( !eepp_mkdir( path.substr( 0, i ), mode ) ) + return false; + } + } + + if ( path[path.size() - 1] == '/' || path[path.size() - 1] == '\\' ) + return true; + } + + return eepp_mkdir( path, mode ); +} + std::string FileSystem::getRealPath( const std::string& path ) { std::string realPath; #ifdef EE_PLATFORM_POSIX @@ -367,7 +396,8 @@ std::vector FileSystem::filesGetInPath( const String& path, const bool& return files; while ( ( dirp = readdir( dp ) ) != NULL ) { - if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) { + if ( strncmp( dirp->d_name, "..", sizeof( dirp->d_name ) ) != 0 && + strncmp( dirp->d_name, ".", sizeof( dirp->d_name ) ) != 0 ) { char* p = &dirp->d_name[0]; String tmp; @@ -476,7 +506,8 @@ std::vector FileSystem::filesGetInPath( const std::string& path, return files; while ( ( dirp = readdir( dp ) ) != NULL ) { - if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) + if ( strncmp( dirp->d_name, "..", sizeof( dirp->d_name ) ) != 0 && + strncmp( dirp->d_name, ".", sizeof( dirp->d_name ) ) != 0 ) files.push_back( std::string( dirp->d_name ) ); } diff --git a/src/eepp/system/pak.cpp b/src/eepp/system/pak.cpp index 00c625adc..bd6baaf6c 100644 --- a/src/eepp/system/pak.cpp +++ b/src/eepp/system/pak.cpp @@ -115,7 +115,7 @@ Int8 Pak::checkPack() { Int32 Pak::exists( const std::string& path ) { if ( isOpen() ) { for ( Uint32 i = 0; i < mPakFiles.size(); i++ ) - if ( strcmp( path.c_str(), mPakFiles[i].filename ) == 0 ) + if ( std::strncmp( path.c_str(), mPakFiles[i].filename, path.size() ) == 0 ) return i; } diff --git a/src/eepp/system/sys.cpp b/src/eepp/system/sys.cpp index 67b1b648d..0b7974187 100644 --- a/src/eepp/system/sys.cpp +++ b/src/eepp/system/sys.cpp @@ -29,6 +29,7 @@ #undef GetTempPath #elif EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_ANDROID #include +#include #include #elif EE_PLATFORM == EE_PLATFORM_HAIKU #include @@ -899,4 +900,60 @@ std::vector Sys::parseArguments( int argc, char* argv[] ) { #endif } +#if EE_PLATFORM == EE_PLATFORM_WIN +static inline bool isDriveReady( const wchar_t* path ) { + DWORD fileSystemFlags; + const UINT driveType = GetDriveTypeW( path ); + return ( driveType != DRIVE_REMOVABLE && driveType != DRIVE_CDROM ) || + GetVolumeInformationW( path, nullptr, 0, nullptr, nullptr, &fileSystemFlags, nullptr, + 0 ) == TRUE; +} +#endif + +std::vector Sys::getLogicalDrives() { +#if EE_PLATFORM == EE_PLATFORM_WIN + std::vector ret; + const UINT oldErrorMode = ::SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX ); + Uint32 driveBits = (Uint32)GetLogicalDrives() & 0x3ffffff; + wchar_t driveName[] = L"A:\\"; + + while ( driveBits ) { + if ( ( driveBits & 1 ) && isDriveReady( driveName ) ) + ret.emplace_back( String::fromWide( driveName ).toUtf8() ); + driveName[0]++; + driveBits = driveBits >> 1; + } + ::SetErrorMode( oldErrorMode ); + return ret; +#elif EE_PLATFORM == EE_PLATFORM_LINUX + std::vector ret; + struct mntent* ent; + FILE* file = setmntent( "/etc/mtab", "r" ); + if ( file == NULL ) { + file = setmntent( "/proc/mounts", "r" ); + if ( file == NULL ) + return ret; + } + while ( NULL != ( ent = getmntent( file ) ) ) { + std::string mntType( ent->mnt_type ); + if ( mntType == "rootfs" || mntType == "devtmpfs" || mntType == "tmpfs" || + mntType == "devpts" || mntType == "hugetlbfs" || mntType == "mqueue" || + mntType == "ramfs" || mntType == "rpc_pipefs" || mntType == "fuse.gvfsd-fuse" || + mntType == "fuse.portal" || mntType == "overlay" || mntType == "nsfs" ) + continue; + + std::string mntDir( ent->mnt_dir ); + if ( String::startsWith( mntDir, "/proc" ) || String::startsWith( mntDir, "/var/run" ) || + String::startsWith( mntDir, "/sys" ) || String::startsWith( mntDir, "/var/lock" ) ) + continue; + + ret.emplace_back( std::move( mntDir ) ); + } + endmntent( file ); + return ret; +#else + return {}; +#endif +} + }} // namespace EE::System diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 0ca265c04..7d42a8832 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -42,7 +42,7 @@ Float UIAbstractTableView::getRowHeight() const { void UIAbstractTableView::setRowHeight( const Float& rowHeight ) { if ( mRowHeight != rowHeight ) { mRowHeight = rowHeight; - createOrUpdateColumns(); + createOrUpdateColumns( false ); } } @@ -51,7 +51,7 @@ void UIAbstractTableView::setColumnWidth( const size_t& colIndex, const Float& w columnData( colIndex ).width = width; updateHeaderSize(); onColumnSizeChange( colIndex ); - createOrUpdateColumns(); + createOrUpdateColumns( false ); } } @@ -77,24 +77,37 @@ void UIAbstractTableView::onModelUpdate( unsigned flags ) { if ( !Engine::instance()->isMainThread() ) { runOnMainThread( [&, flags] { modelUpdate( flags ); - createOrUpdateColumns(); + createOrUpdateColumns( true ); } ); } else { UIAbstractView::onModelUpdate( flags ); - createOrUpdateColumns(); + createOrUpdateColumns( true ); } } -void UIAbstractTableView::createOrUpdateColumns() { +void UIAbstractTableView::resetColumnData() { + Model* model = getModel(); + if ( !model ) + return; + size_t count = model->columnCount(); + for ( size_t i = 0; i < count; i++ ) { + ColumnData& col = columnData( i ); + col.minWidth = 0; + } +} + +void UIAbstractTableView::createOrUpdateColumns( bool resetColumnData ) { Model* model = getModel(); if ( !model ) return; size_t count = model->columnCount(); Float totalWidth = 0; - auto visibleColCount = visibleColumnCount(); + if ( resetColumnData ) + this->resetColumnData(); + for ( size_t i = 0; i < count; i++ ) { ColumnData& col = columnData( i ); if ( !col.widget ) { @@ -223,7 +236,7 @@ void UIAbstractTableView::setHeadersVisible( bool visible ) { void UIAbstractTableView::onSizeChange() { UIAbstractView::onSizeChange(); - createOrUpdateColumns(); + createOrUpdateColumns( false ); } void UIAbstractTableView::onColumnSizeChange( const size_t&, bool fromUserInteraction ) { @@ -237,7 +250,7 @@ Float UIAbstractTableView::getMaxColumnContentWidth( const size_t&, bool ) { void UIAbstractTableView::onColumnResizeToContent( const size_t& colIndex ) { columnData( colIndex ).width = getMaxColumnContentWidth( colIndex, true ); - createOrUpdateColumns(); + createOrUpdateColumns( false ); } void UIAbstractTableView::updateHeaderSize() { @@ -260,6 +273,17 @@ int UIAbstractTableView::visibleColumn() { return -1; } +void UIAbstractTableView::updateCellsVisibility() { + auto colCount = mColumn.size(); + for ( size_t colIdx = 0; colIdx < colCount; ++colIdx ) { + for ( auto row : mWidgets ) { + auto rowCol = row.find( colIdx ); + if ( rowCol != row.end() ) + rowCol->second->setVisible( mColumn[colIdx].visible ); + } + } +} + bool UIAbstractTableView::getAutoExpandOnSingleColumn() const { return mAutoExpandOnSingleColumn; } @@ -334,19 +358,38 @@ bool UIAbstractTableView::isColumnHidden( const size_t& column ) const { void UIAbstractTableView::setColumnHidden( const size_t& column, bool hidden ) { if ( columnData( column ).visible != !hidden ) { columnData( column ).visible = !hidden; - createOrUpdateColumns(); + createOrUpdateColumns( false ); } } -void UIAbstractTableView::setColumnsHidden( const std::vector columns, bool hidden ) { +void UIAbstractTableView::setColumnsHidden( const std::vector& columns, bool hidden ) { for ( auto col : columns ) columnData( col ).visible = !hidden; - createOrUpdateColumns(); + updateCellsVisibility(); + createOrUpdateColumns( false ); } void UIAbstractTableView::setColumnsVisible( const std::vector columns ) { if ( !getModel() ) return; + + // Check if the columns visible are the same + if ( !mColumn.empty() && !columns.empty() ) { + // TODO: Do not limit the column count to 64 + Uint64 colFlags = 0; + Uint64 newColFlags = 0; + for ( size_t i = 0; i < mColumn.size(); ++i ) { + if ( mColumn[i].visible ) + colFlags |= 1 << i; + } + + for ( auto col : columns ) + newColFlags |= 1 << col; + + if ( colFlags == newColFlags ) + return; + } + for ( size_t i = 0; i < getModel()->columnCount(); i++ ) columnData( i ).visible = false; @@ -360,7 +403,9 @@ void UIAbstractTableView::setColumnsVisible( const std::vector columns ) if ( !foundMainColumn && !columns.empty() ) mMainColumn = columns[0]; - createOrUpdateColumns(); + updateCellsVisibility(); + + createOrUpdateColumns( true ); } UITableRow* UIAbstractTableView::createRow() { @@ -452,7 +497,12 @@ UIWidget* UIAbstractTableView::updateCell( const int& rowIndex, const ModelIndex mWidgets[rowIndex][index.column()] = widget; widget->reloadStyle( true, true, true ); } - widget->setPixelsSize( columnData( index.column() ).width, getRowHeight() ); + const auto& colData = columnData( index.column() ); + if ( !colData.visible ) { + widget->setVisible( false ); + return widget; + } + widget->setPixelsSize( colData.width, getRowHeight() ); widget->setPixelsPosition( { getColumnPosition( index.column() ).x, 0 } ); if ( widget->isType( UI_TYPE_TABLECELL ) ) { UITableCell* cell = widget->asType(); diff --git a/src/eepp/ui/abstract/uiabstractview.cpp b/src/eepp/ui/abstract/uiabstractview.cpp index 9c3c796b2..335b1f746 100644 --- a/src/eepp/ui/abstract/uiabstractview.cpp +++ b/src/eepp/ui/abstract/uiabstractview.cpp @@ -33,7 +33,7 @@ bool UIAbstractView::isType( const Uint32& type ) const { return UIAbstractView::getType() == type ? true : UIScrollableWidget::isType( type ); } -void UIAbstractView::setModel( std::shared_ptr model ) { +void UIAbstractView::setModel( const std::shared_ptr& model ) { if ( model.get() == mModel.get() ) return; if ( mModel ) diff --git a/src/eepp/ui/models/filesystemmodel.cpp b/src/eepp/ui/models/filesystemmodel.cpp index ea357c58f..58559556f 100644 --- a/src/eepp/ui/models/filesystemmodel.cpp +++ b/src/eepp/ui/models/filesystemmodel.cpp @@ -461,7 +461,8 @@ size_t FileSystemModel::getFileIndex( Node* parent, const FileInfo& file ) { files.emplace_back( file ); std::sort( files.begin(), files.end(), []( FileInfo a, FileInfo b ) { - return std::strcmp( a.getFileName().c_str(), b.getFileName().c_str() ) < 0; + return std::strncmp( a.getFileName().c_str(), b.getFileName().c_str(), + a.getFileName().size() ) < 0; } ); if ( getDisplayConfig().foldersFirst ) { @@ -723,4 +724,40 @@ bool FileSystemModel::handleFileEvent( const FileEvent& event ) { return ret; } +std::shared_ptr DiskDrivesModel::create( const std::vector& data ) { + return std::shared_ptr( new DiskDrivesModel( data ) ); +} + +std::shared_ptr DiskDrivesModel::create() { + return create( Sys::getLogicalDrives() ); +} + +UIIcon* DiskDrivesModel::diskIcon() const { + auto* scene = SceneManager::instance()->getUISceneNode(); + auto* d = scene->findIcon( "drive" ); + if ( !d ) + d = scene->findIcon( "folder" ); + return d; +} + +Variant DiskDrivesModel::data( const ModelIndex& index, ModelRole role ) const { + eeASSERT( index.row() >= 0 && index.row() < (Int64)mData.size() ); + if ( role == ModelRole::Display ) { + switch ( index.column() ) { + case Column::Icon: + return diskIcon(); + case Column::Name: + return Variant( mData[index.row()].c_str() ); + } + } + + if ( role == ModelRole::Icon ) + return diskIcon(); + + if ( role == ModelRole::Custom ) + return Variant( mData[index.row()].c_str() ); + + return {}; +} + }}} // namespace EE::UI::Models diff --git a/src/eepp/ui/models/model.cpp b/src/eepp/ui/models/model.cpp index 6e3aed32f..1bf5e10f7 100644 --- a/src/eepp/ui/models/model.cpp +++ b/src/eepp/ui/models/model.cpp @@ -307,6 +307,14 @@ Mutex& Model::resourceMutex() { return mResourceLock; } +void Model::acquireResourceMutex() { + mResourceLock.lock(); +} + +void Model::releaseResourceMutex() { + mResourceLock.unlock(); +} + void Model::handleMove( Operation const& operation ) { bool isRow = operation.direction == Direction::Row; bool moveWithin = operation.sourceParent == operation.targetParent; diff --git a/src/eepp/ui/uifiledialog.cpp b/src/eepp/ui/uifiledialog.cpp index f0b27de94..d2b1b1e82 100644 --- a/src/eepp/ui/uifiledialog.cpp +++ b/src/eepp/ui/uifiledialog.cpp @@ -15,6 +15,7 @@ namespace EE { namespace UI { #define FDLG_MIN_WIDTH 640 #define FDLG_MIN_HEIGHT 400 +#define FDLG_DRIVE_PATH "drives://" UIFileDialog* UIFileDialog::New( Uint32 dialogFlags, const std::string& defaultFilePattern, const std::string& defaultDirectory ) { @@ -82,7 +83,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa mPath->addEventListener( Event::OnPressEnter, cb::Make1( this, &UIFileDialog::onPressEnter ) ); mButtonUp = UIPushButton::New(); - mButtonUp->setText( "Up" ) + mButtonUp->setText( getTranslatorString( "@string/uifiledialog_go_up", "Up" ) ) ->setLayoutMarginLeft( 4 ) ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) ->setParent( hLayout ); @@ -116,7 +117,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa } ); mButtonListView = UISelectButton::New(); - mButtonListView->setText( "List" ) + mButtonListView->setText( getTranslatorString( "@string/uifiledialog_list", "List" ) ) ->setLayoutMarginLeft( 4 ) ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) ->setParent( hLayout ); @@ -127,7 +128,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa } ); mButtonTableView = UISelectButton::New(); - mButtonTableView->setText( "Table" ) + mButtonTableView->setText( getTranslatorString( "@string/uifiledialog_table", "Table" ) ) ->setLayoutMarginLeft( 4 ) ->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ) ->setParent( hLayout ); @@ -167,7 +168,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa } } ); mMultiView->setOnSelectionChange( [&] { - if ( mMultiView->getSelection().isEmpty() ) + if ( mMultiView->getSelection().isEmpty() || mDisplayingDrives ) return; const FileSystemModel::Node* node = getSelectionNode(); if ( !node ) { @@ -306,29 +307,44 @@ void UIFileDialog::setTheme( UITheme* Theme ) { void UIFileDialog::refreshFolder( bool resetScroll ) { FileSystem::dirAddSlashAtEnd( mCurPath ); - std::vector flist = FileSystem::filesGetInPath( - String( mCurPath ), getSortAlphabetically(), getFoldersFirst(), !getShowHidden() ); - std::vector files; - std::vector patterns; - if ( "*" != mFiletype->getText() ) { - patterns = String::split( mFiletype->getText().toUtf8(), ';' ); + if ( mCurPath == FDLG_DRIVE_PATH ) { + if ( !mDiskDrivesModel ) + mDiskDrivesModel = DiskDrivesModel::create(); - for ( size_t i = 0; i < patterns.size(); i++ ) - patterns[i] = FileSystem::fileExtension( String::trim( patterns[i] ) ); - } + mDisplayingDrives = true; + mMultiView->getTableView()->setColumnsVisible( { FileSystemModel::Name } ); + mMultiView->setModel( SortingProxyModel::New( mDiskDrivesModel ) ); + } else { + std::vector flist = FileSystem::filesGetInPath( + String( mCurPath ), getSortAlphabetically(), getFoldersFirst(), !getShowHidden() ); + std::vector files; + std::vector patterns; - if ( !mModel ) { - mModel = FileSystemModel::New( - mCurPath, - getShowOnlyFolders() ? FileSystemModel::Mode::DirectoriesOnly - : FileSystemModel::Mode::FilesAndDirectories, - FileSystemModel::DisplayConfig( getSortAlphabetically(), getFoldersFirst(), - !getShowHidden(), patterns ) ); + if ( "*" != mFiletype->getText() ) { + patterns = String::split( mFiletype->getText().toUtf8(), ';' ); + + for ( size_t i = 0; i < patterns.size(); i++ ) + patterns[i] = FileSystem::fileExtension( String::trim( patterns[i] ) ); + } + + if ( !mModel ) { + mModel = FileSystemModel::New( + mCurPath, + getShowOnlyFolders() ? FileSystemModel::Mode::DirectoriesOnly + : FileSystemModel::Mode::FilesAndDirectories, + FileSystemModel::DisplayConfig( getSortAlphabetically(), getFoldersFirst(), + !getShowHidden(), patterns ) ); + } else { + mModel->setRootPath( mCurPath ); + } mMultiView->setModel( SortingProxyModel::New( mModel ) ); - } else { - mModel->setRootPath( mCurPath ); + + mMultiView->getTableView()->setColumnsVisible( + { FileSystemModel::Name, FileSystemModel::Size, FileSystemModel::ModificationTime } ); + + mDisplayingDrives = false; } updateClickStep(); @@ -365,13 +381,20 @@ void UIFileDialog::setCurPath( const std::string& path ) { refreshFolder( true ); } -const FileSystemModel::Node* UIFileDialog::getSelectionNode() const { +ModelIndex UIFileDialog::getSelectionModelIndex() const { if ( mMultiView->getSelection().isEmpty() ) - return nullptr; + return {}; auto index = mMultiView->getSelection().first(); auto* filterModel = (SortingProxyModel*)mMultiView->getModel().get(); auto localIndex = filterModel->mapToSource( index ); - const FileSystemModel::Node& node = mModel.get()->node( localIndex ); + return localIndex; +} + +const FileSystemModel::Node* UIFileDialog::getSelectionNode() const { + if ( mMultiView->getSelection().isEmpty() || mDisplayingDrives ) + return nullptr; + auto localIndex = getSelectionModelIndex(); + const FileSystemModel::Node& node = mModel->node( localIndex ); return &node; } @@ -405,9 +428,25 @@ void UIFileDialog::disableButtons() { mCloseShortcut = {}; } +std::string UIFileDialog::getSelectedDrive() const { + if ( !mDisplayingDrives ) + return ""; + ModelIndex index = getSelectionModelIndex(); + ModelIndex modelIndex( mDiskDrivesModel->index( index.row(), DiskDrivesModel::Name ) ); + Variant var( mDiskDrivesModel->data( modelIndex ) ); + std::string drive( var.asCStr() ); + return drive; +} + void UIFileDialog::openFileOrFolder( bool shouldOpenFolder = false ) { if ( mMultiView->getSelection().isEmpty() ) return; + + if ( mDisplayingDrives ) { + setCurPath( getSelectedDrive() ); + return; + } + auto* node = getSelectionNode(); if ( !node ) { Log::error( "UIFileDialog::getSelectionNode() was empty, shouldn't be empty" ); @@ -427,8 +466,20 @@ void UIFileDialog::openFileOrFolder( bool shouldOpenFolder = false ) { } void UIFileDialog::goFolderUp() { + if ( mCurPath == FDLG_DRIVE_PATH ) + return; std::string prevFolderName( FileSystem::fileNameFromPath( mCurPath ) ); - setCurPath( FileSystem::removeLastFolderFromPath( mCurPath ) ); + std::string newPath( FileSystem::removeLastFolderFromPath( mCurPath ) ); + if ( newPath == mCurPath ) { + auto drives = Sys::getLogicalDrives(); + if ( !drives.empty() ) { + setCurPath( newPath != mCurPath ? newPath : FDLG_DRIVE_PATH ); + } else { + setCurPath( newPath ); + } + } else { + setCurPath( newPath ); + } ModelIndex index = mMultiView->getCurrentView()->findRowWithText( prevFolderName, true, true ); if ( index.isValid() ) mMultiView->setSelection( index ); @@ -486,6 +537,13 @@ void UIFileDialog::open() { !FileSystem::fileExists( getFullPath() ) ) return; + if ( mDisplayingDrives ) { + if ( !allowFolderSelect() ) + return; + if ( FileSystem::isDirectory( getFullPath() ) ) + return; + } + auto* node = !mMultiView->getSelection().isEmpty() ? getSelectionNode() : nullptr; if ( !node ) { node = mModel->getNodeFromPath( getFullPath() ); @@ -515,7 +573,8 @@ void UIFileDialog::open() { } void UIFileDialog::onPressEnter( const Event* ) { - if ( FileSystem::isDirectory( mPath->getText() ) ) { + if ( FileSystem::isDirectory( mPath->getText() ) || + ( FDLG_DRIVE_PATH == mPath->getText().toUtf8() && !Sys::getLogicalDrives().empty() ) ) { setCurPath( mPath->getText() ); } else if ( !allowFolderSelect() && FileSystem::fileExists( mPath->getText() ) ) { String folderPath( FileSystem::fileRemoveFileName( mPath->getText() ) ); @@ -589,6 +648,9 @@ void UIFileDialog::setShowHidden( const bool& showHidden ) { } std::string UIFileDialog::getFullPath() { + if ( mDisplayingDrives ) + return getCurFile(); + std::string tPath = mCurPath; FileSystem::dirAddSlashAtEnd( tPath ); @@ -607,14 +669,18 @@ std::string UIFileDialog::getCurFile() const { return mFile->getText(); if ( mMultiView->getSelection().isEmpty() ) return ""; - auto* node = getSelectionNode(); + if ( mDisplayingDrives ) { + return getSelectedDrive(); + } else { + auto* node = getSelectionNode(); - if ( !node ) { - Log::error( "UIFileDialog::getCurFile() - UIFileDialog::getSelectionNode() was empty, " - "shouldn't be empty" ); - return ""; + if ( !node ) { + Log::error( "UIFileDialog::getCurFile() - UIFileDialog::getSelectionNode() was empty, " + "shouldn't be empty" ); + return ""; + } + return node->getName(); } - return node->getName(); } UIPushButton* UIFileDialog::getButtonOpen() const { diff --git a/src/eepp/ui/uitableview.cpp b/src/eepp/ui/uitableview.cpp index 897af90de..8ce6c28d0 100644 --- a/src/eepp/ui/uitableview.cpp +++ b/src/eepp/ui/uitableview.cpp @@ -40,10 +40,8 @@ void UITableView::drawChilds() { 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 ); - } + updateCell( realIndex, getModel()->index( index.row(), colIndex, index.parent() ), 0, + yOffset ); } updateRow( realIndex, index, yOffset )->nodeDraw(); realIndex++; @@ -155,12 +153,12 @@ Float UITableView::getMaxColumnContentWidth( const size_t& colIndex, bool bestGu return lWidth; } -void UITableView::createOrUpdateColumns() { +void UITableView::createOrUpdateColumns( bool resetColumnData ) { if ( !getModel() ) { updateContentSize(); return; } - UIAbstractTableView::createOrUpdateColumns(); + UIAbstractTableView::createOrUpdateColumns( resetColumnData ); updateContentSize(); } @@ -181,7 +179,7 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) { return UIAbstractTableView::onKeyDown( event ); auto curIndex = getSelection().first(); int pageSize = eefloor( getVisibleArea().getHeight() / getRowHeight() ) - 1; - ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr ); + switch ( event.getKeyCode() ) { case KEY_PAGEUP: { if ( curIndex.row() - pageSize < 0 ) { diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index e12c03c84..1bb33a0e1 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -84,11 +84,11 @@ void UITreeView::traverseTree( TreeViewCallback callback ) const { } } -void UITreeView::createOrUpdateColumns() { +void UITreeView::createOrUpdateColumns( bool resetColumnData ) { updateContentSize(); if ( !getModel() ) return; - UIAbstractTableView::createOrUpdateColumns(); + UIAbstractTableView::createOrUpdateColumns( resetColumnData ); } size_t UITreeView::getItemCount() const { @@ -124,7 +124,7 @@ void UITreeView::bindNavigationClick( UIWidget* widget ) { if ( getModel()->rowCount( idx ) ) { auto& data = getIndexMetadata( idx ); data.open = !data.open; - createOrUpdateColumns(); + createOrUpdateColumns( false ); onOpenTreeModelIndex( idx, data.open ); } else { onOpenModelIndex( idx, event ); @@ -153,7 +153,7 @@ bool UITreeView::tryOpenModelIndex( const ModelIndex& index, bool forceUpdate ) if ( !data.open ) { data.open = true; if ( forceUpdate ) - createOrUpdateColumns(); + createOrUpdateColumns( false ); onOpenTreeModelIndex( index, data.open ); } return true; @@ -186,7 +186,7 @@ UIWidget* UITreeView::setupCell( UITableCell* widget, UIWidget* rowWidget, if ( getModel()->rowCount( idx ) ) { auto& data = getIndexMetadata( idx ); data.open = !data.open; - createOrUpdateColumns(); + createOrUpdateColumns( false ); onOpenTreeModelIndex( idx, data.open ); } } @@ -300,7 +300,7 @@ const Float& UITreeView::getIndentWidth() const { void UITreeView::setIndentWidth( const Float& indentWidth ) { if ( mIndentWidth != indentWidth ) { mIndentWidth = indentWidth; - createOrUpdateColumns(); + createOrUpdateColumns( false ); } } @@ -403,14 +403,14 @@ void UITreeView::expandAll( const ModelIndex& index ) { if ( !getModel() ) return; setAllExpanded( index, true ); - createOrUpdateColumns(); + createOrUpdateColumns( false ); } void UITreeView::collapseAll( const ModelIndex& index ) { if ( !getModel() ) return; setAllExpanded( index, false ); - createOrUpdateColumns(); + createOrUpdateColumns( false ); } UIIcon* UITreeView::getExpandIcon() const { @@ -420,7 +420,7 @@ UIIcon* UITreeView::getExpandIcon() const { void UITreeView::setExpandedIcon( UIIcon* expandIcon ) { if ( mExpandIcon != expandIcon ) { mExpandIcon = expandIcon; - createOrUpdateColumns(); + createOrUpdateColumns( false ); } } @@ -435,7 +435,7 @@ UIIcon* UITreeView::getContractIcon() const { void UITreeView::setContractedIcon( UIIcon* contractIcon ) { if ( mContractIcon != contractIcon ) { mContractIcon = contractIcon; - createOrUpdateColumns(); + createOrUpdateColumns( false ); } } @@ -613,7 +613,7 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { auto& metadata = getIndexMetadata( curIndex ); if ( !metadata.open ) { metadata.open = true; - createOrUpdateColumns(); + createOrUpdateColumns( false ); return 0; } getSelection().set( getModel()->index( 0, getModel()->treeColumn(), curIndex ) ); @@ -625,7 +625,7 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { auto& metadata = getIndexMetadata( curIndex ); if ( metadata.open ) { metadata.open = false; - createOrUpdateColumns(); + createOrUpdateColumns( false ); return 0; } } @@ -641,7 +641,7 @@ Uint32 UITreeView::onKeyDown( const KeyEvent& event ) { if ( getModel()->rowCount( curIndex ) ) { auto& metadata = getIndexMetadata( curIndex ); metadata.open = !metadata.open; - createOrUpdateColumns(); + createOrUpdateColumns( false ); } else { onOpenModelIndex( curIndex, &event ); } @@ -791,7 +791,7 @@ void UITreeView::openModelIndexParentTree( const ModelIndex& index ) { indexes.pop(); } - createOrUpdateColumns(); + createOrUpdateColumns( false ); } bool UITreeView::getFocusOnSelection() const { diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 4d210e288..0a90aaafd 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -181,6 +181,8 @@ const SizePolicy& UIWidget::getLayoutWidthPolicy() const { UIWidget* UIWidget::setLayoutWidthPolicy( const SizePolicy& widthPolicy ) { if ( mWidthPolicy != widthPolicy ) { mWidthPolicy = widthPolicy; + if ( mWidthPolicy == SizePolicy::WrapContent ) + onAutoSize(); notifyLayoutAttrChange(); } @@ -194,6 +196,8 @@ const SizePolicy& UIWidget::getLayoutHeightPolicy() const { UIWidget* UIWidget::setLayoutHeightPolicy( const SizePolicy& heightPolicy ) { if ( mHeightPolicy != heightPolicy ) { mHeightPolicy = heightPolicy; + if ( mHeightPolicy == SizePolicy::WrapContent ) + onAutoSize(); notifyLayoutAttrChange(); } @@ -205,6 +209,9 @@ UIWidget* UIWidget::setLayoutSizePolicy( const SizePolicy& widthPolicy, if ( mWidthPolicy != widthPolicy || mHeightPolicy != heightPolicy ) { mWidthPolicy = widthPolicy; mHeightPolicy = heightPolicy; + if ( mWidthPolicy == SizePolicy::WrapContent || mHeightPolicy == SizePolicy::WrapContent ) { + onAutoSize(); + } notifyLayoutAttrChange(); } diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index 64d009f58..dcd538215 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -439,7 +439,7 @@ void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* ed size_t i = 0; std::vector paths; do { - std::string val( ini.getValue( "files", String::format( "file_name_%lu", i ) ) ); + std::string val( ini.getValue( "files", String::format( "file_name_%zu", i ) ) ); found = !val.empty(); if ( found ) { auto pp = ProjectPath::fromString( val ); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 38e70063b..f0787cef5 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -378,10 +378,12 @@ void App::loadConfig( const LogLevel& logLevel ) { FileSystem::makeDir( mConfigPath ); FileSystem::dirAddSlashAtEnd( mConfigPath ); mPluginsPath = mConfigPath + "plugins"; - mColorSchemesPath = mConfigPath + "editor" + FileSystem::getOSSlash() + "colorschemes"; + mColorSchemesPath = mConfigPath + "editor" + FileSystem::getOSSlash() + "colorschemes" + + FileSystem::getOSSlash(); mTerminalManager = std::make_unique( this ); mTerminalManager->setTerminalColorSchemesPath( mConfigPath + "terminal" + - FileSystem::getOSSlash() + "colorschemes" ); + FileSystem::getOSSlash() + "colorschemes" + + FileSystem::getOSSlash() ); mTerminalManager->setUseFrameBuffer( mUseFrameBuffer ); if ( !FileSystem::fileExists( mPluginsPath ) ) @@ -3872,6 +3874,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe { "palette", 0xefc5 }, { "file-code", 0xecd1 }, { "cursor-pointer", 0xec09 }, + { "drive", 0xedf8 }, }; for ( const auto& icon : icons ) iconTheme->add( UIGlyphIcon::New( icon.first, iconFont, icon.second ) ); @@ -4007,10 +4010,13 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe if ( FileSystem::isDirectory( mColorSchemesPath ) ) { auto colorSchemesFiles = FileSystem::filesGetInPath( mColorSchemesPath ); for ( auto& file : colorSchemesFiles ) { - auto colorSchemesInFile = SyntaxColorScheme::loadFromFile( file ); + auto colorSchemesInFile = + SyntaxColorScheme::loadFromFile( mColorSchemesPath + file ); for ( auto& coloScheme : colorSchemesInFile ) colorSchemes.emplace_back( coloScheme ); } + } else { + FileSystem::makeDir( mColorSchemesPath, true ); } mTerminalManager->loadTerminalColorSchemes(); diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp index 5c81c4311..34c9a0e09 100644 --- a/src/tools/ecode/terminalmanager.cpp +++ b/src/tools/ecode/terminalmanager.cpp @@ -37,10 +37,13 @@ void TerminalManager::loadTerminalColorSchemes() { if ( FileSystem::isDirectory( mTerminalColorSchemesPath ) ) { auto colorSchemesFiles = FileSystem::filesGetInPath( mTerminalColorSchemesPath ); for ( auto& file : colorSchemesFiles ) { - auto colorSchemesInFile = TerminalColorScheme::loadFromFile( file ); + auto colorSchemesInFile = + TerminalColorScheme::loadFromFile( mTerminalColorSchemesPath + file ); for ( auto& coloScheme : colorSchemesInFile ) colorSchemes.emplace_back( coloScheme ); } + } else { + FileSystem::makeDir( mTerminalColorSchemesPath, true ); } for ( const auto& colorScheme : colorSchemes ) mTerminalColorSchemes.insert( { colorScheme.getName(), colorScheme } );