Methods UIWidget::setLayoutSizePolicy, UIWidget::setLayoutWidthPolicy, UIWidget::setLayoutHeightPolicy now trigger auto resize when changing its size policy to SizePolicy::WrapContent.

Added Sys::getLogicalDrives, implemented for Windows and Linux.
UIFileDialog now shows the local drives when no more parent folders are present (when you can't go "up" anymore).
Added DiskDrivesModel.
Replaced all strcmp with strncmp.
FileSystem::mkDir now supports recursive mkdir.
Improvements and fixes in UIAbstractTableView, UITableView and UITreeView.
Silenced use-after-free warning in the Memory Manager.
Allow use premake option "--with-debug-symbols" for Windows builds.
Closes SpartanJ/ecode#8.
This commit is contained in:
Martín Lucas Golini
2023-01-14 02:53:36 -03:00
parent cee82e080a
commit b896b3d07f
26 changed files with 442 additions and 137 deletions

View File

@@ -8,6 +8,7 @@
#include <map>
#include <string>
namespace EE {
class EE_API AllocatedPointer {
@@ -25,6 +26,8 @@ class EE_API AllocatedPointer {
typedef std::map<void*, AllocatedPointer> 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 <class T> 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 <class T> 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 <class T> 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

View File

@@ -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 );

View File

@@ -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<std::string> parseArguments( int argc, char* argv[] );
/** @return The OS logical drives */
static std::vector<std::string> getLogicalDrives();
};
}} // namespace EE::System

View File

@@ -37,7 +37,7 @@ class EE_API UIAbstractTableView : public UIAbstractView {
void setColumnHidden( const size_t& column, bool hidden );
void setColumnsHidden( const std::vector<size_t> columns, bool hidden );
void setColumnsHidden( const std::vector<size_t>& 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

View File

@@ -45,7 +45,7 @@ class EE_API UIAbstractView : public UIScrollableWidget {
bool isType( const Uint32& type ) const;
void setModel( std::shared_ptr<Model> );
void setModel( const std::shared_ptr<Model>& );
Model* getModel() { return mModel.get(); }

View File

@@ -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<DiskDrivesModel> create( const std::vector<std::string>& data );
static std::shared_ptr<DiskDrivesModel> 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<std::string>& data ) : mData( data ) {}
std::vector<std::string> mData;
};
}}} // namespace EE::UI::Models

View File

@@ -138,9 +138,9 @@ class EE_API Model {
Mutex& resourceMutex();
void acquireResourceMutex() { mResourceLock.lock(); }
void acquireResourceMutex();
void releaseResourceMutex() { mResourceLock.unlock(); }
void releaseResourceMutex();
protected:
Model(){};

View File

@@ -136,6 +136,8 @@ class EE_API UIFileDialog : public UIWindow {
KeyBindings::Shortcut mCloseShortcut;
KeyBindings::Shortcut mOpenShortut{ KEY_RETURN, KeyMod::getDefaultModifier() };
std::shared_ptr<FileSystemModel> mModel;
std::shared_ptr<DiskDrivesModel> 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

View File

@@ -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();

View File

@@ -160,7 +160,7 @@ class EE_API UITreeView : public UIAbstractTableView {
UITreeView();
virtual void createOrUpdateColumns();
virtual void createOrUpdateColumns( bool resetColumnData );
struct MetadataForIndex {
bool open{ false };

View File

@@ -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

View File

@@ -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" }

View File

@@ -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<String> 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<std::string> 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 ) );
}

View File

@@ -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;
}

View File

@@ -29,6 +29,7 @@
#undef GetTempPath
#elif EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_ANDROID
#include <libgen.h>
#include <mntent.h>
#include <unistd.h>
#elif EE_PLATFORM == EE_PLATFORM_HAIKU
#include <kernel/OS.h>
@@ -899,4 +900,60 @@ std::vector<std::string> 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<std::string> Sys::getLogicalDrives() {
#if EE_PLATFORM == EE_PLATFORM_WIN
std::vector<std::string> 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<std::string> 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

View File

@@ -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<size_t> columns, bool hidden ) {
void UIAbstractTableView::setColumnsHidden( const std::vector<size_t>& columns, bool hidden ) {
for ( auto col : columns )
columnData( col ).visible = !hidden;
createOrUpdateColumns();
updateCellsVisibility();
createOrUpdateColumns( false );
}
void UIAbstractTableView::setColumnsVisible( const std::vector<size_t> 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<size_t> 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<UITableCell>();

View File

@@ -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> model ) {
void UIAbstractView::setModel( const std::shared_ptr<Model>& model ) {
if ( model.get() == mModel.get() )
return;
if ( mModel )

View File

@@ -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> DiskDrivesModel::create( const std::vector<std::string>& data ) {
return std::shared_ptr<DiskDrivesModel>( new DiskDrivesModel( data ) );
}
std::shared_ptr<DiskDrivesModel> 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

View File

@@ -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;

View File

@@ -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<String> flist = FileSystem::filesGetInPath(
String( mCurPath ), getSortAlphabetically(), getFoldersFirst(), !getShowHidden() );
std::vector<String> files;
std::vector<std::string> 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<String> flist = FileSystem::filesGetInPath(
String( mCurPath ), getSortAlphabetically(), getFoldersFirst(), !getShowHidden() );
std::vector<String> files;
std::vector<std::string> 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 {

View File

@@ -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 ) {

View File

@@ -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 {

View File

@@ -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();
}

View File

@@ -439,7 +439,7 @@ void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* ed
size_t i = 0;
std::vector<ProjectPath> 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 );

View File

@@ -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<TerminalManager>( 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();

View File

@@ -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 } );