2021-12-11 07:10:09 +00:00
// This is an independent project of an individual developer. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/*
MIT License
Copyright ( c ) 2019 - 2020 Stephane Cuillerdier ( aka aiekick )
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
*/
# include "ImGuiFileDialog.h"
# ifdef __cplusplus
# include <cfloat>
# include <cstring> // stricmp / strcasecmp
# include <cstdarg> // variadic
# include <sstream>
# include <iomanip>
# include <ctime>
# include <sys/stat.h>
# include <cstdio>
// this option need c++17
# ifdef USE_STD_FILESYSTEM
# include <filesystem>
# endif
# if defined (__EMSCRIPTEN__) // EMSCRIPTEN
# include <emscripten.h>
# endif // EMSCRIPTEN
2022-05-07 22:29:43 +00:00
# ifdef WIN32
2021-12-11 07:10:09 +00:00
# define stat _stat
# define stricmp _stricmp
# include <cctype>
// this option need c++17
# ifdef USE_STD_FILESYSTEM
# include <Windows.h>
# else
# include "dirent/dirent.h" // directly open the dirent file attached to this lib
# endif // USE_STD_FILESYSTEM
# define PATH_SEP '\\'
# ifndef PATH_MAX
# define PATH_MAX 260
# endif // PATH_MAX
2022-07-24 03:11:30 +00:00
# elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined (__EMSCRIPTEN__) || defined(__HAIKU__)
2021-12-11 07:10:09 +00:00
# define UNIX
# define stricmp strcasecmp
# include <sys/types.h>
// this option need c++17
# ifndef USE_STD_FILESYSTEM
2022-07-24 03:11:30 +00:00
# include <dirent.h>
2021-12-11 07:10:09 +00:00
# endif // USE_STD_FILESYSTEM
# define PATH_SEP ' / '
# endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include "imgui.h"
# ifndef IMGUI_DEFINE_MATH_OPERATORS
# define IMGUI_DEFINE_MATH_OPERATORS
# endif // IMGUI_DEFINE_MATH_OPERATORS
# include "imgui_internal.h"
# include <cstdlib>
# include <algorithm>
# include <iostream>
# ifdef USE_THUMBNAILS
# ifndef DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION
# ifndef STB_IMAGE_IMPLEMENTATION
# define STB_IMAGE_IMPLEMENTATION
# endif // STB_IMAGE_IMPLEMENTATION
# endif // DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION
# include "stb/stb_image.h"
# ifndef DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION
# ifndef STB_IMAGE_RESIZE_IMPLEMENTATION
# define STB_IMAGE_RESIZE_IMPLEMENTATION
# endif // STB_IMAGE_RESIZE_IMPLEMENTATION
# endif // DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION
# include "stb/stb_image_resize.h"
# endif // USE_THUMBNAILS
namespace IGFD
{
// float comparisons
# ifndef IS_FLOAT_DIFFERENT
# define IS_FLOAT_DIFFERENT(a,b) (fabs((a) - (b)) > FLT_EPSILON)
# endif // IS_FLOAT_DIFFERENT
# ifndef IS_FLOAT_EQUAL
# define IS_FLOAT_EQUAL(a,b) (fabs((a) - (b)) < FLT_EPSILON)
# endif // IS_FLOAT_EQUAL
// width of filter combobox
# ifndef FILTER_COMBO_WIDTH
# define FILTER_COMBO_WIDTH 150.0f
# endif // FILTER_COMBO_WIDTH
// for lets you define your button widget
// if you have like me a special bi-color button
# ifndef IMGUI_PATH_BUTTON
# define IMGUI_PATH_BUTTON ImGui::Button
# endif // IMGUI_PATH_BUTTON
# ifndef IMGUI_BUTTON
# define IMGUI_BUTTON ImGui::Button
# endif // IMGUI_BUTTON
// locales
# ifndef createDirButtonString
# define createDirButtonString "+"
# endif // createDirButtonString
# ifndef okButtonString
# define okButtonString "OK"
# endif // okButtonString
# ifndef cancelButtonString
# define cancelButtonString "Cancel"
# endif // cancelButtonString
# ifndef resetButtonString
# define resetButtonString "R"
# endif // resetButtonString
# ifndef drivesButtonString
# define drivesButtonString "Drives"
# endif // drivesButtonString
# ifndef editPathButtonString
# define editPathButtonString "E"
# endif // editPathButtonString
# ifndef searchString
# define searchString "Search"
# endif // searchString
# ifndef dirEntryString
# define dirEntryString "[Dir]"
# endif // dirEntryString
# ifndef linkEntryString
# define linkEntryString "[Link]"
# endif // linkEntryString
# ifndef fileEntryString
# define fileEntryString "[File]"
# endif // fileEntryString
# ifndef fileNameString
# define fileNameString "File Name:"
# endif // fileNameString
# ifndef dirNameString
# define dirNameString "Directory Path:"
# endif // dirNameString
# ifndef buttonResetSearchString
# define buttonResetSearchString "Reset search"
# endif // buttonResetSearchString
# ifndef buttonDriveString
# define buttonDriveString "Drives"
# endif // buttonDriveString
# ifndef buttonEditPathString
# define buttonEditPathString "Edit path\nYou can also right click on path buttons"
# endif // buttonEditPathString
# ifndef buttonResetPathString
# define buttonResetPathString "Reset to current directory"
# endif // buttonResetPathString
# ifndef buttonCreateDirString
# define buttonCreateDirString "Create Directory"
# endif // buttonCreateDirString
# ifndef tableHeaderAscendingIcon
# define tableHeaderAscendingIcon "A|"
# endif // tableHeaderAscendingIcon
# ifndef tableHeaderDescendingIcon
# define tableHeaderDescendingIcon "D|"
# endif // tableHeaderDescendingIcon
# ifndef tableHeaderFileNameString
# define tableHeaderFileNameString "File name"
# endif // tableHeaderFileNameString
# ifndef tableHeaderFileTypeString
# define tableHeaderFileTypeString "Type"
# endif // tableHeaderFileTypeString
# ifndef tableHeaderFileSizeString
# define tableHeaderFileSizeString "Size"
# endif // tableHeaderFileSizeString
# ifndef tableHeaderFileDateString
# define tableHeaderFileDateString "Date"
# endif // tableHeaderFileDateString
# ifndef OverWriteDialogTitleString
# define OverWriteDialogTitleString "Warning"
# endif // OverWriteDialogTitleString
# ifndef OverWriteDialogMessageString
# define OverWriteDialogMessageString "The file you selected already exists? Would you like to overwrite it?"
# endif // OverWriteDialogMessageString
# ifndef OverWriteDialogConfirmButtonString
# define OverWriteDialogConfirmButtonString "Yes"
# endif // OverWriteDialogConfirmButtonString
# ifndef OverWriteDialogCancelButtonString
# define OverWriteDialogCancelButtonString "No"
# endif // OverWriteDialogCancelButtonString
// see strftime functionin <ctime> for customize
# ifndef DateTimeFormat
# define DateTimeFormat "%Y / %m / %d %H:%M"
# endif // DateTimeFormat
# ifdef USE_THUMBNAILS
# ifndef tableHeaderFileThumbnailsString
# define tableHeaderFileThumbnailsString "Thumbnails"
# endif // tableHeaderFileThumbnailsString
# ifndef DisplayMode_FilesList_ButtonString
# define DisplayMode_FilesList_ButtonString "FL"
# endif // DisplayMode_FilesList_ButtonString
# ifndef DisplayMode_FilesList_ButtonHelp
# define DisplayMode_FilesList_ButtonHelp "File List"
# endif // DisplayMode_FilesList_ButtonHelp
# ifndef DisplayMode_ThumbailsList_ButtonString
# define DisplayMode_ThumbailsList_ButtonString "TL"
# endif // DisplayMode_ThumbailsList_ButtonString
# ifndef DisplayMode_ThumbailsList_ButtonHelp
# define DisplayMode_ThumbailsList_ButtonHelp "Thumbnails List"
# endif // DisplayMode_ThumbailsList_ButtonHelp
# ifndef DisplayMode_ThumbailsGrid_ButtonString
# define DisplayMode_ThumbailsGrid_ButtonString "TG"
# endif // DisplayMode_ThumbailsGrid_ButtonString
# ifndef DisplayMode_ThumbailsGrid_ButtonHelp
# define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid"
# endif // DisplayMode_ThumbailsGrid_ButtonHelp
# ifndef DisplayMode_ThumbailsList_ImageHeight
# define DisplayMode_ThumbailsList_ImageHeight 32.0f
# endif // DisplayMode_ThumbailsList_ImageHeight
# ifndef IMGUI_RADIO_BUTTON
inline bool inRadioButton ( const char * vLabel , bool vToggled )
{
bool pressed = false ;
if ( vToggled )
{
ImVec4 bua = ImGui : : GetStyleColorVec4 ( ImGuiCol_ButtonActive ) ;
ImVec4 te = ImGui : : GetStyleColorVec4 ( ImGuiCol_Text ) ;
ImGui : : PushStyleColor ( ImGuiCol_Button , te ) ;
ImGui : : PushStyleColor ( ImGuiCol_ButtonActive , te ) ;
ImGui : : PushStyleColor ( ImGuiCol_ButtonHovered , te ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , bua ) ;
}
pressed = IMGUI_BUTTON ( vLabel ) ;
if ( vToggled )
{
ImGui : : PopStyleColor ( 4 ) ; //-V112
}
return pressed ;
}
# define IMGUI_RADIO_BUTTON inRadioButton
# endif // IMGUI_RADIO_BUTTON
# endif // USE_THUMBNAILS
# ifdef USE_BOOKMARK
# ifndef defaultBookmarkPaneWith
# define defaultBookmarkPaneWith 150.0f
# endif // defaultBookmarkPaneWith
# ifndef bookmarksButtonString
# define bookmarksButtonString "Bookmark"
# endif // bookmarksButtonString
# ifndef bookmarksButtonHelpString
# define bookmarksButtonHelpString "Bookmark"
# endif // bookmarksButtonHelpString
# ifndef addBookmarkButtonString
# define addBookmarkButtonString "+"
# endif // addBookmarkButtonString
# ifndef removeBookmarkButtonString
# define removeBookmarkButtonString "-"
# endif // removeBookmarkButtonString
# ifndef IMGUI_TOGGLE_BUTTON
inline bool inToggleButton ( const char * vLabel , bool * vToggled )
{
bool pressed = false ;
if ( vToggled & & * vToggled )
{
ImVec4 bua = ImGui : : GetStyleColorVec4 ( ImGuiCol_ButtonActive ) ;
//ImVec4 buh = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
//ImVec4 bu = ImGui::GetStyleColorVec4(ImGuiCol_Button);
ImVec4 te = ImGui : : GetStyleColorVec4 ( ImGuiCol_Text ) ;
ImGui : : PushStyleColor ( ImGuiCol_Button , te ) ;
ImGui : : PushStyleColor ( ImGuiCol_ButtonActive , te ) ;
ImGui : : PushStyleColor ( ImGuiCol_ButtonHovered , te ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , bua ) ;
}
pressed = IMGUI_BUTTON ( vLabel ) ;
if ( vToggled & & * vToggled )
{
ImGui : : PopStyleColor ( 4 ) ; //-V112
}
if ( vToggled & & pressed )
* vToggled = ! * vToggled ;
return pressed ;
}
# define IMGUI_TOGGLE_BUTTON inToggleButton
# endif // IMGUI_TOGGLE_BUTTON
# endif // USE_BOOKMARK
/////////////////////////////////////////////////////////////////////////////////////
//// INLINE FUNCTIONS ///////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
# ifndef USE_STD_FILESYSTEM
inline int inAlphaSort ( const struct dirent * * a , const struct dirent * * b )
{
return strcoll ( ( * a ) - > d_name , ( * b ) - > d_name ) ;
}
# endif
/////////////////////////////////////////////////////////////////////////////////////
//// FILE EXTENTIONS INFOS //////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
IGFD : : FileStyle : : FileStyle ( )
: color ( 0 , 0 , 0 , 0 )
{
}
IGFD : : FileStyle : : FileStyle ( const FileStyle & vStyle )
{
color = vStyle . color ;
icon = vStyle . icon ;
font = vStyle . font ;
flags = vStyle . flags ;
}
IGFD : : FileStyle : : FileStyle ( const ImVec4 & vColor , const std : : string & vIcon , ImFont * vFont )
: color ( vColor ) , icon ( vIcon ) , font ( vFont )
{
}
/////////////////////////////////////////////////////////////////////////////////////
//// FILE INFOS /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// https://github.com/ocornut/imgui/issues/1720
bool IGFD : : Utils : : Splitter ( bool split_vertically , float thickness , float * size1 , float * size2 , float min_size1 , float min_size2 , float splitter_long_axis_size )
{
using namespace ImGui ;
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
ImGuiID id = window - > GetID ( " ##Splitter " ) ;
ImRect bb ;
bb . Min = window - > DC . CursorPos + ( split_vertically ? ImVec2 ( * size1 , 0.0f ) : ImVec2 ( 0.0f , * size1 ) ) ;
bb . Max = bb . Min + CalcItemSize ( split_vertically ? ImVec2 ( thickness , splitter_long_axis_size ) : ImVec2 ( splitter_long_axis_size , thickness ) , 0.0f , 0.0f ) ;
return SplitterBehavior ( bb , id , split_vertically ? ImGuiAxis_X : ImGuiAxis_Y , size1 , size2 , min_size1 , min_size2 , 1.0f ) ;
}
# ifdef WIN32
bool IGFD : : Utils : : WReplaceString ( std : : wstring & str , const std : : wstring & oldStr , const std : : wstring & newStr )
{
bool found = false ;
size_t pos = 0 ;
while ( ( pos = str . find ( oldStr , pos ) ) ! = std : : wstring : : npos )
{
found = true ;
str . replace ( pos , oldStr . length ( ) , newStr ) ;
pos + = newStr . length ( ) ;
}
return found ;
}
std : : vector < std : : wstring > IGFD : : Utils : : WSplitStringToVector ( const std : : wstring & text , char delimiter , bool pushEmpty )
{
std : : vector < std : : wstring > arr ;
if ( ! text . empty ( ) )
{
std : : wstring : : size_type start = 0 ;
std : : wstring : : size_type end = text . find ( delimiter , start ) ;
while ( end ! = std : : wstring : : npos )
{
std : : wstring token = text . substr ( start , end - start ) ;
if ( ! token . empty ( ) | | ( token . empty ( ) & & pushEmpty ) ) //-V728
arr . push_back ( token ) ;
start = end + 1 ;
end = text . find ( delimiter , start ) ;
}
std : : wstring token = text . substr ( start ) ;
if ( ! token . empty ( ) | | ( token . empty ( ) & & pushEmpty ) ) //-V728
arr . push_back ( token ) ;
}
return arr ;
}
std : : wstring IGFD : : Utils : : string_to_wstring ( const std : : string & str )
{
std : : wstring ret ;
if ( ! str . empty ( ) )
{
size_t sz = std : : mbstowcs ( nullptr , str . c_str ( ) , str . size ( ) ) ;
if ( sz )
{
ret . resize ( sz ) ;
std : : mbstowcs ( ( wchar_t * ) ret . data ( ) , str . c_str ( ) , sz ) ;
}
}
return ret ;
}
std : : string IGFD : : Utils : : wstring_to_string ( const std : : wstring & str )
{
std : : string ret ;
if ( ! str . empty ( ) )
{
size_t sz = std : : wcstombs ( nullptr , str . c_str ( ) , str . size ( ) ) ;
if ( sz )
{
ret . resize ( sz ) ;
std : : wcstombs ( ( char * ) ret . data ( ) , str . c_str ( ) , sz ) ;
}
}
return ret ;
}
# endif // WIN32
bool IGFD : : Utils : : ReplaceString ( std : : string & str , const std : : string & oldStr , const std : : string & newStr )
{
bool found = false ;
size_t pos = 0 ;
while ( ( pos = str . find ( oldStr , pos ) ) ! = std : : string : : npos )
{
found = true ;
str . replace ( pos , oldStr . length ( ) , newStr ) ;
pos + = newStr . length ( ) ;
}
return found ;
}
std : : vector < std : : string > IGFD : : Utils : : SplitStringToVector ( const std : : string & text , char delimiter , bool pushEmpty )
{
std : : vector < std : : string > arr ;
if ( ! text . empty ( ) )
{
size_t start = 0 ;
size_t end = text . find ( delimiter , start ) ;
while ( end ! = std : : string : : npos )
{
auto token = text . substr ( start , end - start ) ;
if ( ! token . empty ( ) | | ( token . empty ( ) & & pushEmpty ) ) //-V728
arr . push_back ( token ) ;
start = end + 1 ;
end = text . find ( delimiter , start ) ;
}
auto token = text . substr ( start ) ;
if ( ! token . empty ( ) | | ( token . empty ( ) & & pushEmpty ) ) //-V728
arr . push_back ( token ) ;
}
return arr ;
}
std : : vector < std : : string > IGFD : : Utils : : GetDrivesList ( )
{
std : : vector < std : : string > res ;
# ifdef WIN32
const DWORD mydrives = 2048 ;
char lpBuffer [ 2048 ] ;
# define mini(a,b) (((a) < (b)) ? (a) : (b))
const DWORD countChars = mini ( GetLogicalDriveStringsA ( mydrives , lpBuffer ) , 2047 ) ;
# undef mini
if ( countChars > 0 )
{
std : : string var = std : : string ( lpBuffer , ( size_t ) countChars ) ;
IGFD : : Utils : : ReplaceString ( var , " \\ " , " " ) ;
res = IGFD : : Utils : : SplitStringToVector ( var , ' \0 ' , false ) ;
}
# endif // WIN32
return res ;
}
bool IGFD : : Utils : : IsDirectoryExist ( const std : : string & name )
{
bool bExists = false ;
if ( ! name . empty ( ) )
{
# ifdef USE_STD_FILESYSTEM
namespace fs = std : : filesystem ;
# ifdef WIN32
std : : wstring wname = IGFD : : Utils : : string_to_wstring ( name . c_str ( ) ) ;
fs : : path pathName = fs : : path ( wname ) ;
# else
fs : : path pathName = fs : : path ( name ) ;
# endif
bExists = fs : : is_directory ( pathName ) ;
# else
DIR * pDir = nullptr ;
pDir = opendir ( name . c_str ( ) ) ;
if ( pDir ! = nullptr )
{
bExists = true ;
( void ) closedir ( pDir ) ;
}
# endif // USE_STD_FILESYSTEM
}
return bExists ; // this is not a directory!
}
bool IGFD : : Utils : : CreateDirectoryIfNotExist ( const std : : string & name )
{
bool res = false ;
if ( ! name . empty ( ) )
{
if ( ! IsDirectoryExist ( name ) )
{
# ifdef WIN32
# ifdef USE_STD_FILESYSTEM
namespace fs = std : : filesystem ;
std : : wstring wname = IGFD : : Utils : : string_to_wstring ( name . c_str ( ) ) ;
fs : : path pathName = fs : : path ( wname ) ;
res = fs : : create_directory ( pathName ) ;
# else
std : : wstring wname = IGFD : : Utils : : string_to_wstring ( name ) ;
if ( CreateDirectoryW ( wname . c_str ( ) , nullptr ) )
{
res = true ;
}
# endif // USE_STD_FILESYSTEM
# elif defined(__EMSCRIPTEN__)
std : : string str = std : : string ( " FS.mkdir(' " ) + name + " '); " ;
emscripten_run_script ( str . c_str ( ) ) ;
res = true ;
# elif defined(UNIX)
char buffer [ PATH_MAX ] = { } ;
snprintf ( buffer , PATH_MAX , " mkdir -p %s " , name . c_str ( ) ) ;
const int dir_err = std : : system ( buffer ) ;
if ( dir_err ! = - 1 )
{
res = true ;
}
# endif // WIN32
if ( ! res ) {
std : : cout < < " Error creating directory " < < name < < std : : endl ;
}
}
}
return res ;
}
# ifdef USE_STD_FILESYSTEM
// https://github.com/aiekick/ImGuiFileDialog/issues/54
IGFD : : Utils : : PathStruct IGFD : : Utils : : ParsePathFileName ( const std : : string & vPathFileName )
{
namespace fs = std : : filesystem ;
PathStruct res ;
if ( vPathFileName . empty ( ) )
return res ;
auto fsPath = fs : : path ( vPathFileName ) ;
if ( fs : : is_regular_file ( fsPath ) ) {
res . name = fsPath . string ( ) ;
res . path = fsPath . parent_path ( ) . string ( ) ;
res . isOk = true ;
}
return res ;
}
# else
IGFD : : Utils : : PathStruct IGFD : : Utils : : ParsePathFileName ( const std : : string & vPathFileName )
{
PathStruct res ;
if ( ! vPathFileName . empty ( ) )
{
std : : string pfn = vPathFileName ;
std : : string separator ( 1u , PATH_SEP ) ;
IGFD : : Utils : : ReplaceString ( pfn , " \\ " , separator ) ;
IGFD : : Utils : : ReplaceString ( pfn , " / " , separator ) ;
size_t lastSlash = pfn . find_last_of ( separator ) ;
if ( lastSlash ! = std : : string : : npos )
{
res . name = pfn . substr ( lastSlash + 1 ) ;
res . path = pfn . substr ( 0 , lastSlash ) ;
res . isOk = true ;
}
size_t lastPoint = pfn . find_last_of ( ' . ' ) ;
if ( lastPoint ! = std : : string : : npos )
{
if ( ! res . isOk )
{
res . name = pfn ;
res . isOk = true ;
}
res . ext = pfn . substr ( lastPoint + 1 ) ;
IGFD : : Utils : : ReplaceString ( res . name , " . " + res . ext , " " ) ;
}
if ( ! res . isOk )
{
res . name = std : : move ( pfn ) ;
res . isOk = true ;
}
}
return res ;
}
# endif // USE_STD_FILESYSTEM
void IGFD : : Utils : : AppendToBuffer ( char * vBuffer , size_t vBufferLen , const std : : string & vStr )
{
std : : string st = vStr ;
size_t len = vBufferLen - 1u ;
size_t slen = strlen ( vBuffer ) ;
if ( ! st . empty ( ) & & st ! = " \n " )
{
IGFD : : Utils : : ReplaceString ( st , " \n " , " " ) ;
IGFD : : Utils : : ReplaceString ( st , " \r " , " " ) ;
}
vBuffer [ slen ] = ' \0 ' ;
std : : string str = std : : string ( vBuffer ) ;
//if (!str.empty()) str += "\n";
str + = vStr ;
if ( len > str . size ( ) ) len = str . size ( ) ;
# ifdef MSVC
strncpy_s ( vBuffer , vBufferLen , str . c_str ( ) , len ) ;
# else // MSVC
strncpy ( vBuffer , str . c_str ( ) , len ) ;
# endif // MSVC
vBuffer [ len ] = ' \0 ' ;
}
void IGFD : : Utils : : ResetBuffer ( char * vBuffer )
{
vBuffer [ 0 ] = ' \0 ' ;
}
void IGFD : : Utils : : SetBuffer ( char * vBuffer , size_t vBufferLen , const std : : string & vStr )
{
ResetBuffer ( vBuffer ) ;
AppendToBuffer ( vBuffer , vBufferLen , vStr ) ;
}
/////////////////////////////////////////////////////////////////////////////////////
//// FILE INFOS /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
bool IGFD : : FileInfos : : IsTagFound ( const std : : string & vTag ) const
{
if ( ! vTag . empty ( ) )
{
if ( fileNameExt_optimized = = " .. " ) return true ;
return
fileNameExt_optimized . find ( vTag ) ! = std : : string : : npos | | // first try wihtout case and accents
fileNameExt . find ( vTag ) ! = std : : string : : npos ; // second if searched with case and accents
}
// if tag is empty => its a special case but all is found
return true ;
}
/////////////////////////////////////////////////////////////////////////////////////
//// SEARCH MANAGER /////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void IGFD : : SearchManager : : Clear ( )
{
puSearchTag . clear ( ) ;
IGFD : : Utils : : ResetBuffer ( puSearchBuffer ) ;
}
void IGFD : : SearchManager : : DrawSearchBar ( FileDialogInternal & vFileDialogInternal )
{
// search field
if ( IMGUI_BUTTON ( resetButtonString " ##BtnImGuiFileDialogSearchField " ) )
{
Clear ( ) ;
vFileDialogInternal . puFileManager . ApplyFilteringOnFileList ( vFileDialogInternal ) ;
}
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( buttonResetSearchString ) ;
ImGui : : SameLine ( ) ;
ImGui : : Text ( searchString ) ;
ImGui : : SameLine ( ) ;
ImGui : : PushItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
bool edited = ImGui : : InputText ( " ##InputImGuiFileDialogSearchField " , puSearchBuffer , MAX_FILE_DIALOG_NAME_BUFFER ) ;
if ( ImGui : : GetItemID ( ) = = ImGui : : GetActiveID ( ) )
puSearchInputIsActive = true ;
ImGui : : PopItemWidth ( ) ;
if ( edited )
{
puSearchTag = puSearchBuffer ;
vFileDialogInternal . puFileManager . ApplyFilteringOnFileList ( vFileDialogInternal ) ;
}
}
/////////////////////////////////////////////////////////////////////////////////////
//// FILTER INFOS ///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void IGFD : : FilterManager : : FilterInfos : : clear ( )
{
filter . clear ( ) ;
collectionfilters . clear ( ) ;
}
bool IGFD : : FilterManager : : FilterInfos : : empty ( ) const
{
return filter . empty ( ) & & collectionfilters . empty ( ) ;
}
bool IGFD : : FilterManager : : FilterInfos : : exist ( const std : : string & vFilter ) const
{
return filter = = vFilter | | ( collectionfilters . find ( vFilter ) ! = collectionfilters . end ( ) ) ;
}
/////////////////////////////////////////////////////////////////////////////////////
//// FILTER MANAGER /////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void IGFD : : FilterManager : : ParseFilters ( const char * vFilters )
{
prParsedFilters . clear ( ) ;
if ( vFilters )
puDLGFilters = vFilters ; // file mode
else
puDLGFilters . clear ( ) ; // directory mode
if ( ! puDLGFilters . empty ( ) )
{
// ".*,.cpp,.h,.hpp"
// "Source files{.cpp,.h,.hpp},Image files{.png,.gif,.jpg,.jpeg},.md"
bool currentFilterFound = false ;
size_t nan = std : : string : : npos ;
size_t p = 0 , lp = 0 ;
while ( ( p = puDLGFilters . find_first_of ( " {, " , p ) ) ! = nan )
{
FilterInfos infos ;
if ( puDLGFilters [ p ] = = ' { ' ) // {
{
infos . filter = puDLGFilters . substr ( lp , p - lp ) ;
p + + ;
lp = puDLGFilters . find ( ' } ' , p ) ;
if ( lp ! = nan )
{
std : : string fs = puDLGFilters . substr ( p , lp - p ) ;
auto arr = IGFD : : Utils : : SplitStringToVector ( fs , ' , ' , false ) ;
for ( auto a : arr )
{
infos . collectionfilters . emplace ( a ) ;
}
}
p = lp + 1 ;
}
else // ,
{
infos . filter = puDLGFilters . substr ( lp , p - lp ) ;
p + + ;
}
if ( ! currentFilterFound & & prSelectedFilter . filter = = infos . filter )
{
currentFilterFound = true ;
prSelectedFilter = infos ;
}
lp = p ;
if ( ! infos . empty ( ) )
prParsedFilters . emplace_back ( infos ) ;
}
std : : string token = puDLGFilters . substr ( lp ) ;
if ( ! token . empty ( ) )
{
FilterInfos infos ;
infos . filter = std : : move ( token ) ;
prParsedFilters . emplace_back ( infos ) ;
}
if ( ! currentFilterFound )
if ( ! prParsedFilters . empty ( ) )
prSelectedFilter = * prParsedFilters . begin ( ) ;
}
}
void IGFD : : FilterManager : : SetSelectedFilterWithExt ( const std : : string & vFilter )
{
if ( ! prParsedFilters . empty ( ) )
{
if ( ! vFilter . empty ( ) )
{
// std::map<std::string, FilterInfos>
for ( const auto & infos : prParsedFilters )
{
if ( vFilter = = infos . filter )
{
prSelectedFilter = infos ;
}
else
{
// maybe this ext is in an extention so we will
// explore the collections is they are existing
for ( const auto & filter : infos . collectionfilters )
{
if ( vFilter = = filter )
{
prSelectedFilter = infos ;
}
}
}
}
}
if ( prSelectedFilter . empty ( ) )
prSelectedFilter = * prParsedFilters . begin ( ) ;
}
}
void IGFD : : FilterManager : : SetFileStyle ( const IGFD_FileStyleFlags & vFlags , const char * vCriteria , const FileStyle & vInfos )
{
std : : string _criteria ;
if ( vCriteria )
_criteria = std : : string ( vCriteria ) ;
prFilesStyle [ vFlags ] [ _criteria ] = std : : make_shared < FileStyle > ( vInfos ) ;
prFilesStyle [ vFlags ] [ _criteria ] - > flags = vFlags ;
}
// will be called internally
// will not been exposed to IGFD API
bool IGFD : : FilterManager : : prFillFileStyle ( std : : shared_ptr < FileInfos > vFileInfos ) const
{
if ( vFileInfos . use_count ( ) & & ! prFilesStyle . empty ( ) )
{
for ( const auto & _flag : prFilesStyle )
{
for ( const auto & _file : _flag . second )
{
if ( _flag . first & IGFD_FileStyleByTypeDir & & vFileInfos - > fileType = = ' d ' )
{
if ( _file . first . empty ( ) ) // for all dirs
{
vFileInfos - > fileStyle = _file . second ;
}
else if ( _file . first = = vFileInfos - > fileNameExt ) // for dirs who are equal to style criteria
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeFile & & vFileInfos - > fileType = = ' f ' )
{
if ( _file . first . empty ( ) ) // for all files
{
vFileInfos - > fileStyle = _file . second ;
}
else if ( _file . first = = vFileInfos - > fileNameExt ) // for files who are equal to style criteria
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeLink & & vFileInfos - > fileType = = ' l ' )
{
if ( _file . first . empty ( ) ) // for all links
{
vFileInfos - > fileStyle = _file . second ;
}
else if ( _file . first = = vFileInfos - > fileNameExt ) // for links who are equal to style criteria
{
vFileInfos - > fileStyle = _file . second ;
}
}
if ( _flag . first & IGFD_FileStyleByExtention )
{
if ( _file . first = = vFileInfos - > fileExt )
{
vFileInfos - > fileStyle = _file . second ;
}
// can make sense for some dirs like the hidden by ex ".git"
if ( _flag . first & IGFD_FileStyleByTypeDir & & vFileInfos - > fileType = = ' d ' )
{
if ( _file . first = = vFileInfos - > fileExt )
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeFile & & vFileInfos - > fileType = = ' f ' )
{
if ( _file . first = = vFileInfos - > fileExt )
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeLink & & vFileInfos - > fileType = = ' l ' )
{
if ( _file . first = = vFileInfos - > fileExt )
{
vFileInfos - > fileStyle = _file . second ;
}
}
}
if ( _flag . first & IGFD_FileStyleByFullName )
{
if ( _file . first = = vFileInfos - > fileNameExt )
{
vFileInfos - > fileStyle = _file . second ;
}
if ( _flag . first & IGFD_FileStyleByTypeDir & & vFileInfos - > fileType = = ' d ' )
{
if ( _file . first = = vFileInfos - > fileNameExt )
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeFile & & vFileInfos - > fileType = = ' f ' )
{
if ( _file . first = = vFileInfos - > fileNameExt )
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeLink & & vFileInfos - > fileType = = ' l ' )
{
if ( _file . first = = vFileInfos - > fileNameExt )
{
vFileInfos - > fileStyle = _file . second ;
}
}
}
if ( _flag . first & IGFD_FileStyleByContainedInFullName )
{
if ( vFileInfos - > fileNameExt . find ( _file . first ) ! = std : : string : : npos )
{
vFileInfos - > fileStyle = _file . second ;
}
if ( _flag . first & IGFD_FileStyleByTypeDir & & vFileInfos - > fileType = = ' d ' )
{
if ( vFileInfos - > fileNameExt . find ( _file . first ) ! = std : : string : : npos )
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeFile & & vFileInfos - > fileType = = ' f ' )
{
if ( vFileInfos - > fileNameExt . find ( _file . first ) ! = std : : string : : npos )
{
vFileInfos - > fileStyle = _file . second ;
}
}
else if ( _flag . first & IGFD_FileStyleByTypeLink & & vFileInfos - > fileType = = ' l ' )
{
if ( vFileInfos - > fileNameExt . find ( _file . first ) ! = std : : string : : npos )
{
vFileInfos - > fileStyle = _file . second ;
}
}
}
if ( vFileInfos - > fileStyle . use_count ( ) )
return true ;
}
}
}
return false ;
}
void IGFD : : FilterManager : : SetFileStyle ( const IGFD_FileStyleFlags & vFlags , const char * vCriteria , const ImVec4 & vColor , const std : : string & vIcon , ImFont * vFont )
{
std : : string _criteria ;
if ( vCriteria )
_criteria = std : : string ( vCriteria ) ;
prFilesStyle [ vFlags ] [ _criteria ] = std : : make_shared < FileStyle > ( vColor , vIcon , vFont ) ;
prFilesStyle [ vFlags ] [ _criteria ] - > flags = vFlags ;
}
// todo : to refactor this fucking function
bool IGFD : : FilterManager : : GetFileStyle ( const IGFD_FileStyleFlags & vFlags , const std : : string & vCriteria , ImVec4 * vOutColor , std : : string * vOutIcon , ImFont * * vOutFont )
{
if ( vOutColor )
{
if ( ! prFilesStyle . empty ( ) )
{
if ( prFilesStyle . find ( vFlags ) ! = prFilesStyle . end ( ) ) // found
{
if ( vFlags & IGFD_FileStyleByContainedInFullName )
{
// search for vCriteria who are containing the criteria
for ( const auto & _file : prFilesStyle . at ( vFlags ) )
{
if ( vCriteria . find ( _file . first ) ! = std : : string : : npos )
{
if ( _file . second . use_count ( ) )
{
* vOutColor = _file . second - > color ;
if ( vOutIcon )
* vOutIcon = _file . second - > icon ;
if ( vOutFont )
* vOutFont = _file . second - > font ;
return true ;
}
}
}
}
else
{
if ( prFilesStyle . at ( vFlags ) . find ( vCriteria ) ! = prFilesStyle . at ( vFlags ) . end ( ) ) // found
{
* vOutColor = prFilesStyle [ vFlags ] [ vCriteria ] - > color ;
if ( vOutIcon )
* vOutIcon = prFilesStyle [ vFlags ] [ vCriteria ] - > icon ;
if ( vOutFont )
* vOutFont = prFilesStyle [ vFlags ] [ vCriteria ] - > font ;
return true ;
}
}
}
else
{
// search for flag composition
for ( const auto & _flag : prFilesStyle )
{
if ( _flag . first & vFlags )
{
if ( _flag . first & IGFD_FileStyleByContainedInFullName )
{
// search for vCriteria who are containing the criteria
for ( const auto & _file : prFilesStyle . at ( _flag . first ) )
{
if ( vCriteria . find ( _file . first ) ! = std : : string : : npos )
{
if ( _file . second . use_count ( ) )
{
* vOutColor = _file . second - > color ;
if ( vOutIcon )
* vOutIcon = _file . second - > icon ;
if ( vOutFont )
* vOutFont = _file . second - > font ;
return true ;
}
}
}
}
else
{
if ( prFilesStyle . at ( _flag . first ) . find ( vCriteria ) ! = prFilesStyle . at ( _flag . first ) . end ( ) ) // found
{
* vOutColor = prFilesStyle [ _flag . first ] [ vCriteria ] - > color ;
if ( vOutIcon )
* vOutIcon = prFilesStyle [ _flag . first ] [ vCriteria ] - > icon ;
if ( vOutFont )
* vOutFont = prFilesStyle [ _flag . first ] [ vCriteria ] - > font ;
return true ;
}
}
}
}
}
}
}
return false ;
}
void IGFD : : FilterManager : : ClearFilesStyle ( )
{
prFilesStyle . clear ( ) ;
}
bool IGFD : : FilterManager : : IsCoveredByFilters ( const std : : string & vTag ) const
{
if ( ! puDLGFilters . empty ( ) & & ! prSelectedFilter . empty ( ) )
{
// check if current file extention is covered by current filter
// we do that here, for avoid doing that during filelist display
// for better fps
if ( prSelectedFilter . exist ( vTag ) | | prSelectedFilter . filter = = " .* " )
{
return true ;
}
}
return false ;
}
bool IGFD : : FilterManager : : DrawFilterComboBox ( FileDialogInternal & vFileDialogInternal )
{
// combobox of filters
if ( ! puDLGFilters . empty ( ) )
{
ImGui : : SameLine ( ) ;
bool needToApllyNewFilter = false ;
2022-02-23 03:41:37 +00:00
ImGui : : PushItemWidth ( FILTER_COMBO_WIDTH * FileDialog : : Instance ( ) - > DpiScale ) ;
2021-12-11 07:10:09 +00:00
if ( ImGui : : BeginCombo ( " ##Filters " , prSelectedFilter . filter . c_str ( ) , ImGuiComboFlags_None ) )
{
intptr_t i = 0 ;
for ( const auto & filter : prParsedFilters )
{
const bool item_selected = ( filter . filter = = prSelectedFilter . filter ) ;
ImGui : : PushID ( ( void * ) ( intptr_t ) i + + ) ;
if ( ImGui : : Selectable ( filter . filter . c_str ( ) , item_selected ) )
{
prSelectedFilter = filter ;
needToApllyNewFilter = true ;
}
ImGui : : PopID ( ) ;
}
ImGui : : EndCombo ( ) ;
}
ImGui : : PopItemWidth ( ) ;
if ( needToApllyNewFilter )
{
vFileDialogInternal . puFileManager . OpenCurrentPath ( vFileDialogInternal ) ;
}
return needToApllyNewFilter ;
}
return false ;
}
IGFD : : FilterManager : : FilterInfos IGFD : : FilterManager : : GetSelectedFilter ( )
{
return prSelectedFilter ;
}
std : : string IGFD : : FilterManager : : ReplaceExtentionWithCurrentFilter ( const std : : string & vFile ) const
{
auto result = vFile ;
if ( ! result . empty ( ) )
{
// if not a collection we can replace the filter by the extention we want
if ( prSelectedFilter . collectionfilters . empty ( ) )
{
size_t lastPoint = vFile . find_last_of ( ' . ' ) ;
if ( lastPoint ! = std : : string : : npos )
{
result = result . substr ( 0 , lastPoint ) ;
}
result + = prSelectedFilter . filter ;
}
}
return result ;
}
void IGFD : : FilterManager : : SetDefaultFilterIfNotDefined ( )
{
if ( prSelectedFilter . empty ( ) & & // no filter selected
! prParsedFilters . empty ( ) ) // filter exist
prSelectedFilter = * prParsedFilters . begin ( ) ; // we take the first filter
}
/////////////////////////////////////////////////////////////////////////////////////
//// FILE MANAGER ///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
IGFD : : FileManager : : FileManager ( )
{
puFsRoot = std : : string ( 1u , PATH_SEP ) ;
puSortingDirection [ 0 ] = false ;
puSortingDirection [ 1 ] = false ;
puSortingDirection [ 2 ] = false ;
puSortingDirection [ 3 ] = false ;
}
void IGFD : : FileManager : : OpenCurrentPath ( const FileDialogInternal & vFileDialogInternal )
{
puShowDrives = false ;
ClearComposer ( ) ;
ClearFileLists ( ) ;
if ( puDLGDirectoryMode ) // directory mode
SetDefaultFileName ( " . " ) ;
else
SetDefaultFileName ( puDLGDefaultFileName ) ;
ScanDir ( vFileDialogInternal , GetCurrentPath ( ) ) ;
}
void IGFD : : FileManager : : SortFields ( const FileDialogInternal & vFileDialogInternal , const SortingFieldEnum & vSortingField , const bool vCanChangeOrder )
{
if ( vSortingField ! = SortingFieldEnum : : FIELD_NONE )
{
puHeaderFileName = tableHeaderFileNameString ;
puHeaderFileType = tableHeaderFileTypeString ;
puHeaderFileSize = tableHeaderFileSizeString ;
puHeaderFileDate = tableHeaderFileDateString ;
# ifdef USE_THUMBNAILS
puHeaderFileThumbnails = tableHeaderFileThumbnailsString ;
# endif // #ifdef USE_THUMBNAILS
}
if ( vSortingField = = SortingFieldEnum : : FIELD_FILENAME )
{
if ( vCanChangeOrder & & puSortingField = = vSortingField ) {
//printf("Change the sorting\n");
puSortingDirection [ 0 ] = true ; //!puSortingDirection[0];
}
if ( puSortingDirection [ 0 ] )
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileName = tableHeaderDescendingIcon + puHeaderFileName ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
// this code fail in c:\\Users with the link "All users". got a invalid comparator
/*
// use code from https://github.com/jackm97/ImGuiFileDialog/commit/bf40515f5a1de3043e60562dc1a494ee7ecd3571
// strict ordering for file/directory types beginning in '.'
// common on Linux platforms
if ( a - > fileNameExt [ 0 ] = = ' . ' & & b - > fileNameExt [ 0 ] ! = ' . ' )
return false ;
if ( a - > fileNameExt [ 0 ] ! = ' . ' & & b - > fileNameExt [ 0 ] = = ' . ' )
return true ;
if ( a - > fileNameExt [ 0 ] = = ' . ' & & b - > fileNameExt [ 0 ] = = ' . ' )
{
return ( stricmp ( a - > fileNameExt . c_str ( ) , b - > fileNameExt . c_str ( ) ) < 0 ) ; // sort in insensitive case
}
*/
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType = = ' d ' ) ; // directory in first
return ( stricmp ( a - > fileNameExt . c_str ( ) , b - > fileNameExt . c_str ( ) ) < 0 ) ; // sort in insensitive case
} ) ;
}
else
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileName = tableHeaderAscendingIcon + puHeaderFileName ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
// this code fail in c:\\Users with the link "All users". got a invalid comparator
/*
// use code from https://github.com/jackm97/ImGuiFileDialog/commit/bf40515f5a1de3043e60562dc1a494ee7ecd3571
// strict ordering for file/directory types beginning in '.'
// common on Linux platforms
if ( a - > fileNameExt [ 0 ] = = ' . ' & & b - > fileNameExt [ 0 ] ! = ' . ' )
return false ;
if ( a - > fileNameExt [ 0 ] ! = ' . ' & & b - > fileNameExt [ 0 ] = = ' . ' )
return true ;
if ( a - > fileNameExt [ 0 ] = = ' . ' & & b - > fileNameExt [ 0 ] = = ' . ' )
{
return ( stricmp ( a - > fileNameExt . c_str ( ) , b - > fileNameExt . c_str ( ) ) > 0 ) ; // sort in insensitive case
}
*/
return ( stricmp ( a - > fileNameExt . c_str ( ) , b - > fileNameExt . c_str ( ) ) > 0 ) ; // sort in insensitive case
} ) ;
}
}
else if ( vSortingField = = SortingFieldEnum : : FIELD_TYPE )
{
if ( vCanChangeOrder & & puSortingField = = vSortingField )
puSortingDirection [ 1 ] = ! puSortingDirection [ 1 ] ;
if ( puSortingDirection [ 1 ] )
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileType = tableHeaderDescendingIcon + puHeaderFileType ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType = = ' d ' ) ; // directory in first
return ( a - > fileExt < b - > fileExt ) ; // else
} ) ;
}
else
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileType = tableHeaderAscendingIcon + puHeaderFileType ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType ! = ' d ' ) ; // directory in last
return ( a - > fileExt > b - > fileExt ) ; // else
} ) ;
}
}
else if ( vSortingField = = SortingFieldEnum : : FIELD_SIZE )
{
if ( vCanChangeOrder & & puSortingField = = vSortingField )
puSortingDirection [ 2 ] = ! puSortingDirection [ 2 ] ;
if ( puSortingDirection [ 2 ] )
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileSize = tableHeaderDescendingIcon + puHeaderFileSize ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType = = ' d ' ) ; // directory in first
return ( a - > fileSize < b - > fileSize ) ; // else
} ) ;
}
else
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileSize = tableHeaderAscendingIcon + puHeaderFileSize ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType ! = ' d ' ) ; // directory in last
return ( a - > fileSize > b - > fileSize ) ; // else
} ) ;
}
}
else if ( vSortingField = = SortingFieldEnum : : FIELD_DATE )
{
if ( vCanChangeOrder & & puSortingField = = vSortingField )
puSortingDirection [ 3 ] = ! puSortingDirection [ 3 ] ;
if ( puSortingDirection [ 3 ] )
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileDate = tableHeaderDescendingIcon + puHeaderFileDate ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType = = ' d ' ) ; // directory in first
return ( a - > fileModifDate < b - > fileModifDate ) ; // else
} ) ;
}
else
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileDate = tableHeaderAscendingIcon + puHeaderFileDate ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
2022-05-25 05:10:01 +00:00
if ( a = = NULL | | b = = NULL )
return false ;
2021-12-11 07:10:09 +00:00
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType ! = ' d ' ) ; // directory in last
return ( a - > fileModifDate > b - > fileModifDate ) ; // else
} ) ;
}
}
# ifdef USE_THUMBNAILS
else if ( vSortingField = = SortingFieldEnum : : FIELD_THUMBNAILS )
{
if ( vCanChangeOrder & & puSortingField = = vSortingField )
puSortingDirection [ 4 ] = ! puSortingDirection [ 4 ] ;
// we will compare thumbnails by :
// 1) width
// 2) height
if ( puSortingDirection [ 4 ] )
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileThumbnails = tableHeaderDescendingIcon + puHeaderFileThumbnails ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType = = ' d ' ) ; // directory in first
if ( a - > thumbnailInfo . textureWidth = = b - > thumbnailInfo . textureWidth )
return ( a - > thumbnailInfo . textureHeight < b - > thumbnailInfo . textureHeight ) ;
return ( a - > thumbnailInfo . textureWidth < b - > thumbnailInfo . textureWidth ) ;
} ) ;
}
else
{
# ifdef USE_CUSTOM_SORTING_ICON
puHeaderFileThumbnails = tableHeaderAscendingIcon + puHeaderFileThumbnails ;
# endif // USE_CUSTOM_SORTING_ICON
std : : sort ( prFileList . begin ( ) , prFileList . end ( ) ,
[ ] ( const std : : shared_ptr < FileInfos > & a , const std : : shared_ptr < FileInfos > & b ) - > bool
{
if ( ! a . use_count ( ) | | ! b . use_count ( ) )
return false ;
if ( a - > fileType ! = b - > fileType ) return ( a - > fileType ! = ' d ' ) ; // directory in last
if ( a - > thumbnailInfo . textureWidth = = b - > thumbnailInfo . textureWidth )
return ( a - > thumbnailInfo . textureHeight > b - > thumbnailInfo . textureHeight ) ;
return ( a - > thumbnailInfo . textureWidth > b - > thumbnailInfo . textureWidth ) ;
} ) ;
}
}
# endif // USE_THUMBNAILS
if ( vSortingField ! = SortingFieldEnum : : FIELD_NONE )
{
puSortingField = vSortingField ;
}
ApplyFilteringOnFileList ( vFileDialogInternal ) ;
}
void IGFD : : FileManager : : ClearFileLists ( )
{
prFilteredFileList . clear ( ) ;
prFileList . clear ( ) ;
}
std : : string IGFD : : FileManager : : prOptimizeFilenameForSearchOperations ( const std : : string & vFileNameExt )
{
auto fileNameExt = vFileNameExt ;
// convert to lower case
for ( char & c : fileNameExt )
c = ( char ) std : : tolower ( c ) ;
return fileNameExt ;
}
void IGFD : : FileManager : : AddFile ( const FileDialogInternal & vFileDialogInternal , const std : : string & vPath , const std : : string & vFileName , const char & vFileType )
{
auto infos = std : : make_shared < FileInfos > ( ) ;
infos - > filePath = vPath ;
infos - > fileNameExt = vFileName ;
infos - > fileNameExt_optimized = prOptimizeFilenameForSearchOperations ( infos - > fileNameExt ) ;
infos - > fileType = vFileType ;
if ( infos - > fileNameExt . empty ( ) | | ( infos - > fileNameExt = = " . " & & ! vFileDialogInternal . puFilterManager . puDLGFilters . empty ( ) ) ) return ; // filename empty or filename is the current dir '.' //-V807
if ( infos - > fileNameExt ! = " .. " & & ( vFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_DontShowHiddenFiles ) & & infos - > fileNameExt [ 0 ] = = ' . ' ) // dont show hidden files
if ( ! vFileDialogInternal . puFilterManager . puDLGFilters . empty ( ) | | ( vFileDialogInternal . puFilterManager . puDLGFilters . empty ( ) & & infos - > fileNameExt ! = " . " ) ) // except "." if in directory mode //-V728
return ;
if ( infos - > fileType = = ' f ' | |
infos - > fileType = = ' l ' ) // link can have the same extention of a file
{
size_t lpt = infos - > fileNameExt . find_last_of ( ' . ' ) ;
if ( lpt ! = std : : string : : npos )
{
infos - > fileExt = infos - > fileNameExt . substr ( lpt ) ;
}
2022-02-09 04:13:54 +00:00
for ( char & i : infos - > fileExt ) {
if ( i > = ' A ' & & i < = ' Z ' ) i + = ' a ' - ' A ' ;
}
2021-12-11 07:10:09 +00:00
if ( ! vFileDialogInternal . puFilterManager . IsCoveredByFilters ( infos - > fileExt ) )
{
return ;
}
}
vFileDialogInternal . puFilterManager . prFillFileStyle ( infos ) ;
prCompleteFileInfos ( infos ) ;
prFileList . push_back ( infos ) ;
}
void IGFD : : FileManager : : ScanDir ( const FileDialogInternal & vFileDialogInternal , const std : : string & vPath )
{
std : : string path = vPath ;
if ( prCurrentPathDecomposition . empty ( ) )
{
SetCurrentDir ( path ) ;
}
if ( ! prCurrentPathDecomposition . empty ( ) )
{
# ifdef WIN32
if ( path = = puFsRoot )
path + = std : : string ( 1u , PATH_SEP ) ;
# endif // WIN32
ClearFileLists ( ) ;
# ifdef USE_STD_FILESYSTEM
//const auto wpath = IGFD::Utils::WGetString(path.c_str());
const std : : filesystem : : path fspath ( path ) ;
const auto dir_iter = std : : filesystem : : directory_iterator ( fspath ) ;
AddFile ( vFileDialogInternal , path , " .. " , ' d ' ) ;
for ( const auto & file : dir_iter )
{
char fileType = 0 ;
if ( file . is_symlink ( ) )
fileType = ' l ' ;
else if ( file . is_directory ( ) )
fileType = ' d ' ;
else
fileType = ' f ' ;
auto fileNameExt = file . path ( ) . filename ( ) . string ( ) ;
AddFile ( vFileDialogInternal , path , fileNameExt , fileType ) ;
}
# else // dirent
struct dirent * * files = nullptr ;
2022-01-19 20:03:33 +00:00
int n = scandir ( path . c_str ( ) , & files , nullptr , inAlphaSort ) ;
if ( n > 0 )
2021-12-11 07:10:09 +00:00
{
2022-01-19 20:03:33 +00:00
int i ;
2021-12-11 07:10:09 +00:00
for ( i = 0 ; i < n ; i + + )
{
struct dirent * ent = files [ i ] ;
2022-07-24 03:11:30 +00:00
std : : string where = path + std : : string ( " / " ) + std : : string ( ent - > d_name ) ;
2021-12-11 07:10:09 +00:00
char fileType = 0 ;
2022-07-24 03:11:30 +00:00
# ifdef HAVE_DIRENT_TYPE
if ( ent - > d_type ! = DT_UNKNOWN )
{
switch ( ent - > d_type )
{
case DT_REG :
fileType = ' f ' ; break ;
case DT_DIR :
fileType = ' d ' ; break ;
case DT_LNK :
DIR * dirTest = opendir ( where . c_str ( ) ) ;
if ( dirTest = = NULL )
{
if ( errno = = ENOTDIR )
{
fileType = ' f ' ;
}
else
{
fileType = ' l ' ;
}
}
else
{
fileType = ' d ' ;
closedir ( dirTest ) ;
}
break ;
}
}
else
# endif // HAVE_DIRENT_TYPE
2021-12-11 07:10:09 +00:00
{
2022-07-24 03:11:30 +00:00
struct stat filestat ;
if ( stat ( where . c_str ( ) , & filestat ) = = 0 )
{
if ( S_ISDIR ( filestat . st_mode ) )
{
fileType = ' d ' ;
}
else
{
fileType = ' f ' ;
}
}
2021-12-11 07:10:09 +00:00
}
auto fileNameExt = ent - > d_name ;
AddFile ( vFileDialogInternal , path , fileNameExt , fileType ) ;
}
for ( i = 0 ; i < n ; i + + )
{
free ( files [ i ] ) ;
}
free ( files ) ;
}
# endif // USE_STD_FILESYSTEM
SortFields ( vFileDialogInternal , puSortingField , false ) ;
}
}
bool IGFD : : FileManager : : GetDrives ( )
{
auto drives = IGFD : : Utils : : GetDrivesList ( ) ;
if ( ! drives . empty ( ) )
{
prCurrentPath . clear ( ) ;
prCurrentPathDecomposition . clear ( ) ;
ClearFileLists ( ) ;
for ( auto & drive : drives )
{
auto info = std : : make_shared < FileInfos > ( ) ;
info - > fileNameExt = drive ;
info - > fileNameExt_optimized = prOptimizeFilenameForSearchOperations ( drive ) ;
info - > fileType = ' d ' ;
if ( ! info - > fileNameExt . empty ( ) )
{
prFileList . push_back ( info ) ;
}
}
puShowDrives = true ;
return true ;
}
return false ;
}
bool IGFD : : FileManager : : IsComposerEmpty ( )
{
return prCurrentPathDecomposition . empty ( ) ;
}
size_t IGFD : : FileManager : : GetComposerSize ( )
{
return prCurrentPathDecomposition . size ( ) ;
}
bool IGFD : : FileManager : : IsFileListEmpty ( )
{
return prFileList . empty ( ) ;
}
size_t IGFD : : FileManager : : GetFullFileListSize ( )
{
return prFileList . size ( ) ;
}
std : : shared_ptr < FileInfos > IGFD : : FileManager : : GetFullFileAt ( size_t vIdx )
{
if ( vIdx < prFileList . size ( ) )
return prFileList [ vIdx ] ;
return nullptr ;
}
bool IGFD : : FileManager : : IsFilteredListEmpty ( )
{
return prFilteredFileList . empty ( ) ;
}
size_t IGFD : : FileManager : : GetFilteredListSize ( )
{
return prFilteredFileList . size ( ) ;
}
std : : shared_ptr < FileInfos > IGFD : : FileManager : : GetFilteredFileAt ( size_t vIdx )
{
if ( vIdx < prFilteredFileList . size ( ) )
return prFilteredFileList [ vIdx ] ;
return nullptr ;
}
bool IGFD : : FileManager : : IsFileNameSelected ( const std : : string & vFileName )
{
return prSelectedFileNames . find ( vFileName ) ! = prSelectedFileNames . end ( ) ;
}
std : : string IGFD : : FileManager : : GetBack ( )
{
return prCurrentPathDecomposition . back ( ) ;
}
void IGFD : : FileManager : : ClearComposer ( )
{
prCurrentPathDecomposition . clear ( ) ;
}
void IGFD : : FileManager : : ClearAll ( )
{
ClearComposer ( ) ;
ClearFileLists ( ) ;
}
void IGFD : : FileManager : : ApplyFilteringOnFileList ( const FileDialogInternal & vFileDialogInternal )
{
prFilteredFileList . clear ( ) ;
for ( const auto & file : prFileList )
{
if ( ! file . use_count ( ) )
continue ;
bool show = true ;
if ( ! file - > IsTagFound ( vFileDialogInternal . puSearchManager . puSearchTag ) ) // if search tag
show = false ;
if ( puDLGDirectoryMode & & file - > fileType ! = ' d ' ) // directory mode
show = false ;
if ( show )
prFilteredFileList . push_back ( file ) ;
}
}
std : : string IGFD : : FileManager : : prRoundNumber ( double vvalue , int n )
{
std : : stringstream tmp ;
tmp < < std : : setprecision ( n ) < < std : : fixed < < vvalue ;
return tmp . str ( ) ;
}
std : : string IGFD : : FileManager : : prFormatFileSize ( size_t vByteSize )
{
if ( vByteSize ! = 0 )
{
static double lo = 1024.0 ;
static double ko = 1024.0 * 1024.0 ;
static double mo = 1024.0 * 1024.0 * 1024.0 ;
auto v = ( double ) vByteSize ;
if ( v < lo )
return prRoundNumber ( v , 0 ) ; // octet
else if ( v < ko )
return prRoundNumber ( v / lo , 2 ) + " K " ; // ko
else if ( v < mo )
return prRoundNumber ( v / ko , 2 ) + " M " ; // Mo
else
return prRoundNumber ( v / mo , 2 ) + " G " ; // Go
}
return " " ;
}
void IGFD : : FileManager : : prCompleteFileInfos ( const std : : shared_ptr < FileInfos > & vInfos )
{
if ( ! vInfos . use_count ( ) )
return ;
if ( vInfos - > fileNameExt ! = " . " & &
vInfos - > fileNameExt ! = " .. " )
{
// _stat struct :
//dev_t st_dev; /* ID of device containing file */
//ino_t st_ino; /* inode number */
//mode_t st_mode; /* protection */
//nlink_t st_nlink; /* number of hard links */
//uid_t st_uid; /* user ID of owner */
//gid_t st_gid; /* group ID of owner */
//dev_t st_rdev; /* device ID (if special file) */
//off_t st_size; /* total size, in bytes */
//blksize_t st_blksize; /* blocksize for file system I/O */
//blkcnt_t st_blocks; /* number of 512B blocks allocated */
//time_t st_atime; /* time of last access - not sure out of ntfs */
//time_t st_mtime; /* time of last modification - not sure out of ntfs */
//time_t st_ctime; /* time of last status change - not sure out of ntfs */
std : : string fpn ;
if ( vInfos - > fileType = = ' f ' | | vInfos - > fileType = = ' l ' | | vInfos - > fileType = = ' d ' ) // file
fpn = vInfos - > filePath + std : : string ( 1u , PATH_SEP ) + vInfos - > fileNameExt ;
struct stat statInfos = { } ;
char timebuf [ 100 ] ;
int result = stat ( fpn . c_str ( ) , & statInfos ) ;
2022-06-15 07:03:20 +00:00
if ( result ! = - 1 )
2021-12-11 07:10:09 +00:00
{
if ( vInfos - > fileType ! = ' d ' )
{
vInfos - > fileSize = ( size_t ) statInfos . st_size ;
vInfos - > formatedFileSize = prFormatFileSize ( vInfos - > fileSize ) ;
}
size_t len = 0 ;
# ifdef MSVC
struct tm _tm ;
errno_t err = localtime_s ( & _tm , & statInfos . st_mtime ) ;
if ( ! err ) len = strftime ( timebuf , 99 , DateTimeFormat , & _tm ) ;
# else // MSVC
struct tm * _tm = localtime ( & statInfos . st_mtime ) ;
if ( _tm ) len = strftime ( timebuf , 99 , DateTimeFormat , _tm ) ;
# endif // MSVC
if ( len )
{
vInfos - > fileModifDate = std : : string ( timebuf , len ) ;
}
2022-06-15 07:03:20 +00:00
} else {
vInfos - > fileSize = 0 ;
vInfos - > formatedFileSize = prFormatFileSize ( vInfos - > fileSize ) ;
vInfos - > fileModifDate = " ??? " ;
}
2021-12-11 07:10:09 +00:00
}
}
void IGFD : : FileManager : : prRemoveFileNameInSelection ( const std : : string & vFileName )
{
prSelectedFileNames . erase ( vFileName ) ;
if ( prSelectedFileNames . size ( ) = = 1 )
{
snprintf ( puFileNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER , " %s " , vFileName . c_str ( ) ) ;
}
else
{
snprintf ( puFileNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER , " %zu files Selected " , prSelectedFileNames . size ( ) ) ;
}
}
void IGFD : : FileManager : : prAddFileNameInSelection ( const std : : string & vFileName , bool vSetLastSelectionFileName )
{
prSelectedFileNames . emplace ( vFileName ) ;
if ( prSelectedFileNames . size ( ) = = 1 )
{
snprintf ( puFileNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER , " %s " , vFileName . c_str ( ) ) ;
}
else
{
snprintf ( puFileNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER , " %zu files Selected " , prSelectedFileNames . size ( ) ) ;
}
if ( vSetLastSelectionFileName )
prLastSelectedFileName = vFileName ;
}
void IGFD : : FileManager : : SetCurrentDir ( const std : : string & vPath )
{
std : : string path = vPath ;
# ifdef WIN32
if ( puFsRoot = = path )
path + = std : : string ( 1u , PATH_SEP ) ;
# endif // WIN32
# ifdef USE_STD_FILESYSTEM
namespace fs = std : : filesystem ;
bool dir_opened = fs : : is_directory ( vPath ) ;
if ( ! dir_opened )
{
path = " . " ;
dir_opened = fs : : is_directory ( vPath ) ;
}
if ( dir_opened )
# else
DIR * dir = opendir ( path . c_str ( ) ) ;
if ( dir = = nullptr )
{
path = " . " ;
dir = opendir ( path . c_str ( ) ) ;
}
if ( dir ! = nullptr )
# endif // USE_STD_FILESYSTEM
{
# ifdef WIN32
DWORD numchar = 0 ;
// numchar = GetFullPathNameA(path.c_str(), PATH_MAX, real_path, nullptr);
std : : wstring wpath = IGFD : : Utils : : string_to_wstring ( path ) ;
numchar = GetFullPathNameW ( wpath . c_str ( ) , 0 , nullptr , nullptr ) ;
std : : wstring fpath ( numchar , 0 ) ;
GetFullPathNameW ( wpath . c_str ( ) , numchar , ( wchar_t * ) fpath . data ( ) , nullptr ) ;
std : : string real_path = IGFD : : Utils : : wstring_to_string ( fpath ) ;
if ( real_path . back ( ) = = ' \0 ' ) // for fix issue we can have with std::string concatenation.. if there is a \0 at end
real_path = real_path . substr ( 0 , real_path . size ( ) - 1U ) ;
if ( ! real_path . empty ( ) )
# elif defined(UNIX) // UNIX is LINUX or APPLE
char real_path [ PATH_MAX ] ;
char * numchar = realpath ( path . c_str ( ) , real_path ) ;
if ( numchar ! = nullptr )
# endif // WIN32
{
prCurrentPath = std : : move ( real_path ) ;
if ( prCurrentPath [ prCurrentPath . size ( ) - 1 ] = = PATH_SEP )
{
prCurrentPath = prCurrentPath . substr ( 0 , prCurrentPath . size ( ) - 1 ) ;
}
IGFD : : Utils : : SetBuffer ( puInputPathBuffer , MAX_PATH_BUFFER_SIZE , prCurrentPath ) ;
prCurrentPathDecomposition = IGFD : : Utils : : SplitStringToVector ( prCurrentPath , PATH_SEP , false ) ;
# ifdef UNIX // UNIX is LINUX or APPLE
prCurrentPathDecomposition . insert ( prCurrentPathDecomposition . begin ( ) , std : : string ( 1u , PATH_SEP ) ) ;
# endif // UNIX
if ( ! prCurrentPathDecomposition . empty ( ) )
{
# ifdef WIN32
puFsRoot = prCurrentPathDecomposition [ 0 ] ;
# endif // WIN32
}
}
# ifndef USE_STD_FILESYSTEM
closedir ( dir ) ;
# endif
}
}
bool IGFD : : FileManager : : CreateDir ( const std : : string & vPath )
{
bool res = false ;
if ( ! vPath . empty ( ) )
{
std : : string path = prCurrentPath + std : : string ( 1u , PATH_SEP ) + vPath ;
res = IGFD : : Utils : : CreateDirectoryIfNotExist ( path ) ;
}
return res ;
}
void IGFD : : FileManager : : ComposeNewPath ( std : : vector < std : : string > : : iterator vIter )
{
std : : string res ;
while ( true )
{
if ( ! res . empty ( ) )
{
# ifdef WIN32
res = * vIter + std : : string ( 1u , PATH_SEP ) + res ;
# elif defined(UNIX) // UNIX is LINUX or APPLE
if ( * vIter = = puFsRoot )
res = * vIter + res ;
else
res = * vIter + PATH_SEP + res ;
# endif // WIN32
}
else
res = * vIter ;
if ( vIter = = prCurrentPathDecomposition . begin ( ) )
{
# if defined(UNIX) // UNIX is LINUX or APPLE
if ( res [ 0 ] ! = PATH_SEP )
res = PATH_SEP + res ;
# endif // defined(UNIX)
break ;
}
- - vIter ;
}
prCurrentPath = std : : move ( res ) ;
}
bool IGFD : : FileManager : : SetPathOnParentDirectoryIfAny ( )
{
if ( prCurrentPathDecomposition . size ( ) > 1 )
{
ComposeNewPath ( prCurrentPathDecomposition . end ( ) - 2 ) ;
return true ;
}
return false ;
}
std : : string IGFD : : FileManager : : GetCurrentPath ( )
{
if ( prCurrentPath . empty ( ) )
prCurrentPath = " . " ;
return prCurrentPath ;
}
void IGFD : : FileManager : : SetCurrentPath ( const std : : string & vCurrentPath )
{
if ( vCurrentPath . empty ( ) )
prCurrentPath = " . " ;
else
prCurrentPath = vCurrentPath ;
}
bool IGFD : : FileManager : : IsFileExist ( const std : : string & vFile )
{
std : : ifstream docFile ( vFile , std : : ios : : in ) ;
if ( docFile . is_open ( ) )
{
docFile . close ( ) ;
return true ;
}
return false ;
}
void IGFD : : FileManager : : SetDefaultFileName ( const std : : string & vFileName )
{
puDLGDefaultFileName = vFileName ;
IGFD : : Utils : : SetBuffer ( puFileNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER , vFileName ) ;
}
bool IGFD : : FileManager : : SelectDirectory ( const std : : shared_ptr < FileInfos > & vInfos )
{
if ( ! vInfos . use_count ( ) )
return false ;
bool pathClick = false ;
if ( vInfos - > fileNameExt = = " .. " )
{
pathClick = SetPathOnParentDirectoryIfAny ( ) ;
}
else
{
std : : string newPath ;
if ( puShowDrives )
{
newPath = vInfos - > fileNameExt + std : : string ( 1u , PATH_SEP ) ;
}
else
{
# ifdef __linux__
if ( puFsRoot = = prCurrentPath )
newPath = prCurrentPath + vInfos - > fileNameExt ;
else
# endif // __linux__
newPath = prCurrentPath + std : : string ( 1u , PATH_SEP ) + vInfos - > fileNameExt ;
}
if ( IGFD : : Utils : : IsDirectoryExist ( newPath ) )
{
if ( puShowDrives )
{
prCurrentPath = vInfos - > fileNameExt ;
puFsRoot = prCurrentPath ;
}
else
{
prCurrentPath = newPath ; //-V820
}
pathClick = true ;
}
}
return pathClick ;
}
void IGFD : : FileManager : : SelectFileName ( const FileDialogInternal & vFileDialogInternal , const std : : shared_ptr < FileInfos > & vInfos )
{
if ( ! vInfos . use_count ( ) )
return ;
if ( ImGui : : GetIO ( ) . KeyCtrl )
{
if ( puDLGcountSelectionMax = = 0 ) // infinite selection
{
if ( prSelectedFileNames . find ( vInfos - > fileNameExt ) = = prSelectedFileNames . end ( ) ) // not found +> add
{
prAddFileNameInSelection ( vInfos - > fileNameExt , true ) ;
}
else // found +> remove
{
prRemoveFileNameInSelection ( vInfos - > fileNameExt ) ;
}
}
else // selection limited by size
{
if ( prSelectedFileNames . size ( ) < puDLGcountSelectionMax )
{
if ( prSelectedFileNames . find ( vInfos - > fileNameExt ) = = prSelectedFileNames . end ( ) ) // not found +> add
{
prAddFileNameInSelection ( vInfos - > fileNameExt , true ) ;
}
else // found +> remove
{
prRemoveFileNameInSelection ( vInfos - > fileNameExt ) ;
}
}
}
}
else if ( ImGui : : GetIO ( ) . KeyShift )
{
if ( puDLGcountSelectionMax ! = 1 )
{
prSelectedFileNames . clear ( ) ;
// we will iterate filelist and get the last selection after the start selection
bool startMultiSelection = false ;
std : : string fileNameToSelect = vInfos - > fileNameExt ;
std : : string savedLastSelectedFileName ; // for invert selection mode
for ( const auto & file : prFileList )
{
if ( ! file . use_count ( ) )
continue ;
bool canTake = true ;
if ( ! file - > IsTagFound ( vFileDialogInternal . puSearchManager . puSearchTag ) ) canTake = false ;
if ( canTake ) // if not filtered, we will take files who are filtered by the dialog
{
if ( file - > fileNameExt = = prLastSelectedFileName )
{
startMultiSelection = true ;
prAddFileNameInSelection ( prLastSelectedFileName , false ) ;
}
else if ( startMultiSelection )
{
if ( puDLGcountSelectionMax = = 0 ) // infinite selection
{
prAddFileNameInSelection ( file - > fileNameExt , false ) ;
}
else // selection limited by size
{
if ( prSelectedFileNames . size ( ) < puDLGcountSelectionMax )
{
prAddFileNameInSelection ( file - > fileNameExt , false ) ;
}
else
{
startMultiSelection = false ;
if ( ! savedLastSelectedFileName . empty ( ) )
prLastSelectedFileName = savedLastSelectedFileName ;
break ;
}
}
}
if ( file - > fileNameExt = = fileNameToSelect )
{
if ( ! startMultiSelection ) // we are before the last Selected FileName, so we must inverse
{
savedLastSelectedFileName = prLastSelectedFileName ;
prLastSelectedFileName = fileNameToSelect ;
fileNameToSelect = savedLastSelectedFileName ;
startMultiSelection = true ;
prAddFileNameInSelection ( prLastSelectedFileName , false ) ;
}
else
{
startMultiSelection = false ;
if ( ! savedLastSelectedFileName . empty ( ) )
prLastSelectedFileName = savedLastSelectedFileName ;
break ;
}
}
}
}
}
}
else
{
prSelectedFileNames . clear ( ) ;
IGFD : : Utils : : ResetBuffer ( puFileNameBuffer ) ;
prAddFileNameInSelection ( vInfos - > fileNameExt , true ) ;
}
}
void IGFD : : FileManager : : DrawDirectoryCreation ( const FileDialogInternal & vFileDialogInternal )
{
if ( vFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_DisableCreateDirectoryButton )
return ;
if ( IMGUI_BUTTON ( createDirButtonString ) )
{
if ( ! prCreateDirectoryMode )
{
prCreateDirectoryMode = true ;
IGFD : : Utils : : ResetBuffer ( puDirectoryNameBuffer ) ;
}
}
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( buttonCreateDirString ) ;
if ( prCreateDirectoryMode )
{
ImGui : : SameLine ( ) ;
ImGui : : PushItemWidth ( 100.0f ) ;
ImGui : : InputText ( " ##DirectoryFileName " , puDirectoryNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER ) ;
ImGui : : PopItemWidth ( ) ;
ImGui : : SameLine ( ) ;
if ( IMGUI_BUTTON ( okButtonString ) )
{
std : : string newDir = std : : string ( puDirectoryNameBuffer ) ;
if ( CreateDir ( newDir ) )
{
SetCurrentPath ( prCurrentPath + std : : string ( 1u , PATH_SEP ) + newDir ) ;
OpenCurrentPath ( vFileDialogInternal ) ;
}
prCreateDirectoryMode = false ;
}
ImGui : : SameLine ( ) ;
if ( IMGUI_BUTTON ( cancelButtonString ) )
{
prCreateDirectoryMode = false ;
}
}
}
void IGFD : : FileManager : : DrawPathComposer ( const FileDialogInternal & vFileDialogInternal )
{
if ( IMGUI_BUTTON ( resetButtonString ) )
{
SetCurrentPath ( " . " ) ;
OpenCurrentPath ( vFileDialogInternal ) ;
}
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( buttonResetPathString ) ;
# ifdef WIN32
ImGui : : SameLine ( ) ;
if ( IMGUI_BUTTON ( drivesButtonString ) )
{
puDrivesClicked = true ;
}
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( buttonDriveString ) ;
# endif // WIN32
ImGui : : SameLine ( ) ;
if ( IMGUI_BUTTON ( editPathButtonString ) )
{
puInputPathActivated = true ;
}
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( buttonEditPathString ) ;
ImGui : : SameLine ( ) ;
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
// show current path
if ( ! prCurrentPathDecomposition . empty ( ) )
{
ImGui : : SameLine ( ) ;
if ( puInputPathActivated )
{
ImGui : : PushItemWidth ( ImGui : : GetContentRegionAvail ( ) . x ) ;
ImGui : : InputText ( " ##pathedition " , puInputPathBuffer , MAX_PATH_BUFFER_SIZE ) ;
ImGui : : PopItemWidth ( ) ;
}
else
{
int _id = 0 ;
for ( auto itPathDecomp = prCurrentPathDecomposition . begin ( ) ;
itPathDecomp ! = prCurrentPathDecomposition . end ( ) ; + + itPathDecomp )
{
if ( itPathDecomp ! = prCurrentPathDecomposition . begin ( ) )
ImGui : : SameLine ( ) ;
ImGui : : PushID ( _id + + ) ;
bool click = IMGUI_PATH_BUTTON ( ( * itPathDecomp ) . c_str ( ) ) ;
ImGui : : PopID ( ) ;
if ( click )
{
ComposeNewPath ( itPathDecomp ) ;
puPathClicked = true ;
break ;
}
// activate input for path
if ( ImGui : : IsItemClicked ( ImGuiMouseButton_Right ) )
{
ComposeNewPath ( itPathDecomp ) ;
IGFD : : Utils : : SetBuffer ( puInputPathBuffer , MAX_PATH_BUFFER_SIZE , prCurrentPath ) ;
puInputPathActivated = true ;
break ;
}
}
}
}
}
std : : string IGFD : : FileManager : : GetResultingPath ( )
{
std : : string path = prCurrentPath ;
if ( puDLGDirectoryMode ) // if directory mode
{
std : : string selectedDirectory = puFileNameBuffer ;
if ( ! selectedDirectory . empty ( ) & &
selectedDirectory ! = " . " )
path + = std : : string ( 1u , PATH_SEP ) + selectedDirectory ;
}
return path ;
}
std : : string IGFD : : FileManager : : GetResultingFileName ( FileDialogInternal & vFileDialogInternal )
{
if ( ! puDLGDirectoryMode ) // if not directory mode
{
return puFileNameBuffer ; //vFileDialogInternal.puFilterManager.ReplaceExtentionWithCurrentFilter(std::string(puFileNameBuffer));
}
return " " ; // directory mode
}
std : : string IGFD : : FileManager : : GetResultingFilePathName ( FileDialogInternal & vFileDialogInternal )
{
std : : string result = GetResultingPath ( ) ;
std : : string filename = GetResultingFileName ( vFileDialogInternal ) ;
if ( ! filename . empty ( ) )
{
# ifdef UNIX
if ( puFsRoot ! = result )
# endif // UNIX
result + = std : : string ( 1u , PATH_SEP ) ;
result + = filename ;
}
return result ;
}
std : : map < std : : string , std : : string > IGFD : : FileManager : : GetResultingSelection ( )
{
std : : map < std : : string , std : : string > res ;
for ( auto & selectedFileName : prSelectedFileNames )
{
std : : string result = GetResultingPath ( ) ;
# ifdef UNIX
if ( puFsRoot ! = result )
# endif // UNIX
result + = std : : string ( 1u , PATH_SEP ) ;
result + = selectedFileName ;
res [ selectedFileName ] = result ;
}
return res ;
}
/////////////////////////////////////////////////////////////////////////////////////
//// FILE DIALOG INTERNAL ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void IGFD : : FileDialogInternal : : NewFrame ( )
{
puCanWeContinue = true ; // reset flag for possibily validate the dialog
puIsOk = false ; // reset dialog result
puFileManager . puDrivesClicked = false ;
puFileManager . puPathClicked = false ;
puNeedToExitDialog = false ;
# ifdef USE_DIALOG_EXIT_WITH_KEY
if ( ImGui : : IsKeyPressed ( IGFD_EXIT_KEY ) )
{
// we do that here with the data's defined at the last frame
// because escape key can quit input activation and at the end of the frame all flag will be false
// so we will detect nothing
if ( ! ( puFileManager . puInputPathActivated | |
puSearchManager . puSearchInputIsActive | |
puFileInputIsActive | |
puFileListViewIsActive ) )
{
puNeedToExitDialog = true ; // need to quit dialog
}
}
else
# endif
{
puSearchManager . puSearchInputIsActive = false ;
puFileInputIsActive = false ;
puFileListViewIsActive = false ;
}
}
void IGFD : : FileDialogInternal : : EndFrame ( )
{
// directory change
if ( puFileManager . puPathClicked )
{
puFileManager . OpenCurrentPath ( * this ) ;
}
if ( puFileManager . puDrivesClicked )
{
if ( puFileManager . GetDrives ( ) )
{
puFileManager . ApplyFilteringOnFileList ( * this ) ;
}
}
if ( puFileManager . puInputPathActivated )
{
auto gio = ImGui : : GetIO ( ) ;
2022-01-19 20:03:33 +00:00
if ( ImGui : : IsKeyReleased ( ImGuiKey_Enter ) )
2021-12-11 07:10:09 +00:00
{
puFileManager . SetCurrentPath ( std : : string ( puFileManager . puInputPathBuffer ) ) ;
puFileManager . OpenCurrentPath ( * this ) ;
puFileManager . puInputPathActivated = false ;
}
2022-01-19 20:03:33 +00:00
if ( ImGui : : IsKeyReleased ( ImGuiKey_Escape ) )
2021-12-11 07:10:09 +00:00
{
puFileManager . puInputPathActivated = false ;
}
}
}
void IGFD : : FileDialogInternal : : ResetForNewDialog ( )
{
}
/////////////////////////////////////////////////////////////////////////////////////
//// THUMBNAIL FEATURE //////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
IGFD : : ThumbnailFeature : : ThumbnailFeature ( )
{
# ifdef USE_THUMBNAILS
prDisplayMode = DisplayModeEnum : : FILE_LIST ;
# endif
}
IGFD : : ThumbnailFeature : : ~ ThumbnailFeature ( ) = default ;
void IGFD : : ThumbnailFeature : : NewThumbnailFrame ( FileDialogInternal & vFileDialogInternal )
{
( void ) vFileDialogInternal ;
# ifdef USE_THUMBNAILS
prStartThumbnailFileDatasExtraction ( ) ;
# endif
}
void IGFD : : ThumbnailFeature : : EndThumbnailFrame ( FileDialogInternal & vFileDialogInternal )
{
# ifdef USE_THUMBNAILS
prClearThumbnails ( vFileDialogInternal ) ;
# endif
}
void IGFD : : ThumbnailFeature : : QuitThumbnailFrame ( FileDialogInternal & vFileDialogInternal )
{
# ifdef USE_THUMBNAILS
prStopThumbnailFileDatasExtraction ( ) ;
prClearThumbnails ( vFileDialogInternal ) ;
# endif
}
# ifdef USE_THUMBNAILS
void IGFD : : ThumbnailFeature : : prStartThumbnailFileDatasExtraction ( )
{
const bool res = prThumbnailGenerationThread . use_count ( ) & & prThumbnailGenerationThread - > joinable ( ) ;
if ( ! res )
{
prIsWorking = true ;
prCountFiles = 0U ;
prThumbnailGenerationThread = std : : shared_ptr < std : : thread > (
new std : : thread ( & IGFD : : ThumbnailFeature : : prThreadThumbnailFileDatasExtractionFunc , this ) ,
[ this ] ( std : : thread * obj )
{
prIsWorking = false ;
if ( obj )
obj - > join ( ) ;
} ) ;
}
}
bool IGFD : : ThumbnailFeature : : prStopThumbnailFileDatasExtraction ( )
{
const bool res = prThumbnailGenerationThread . use_count ( ) & & prThumbnailGenerationThread - > joinable ( ) ;
if ( res )
{
prThumbnailGenerationThread . reset ( ) ;
}
return res ;
}
void IGFD : : ThumbnailFeature : : prThreadThumbnailFileDatasExtractionFunc ( )
{
prCountFiles = 0U ;
prIsWorking = true ;
// infinite loop while is thread working
while ( prIsWorking )
{
if ( ! prThumbnailFileDatasToGet . empty ( ) )
{
std : : shared_ptr < FileInfos > file = nullptr ;
prThumbnailFileDatasToGetMutex . lock ( ) ;
//get the first file in the list
file = ( * prThumbnailFileDatasToGet . begin ( ) ) ;
prThumbnailFileDatasToGetMutex . unlock ( ) ;
// retrieve datas of the texture file if its an image file
if ( file . use_count ( ) )
{
if ( file - > fileType = = ' f ' ) //-V522
{
if ( file - > fileExt = = " .png "
| | file - > fileExt = = " .bmp "
| | file - > fileExt = = " .tga "
| | file - > fileExt = = " .jpg " | | file - > fileExt = = " .jpeg "
| | file - > fileExt = = " .gif "
| | file - > fileExt = = " .psd "
| | file - > fileExt = = " .pic "
| | file - > fileExt = = " .ppm " | | file - > fileExt = = " .pgm "
//|| file->fileExt == ".hdr" => format float so in few times
)
{
auto fpn = file - > filePath + std : : string ( 1u , PATH_SEP ) + file - > fileNameExt ;
int w = 0 ;
int h = 0 ;
int chans = 0 ;
uint8_t * datas = stbi_load ( fpn . c_str ( ) , & w , & h , & chans , STBI_rgb_alpha ) ;
if ( datas )
{
if ( w & & h )
{
// resize with respect to glyph ratio
const float ratioX = ( float ) w / ( float ) h ;
const float newX = DisplayMode_ThumbailsList_ImageHeight * ratioX ;
float newY = w / ratioX ;
if ( newX < w )
newY = DisplayMode_ThumbailsList_ImageHeight ;
const auto newWidth = ( int ) newX ;
const auto newHeight = ( int ) newY ;
const auto newBufSize = ( size_t ) ( newWidth * newHeight * 4U ) ; //-V112 //-V1028
auto resizedData = new uint8_t [ newBufSize ] ;
const int resizeSucceeded = stbir_resize_uint8 (
datas , w , h , 0 ,
resizedData , newWidth , newHeight , 0 ,
4 ) ; //-V112
if ( resizeSucceeded )
{
auto th = & file - > thumbnailInfo ;
th - > textureFileDatas = resizedData ;
th - > textureWidth = newWidth ;
th - > textureHeight = newHeight ;
th - > textureChannels = 4 ; //-V112
// we set that at least, because will launch the gpu creation of the texture in the main thread
th - > isReadyToUpload = true ;
// need gpu loading
prAddThumbnailToCreate ( file ) ;
}
}
else
{
printf ( " image loading fail : w:%i h:%i c:%i \n " , w , h , 4 ) ; //-V112
}
stbi_image_free ( datas ) ;
}
}
}
// peu importe le resultat on vire le fichicer
// remove form this list
// write => thread concurency issues
prThumbnailFileDatasToGetMutex . lock ( ) ;
prThumbnailFileDatasToGet . pop_front ( ) ;
prThumbnailFileDatasToGetMutex . unlock ( ) ;
}
}
}
}
inline void inVariadicProgressBar ( float fraction , const ImVec2 & size_arg , const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
char TempBuffer [ 512 ] ;
const int w = vsnprintf ( TempBuffer , 511 , fmt , args ) ;
va_end ( args ) ;
if ( w )
{
ImGui : : ProgressBar ( fraction , size_arg , TempBuffer ) ;
}
}
void IGFD : : ThumbnailFeature : : prDrawThumbnailGenerationProgress ( )
{
if ( prThumbnailGenerationThread . use_count ( ) & & prThumbnailGenerationThread - > joinable ( ) )
{
if ( ! prThumbnailFileDatasToGet . empty ( ) )
{
const auto p = ( float ) ( ( double ) prCountFiles / ( double ) prThumbnailFileDatasToGet . size ( ) ) ; // read => no thread concurency issues
inVariadicProgressBar ( p , ImVec2 ( 50 , 0 ) , " %u/%u " , prCountFiles , ( uint32_t ) prThumbnailFileDatasToGet . size ( ) ) ; // read => no thread concurency issues
ImGui : : SameLine ( ) ;
}
}
}
void IGFD : : ThumbnailFeature : : prAddThumbnailToLoad ( const std : : shared_ptr < FileInfos > & vFileInfos )
{
if ( vFileInfos . use_count ( ) )
{
if ( vFileInfos - > fileType = = ' f ' )
{
if ( vFileInfos - > fileExt = = " .png "
| | vFileInfos - > fileExt = = " .bmp "
| | vFileInfos - > fileExt = = " .tga "
| | vFileInfos - > fileExt = = " .jpg " | | vFileInfos - > fileExt = = " .jpeg "
| | vFileInfos - > fileExt = = " .gif "
| | vFileInfos - > fileExt = = " .psd "
| | vFileInfos - > fileExt = = " .pic "
| | vFileInfos - > fileExt = = " .ppm " | | vFileInfos - > fileExt = = " .pgm "
//|| file->fileExt == ".hdr" => format float so in few times
)
{
// write => thread concurency issues
prThumbnailFileDatasToGetMutex . lock ( ) ;
prThumbnailFileDatasToGet . push_back ( vFileInfos ) ;
vFileInfos - > thumbnailInfo . isLoadingOrLoaded = true ;
prThumbnailFileDatasToGetMutex . unlock ( ) ;
}
}
}
}
void IGFD : : ThumbnailFeature : : prAddThumbnailToCreate ( const std : : shared_ptr < FileInfos > & vFileInfos )
{
if ( vFileInfos . use_count ( ) )
{
// write => thread concurency issues
prThumbnailToCreateMutex . lock ( ) ;
prThumbnailToCreate . push_back ( vFileInfos ) ;
prThumbnailToCreateMutex . unlock ( ) ;
}
}
void IGFD : : ThumbnailFeature : : prAddThumbnailToDestroy ( const IGFD_Thumbnail_Info & vIGFD_Thumbnail_Info )
{
// write => thread concurency issues
prThumbnailToDestroyMutex . lock ( ) ;
prThumbnailToDestroy . push_back ( vIGFD_Thumbnail_Info ) ;
prThumbnailToDestroyMutex . unlock ( ) ;
}
void IGFD : : ThumbnailFeature : : prDrawDisplayModeToolBar ( )
{
if ( IMGUI_RADIO_BUTTON ( DisplayMode_FilesList_ButtonString ,
prDisplayMode = = DisplayModeEnum : : FILE_LIST ) )
prDisplayMode = DisplayModeEnum : : FILE_LIST ;
if ( ImGui : : IsItemHovered ( ) ) ImGui : : SetTooltip ( DisplayMode_FilesList_ButtonHelp ) ;
ImGui : : SameLine ( ) ;
if ( IMGUI_RADIO_BUTTON ( DisplayMode_ThumbailsList_ButtonString ,
prDisplayMode = = DisplayModeEnum : : THUMBNAILS_LIST ) )
prDisplayMode = DisplayModeEnum : : THUMBNAILS_LIST ;
if ( ImGui : : IsItemHovered ( ) ) ImGui : : SetTooltip ( DisplayMode_ThumbailsList_ButtonHelp ) ;
ImGui : : SameLine ( ) ;
/* todo
if ( IMGUI_RADIO_BUTTON ( DisplayMode_ThumbailsGrid_ButtonString ,
prDisplayMode = = DisplayModeEnum : : THUMBNAILS_GRID ) )
prDisplayMode = DisplayModeEnum : : THUMBNAILS_GRID ;
if ( ImGui : : IsItemHovered ( ) ) ImGui : : SetTooltip ( DisplayMode_ThumbailsGrid_ButtonHelp ) ;
ImGui : : SameLine ( ) ;
*/
prDrawThumbnailGenerationProgress ( ) ;
}
void IGFD : : ThumbnailFeature : : prClearThumbnails ( FileDialogInternal & vFileDialogInternal )
{
// directory wil be changed so the file list will be erased
if ( vFileDialogInternal . puFileManager . puPathClicked )
{
size_t count = vFileDialogInternal . puFileManager . GetFullFileListSize ( ) ;
for ( size_t idx = 0U ; idx < count ; idx + + )
{
auto file = vFileDialogInternal . puFileManager . GetFullFileAt ( idx ) ;
if ( file . use_count ( ) )
{
if ( file - > thumbnailInfo . isReadyToDisplay ) //-V522
{
prAddThumbnailToDestroy ( file - > thumbnailInfo ) ;
}
}
}
}
}
void IGFD : : ThumbnailFeature : : SetCreateThumbnailCallback ( const CreateThumbnailFun & vCreateThumbnailFun )
{
prCreateThumbnailFun = vCreateThumbnailFun ;
}
void IGFD : : ThumbnailFeature : : SetDestroyThumbnailCallback ( const DestroyThumbnailFun & vCreateThumbnailFun )
{
prDestroyThumbnailFun = vCreateThumbnailFun ;
}
void IGFD : : ThumbnailFeature : : ManageGPUThumbnails ( )
{
if ( prCreateThumbnailFun )
{
if ( ! prThumbnailToCreate . empty ( ) )
{
for ( const auto & file : prThumbnailToCreate )
{
if ( file . use_count ( ) )
{
prCreateThumbnailFun ( & file - > thumbnailInfo ) ;
}
}
prThumbnailToCreateMutex . lock ( ) ;
prThumbnailToCreate . clear ( ) ;
prThumbnailToCreateMutex . unlock ( ) ;
}
}
else
{
printf ( " No Callback found for create texture \n You need to define the callback with a call to SetCreateThumbnailCallback \n " ) ;
}
if ( prDestroyThumbnailFun )
{
if ( ! prThumbnailToDestroy . empty ( ) )
{
for ( auto thumbnail : prThumbnailToDestroy )
{
prDestroyThumbnailFun ( & thumbnail ) ;
}
prThumbnailToDestroyMutex . lock ( ) ;
prThumbnailToDestroy . clear ( ) ;
prThumbnailToDestroyMutex . unlock ( ) ;
}
}
else
{
printf ( " No Callback found for destroy texture \n You need to define the callback with a call to SetCreateThumbnailCallback \n " ) ;
}
}
# endif // USE_THUMBNAILS
/////////////////////////////////////////////////////////////////////////////////////
//// BOOKMARK FEATURE ///////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
IGFD : : BookMarkFeature : : BookMarkFeature ( )
{
# ifdef USE_BOOKMARK
prBookmarkWidth = defaultBookmarkPaneWith ;
# endif // USE_BOOKMARK
}
# ifdef USE_BOOKMARK
void IGFD : : BookMarkFeature : : prDrawBookmarkButton ( )
{
IMGUI_TOGGLE_BUTTON ( bookmarksButtonString , & prBookmarkPaneShown ) ;
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( bookmarksButtonHelpString ) ;
}
bool IGFD : : BookMarkFeature : : prDrawBookmarkPane ( FileDialogInternal & vFileDialogInternal , const ImVec2 & vSize )
{
bool res = false ;
ImGui : : BeginChild ( " ##bookmarkpane " , vSize ) ;
static int selectedBookmarkForEdition = - 1 ;
if ( IMGUI_BUTTON ( addBookmarkButtonString " ##ImGuiFileDialogAddBookmark " ) )
{
if ( ! vFileDialogInternal . puFileManager . IsComposerEmpty ( ) )
{
BookmarkStruct bookmark ;
bookmark . name = vFileDialogInternal . puFileManager . GetBack ( ) ;
bookmark . path = vFileDialogInternal . puFileManager . GetCurrentPath ( ) ;
prBookmarks . push_back ( bookmark ) ;
}
}
if ( selectedBookmarkForEdition > = 0 & &
selectedBookmarkForEdition < ( int ) prBookmarks . size ( ) )
{
ImGui : : SameLine ( ) ;
if ( IMGUI_BUTTON ( removeBookmarkButtonString " ##ImGuiFileDialogAddBookmark " ) )
{
prBookmarks . erase ( prBookmarks . begin ( ) + selectedBookmarkForEdition ) ;
if ( selectedBookmarkForEdition = = ( int ) prBookmarks . size ( ) )
selectedBookmarkForEdition - - ;
}
if ( selectedBookmarkForEdition > = 0 & &
selectedBookmarkForEdition < ( int ) prBookmarks . size ( ) )
{
ImGui : : SameLine ( ) ;
ImGui : : PushItemWidth ( vSize . x - ImGui : : GetCursorPosX ( ) ) ;
if ( ImGui : : InputText ( " ##ImGuiFileDialogBookmarkEdit " , prBookmarkEditBuffer , MAX_FILE_DIALOG_NAME_BUFFER ) )
{
prBookmarks [ ( size_t ) selectedBookmarkForEdition ] . name = std : : string ( prBookmarkEditBuffer ) ;
}
ImGui : : PopItemWidth ( ) ;
}
}
ImGui : : Separator ( ) ;
if ( ! prBookmarks . empty ( ) )
{
prBookmarkClipper . Begin ( ( int ) prBookmarks . size ( ) , ImGui : : GetTextLineHeightWithSpacing ( ) ) ;
while ( prBookmarkClipper . Step ( ) )
{
for ( int i = prBookmarkClipper . DisplayStart ; i < prBookmarkClipper . DisplayEnd ; i + + )
{
if ( i < 0 ) continue ;
const BookmarkStruct & bookmark = prBookmarks [ ( size_t ) i ] ;
ImGui : : PushID ( i ) ;
if ( ImGui : : Selectable ( bookmark . name . c_str ( ) , selectedBookmarkForEdition = = i ,
ImGuiSelectableFlags_AllowDoubleClick ) |
( selectedBookmarkForEdition = = - 1 & &
bookmark . path = = vFileDialogInternal . puFileManager . GetCurrentPath ( ) ) ) // select if path is current
{
selectedBookmarkForEdition = i ;
IGFD : : Utils : : ResetBuffer ( prBookmarkEditBuffer ) ;
IGFD : : Utils : : AppendToBuffer ( prBookmarkEditBuffer , MAX_FILE_DIALOG_NAME_BUFFER , bookmark . name ) ;
if ( ImGui : : IsMouseDoubleClicked ( 0 ) ) // apply path
{
vFileDialogInternal . puFileManager . SetCurrentPath ( bookmark . path ) ;
vFileDialogInternal . puFileManager . OpenCurrentPath ( vFileDialogInternal ) ;
res = true ;
}
}
ImGui : : PopID ( ) ;
if ( ImGui : : IsItemHovered ( ) )
ImGui : : SetTooltip ( " %s " , bookmark . path . c_str ( ) ) ; //-V111
}
}
prBookmarkClipper . End ( ) ;
}
ImGui : : EndChild ( ) ;
return res ;
}
std : : string IGFD : : BookMarkFeature : : SerializeBookmarks ( )
{
std : : string res ;
size_t idx = 0 ;
for ( auto & it : prBookmarks )
{
if ( idx + + ! = 0 )
res + = " ## " ; // ## because reserved by imgui, so an input text cant have ##
res + = it . name + " ## " + it . path ;
}
return res ;
}
void IGFD : : BookMarkFeature : : DeserializeBookmarks ( const std : : string & vBookmarks )
{
if ( ! vBookmarks . empty ( ) )
{
prBookmarks . clear ( ) ;
auto arr = IGFD : : Utils : : SplitStringToVector ( vBookmarks , ' # ' , false ) ;
for ( size_t i = 0 ; i < arr . size ( ) ; i + = 2 )
{
BookmarkStruct bookmark ;
bookmark . name = arr [ i ] ;
if ( i + 1 < arr . size ( ) ) // for avoid crash if arr size is impair due to user mistake after edition
{
// if bad format we jump this bookmark
bookmark . path = arr [ i + 1 ] ;
prBookmarks . push_back ( bookmark ) ;
}
}
}
}
# endif // USE_BOOKMARK
/////////////////////////////////////////////////////////////////////////////////////
//// KEY EXPLORER FEATURE ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
KeyExplorerFeature : : KeyExplorerFeature ( ) = default ;
# ifdef USE_EXPLORATION_BY_KEYS
bool IGFD : : KeyExplorerFeature : : prLocateItem_Loop ( FileDialogInternal & vFileDialogInternal , ImWchar vC )
{
bool found = false ;
auto & fdi = vFileDialogInternal . puFileManager ;
if ( ! fdi . IsFilteredListEmpty ( ) )
{
auto countFiles = fdi . GetFilteredListSize ( ) ;
for ( size_t i = prLocateFileByInputChar_lastFileIdx ; i < countFiles ; i + + )
{
auto nfo = fdi . GetFilteredFileAt ( i ) ;
if ( nfo . use_count ( ) )
{
if ( nfo - > fileNameExt_optimized [ 0 ] = = vC | | // lower case search //-V522
nfo - > fileNameExt [ 0 ] = = vC ) // maybe upper case search
{
//float p = ((float)i) * ImGui::GetTextLineHeightWithSpacing();
float p = ( float ) ( ( double ) i / ( double ) countFiles ) * ImGui : : GetScrollMaxY ( ) ;
ImGui : : SetScrollY ( p ) ;
prLocateFileByInputChar_lastFound = true ;
prLocateFileByInputChar_lastFileIdx = i ;
prStartFlashItem ( prLocateFileByInputChar_lastFileIdx ) ;
auto infos = fdi . GetFilteredFileAt ( prLocateFileByInputChar_lastFileIdx ) ;
if ( infos . use_count ( ) )
{
if ( infos - > fileType = = ' d ' ) //-V522
{
if ( fdi . puDLGDirectoryMode ) // directory chooser
{
fdi . SelectFileName ( vFileDialogInternal , infos ) ;
}
}
else
{
fdi . SelectFileName ( vFileDialogInternal , infos ) ;
}
found = true ;
break ;
}
}
}
}
}
return found ;
}
void IGFD : : KeyExplorerFeature : : prLocateByInputKey ( FileDialogInternal & vFileDialogInternal )
{
ImGuiContext & g = * GImGui ;
auto & fdi = vFileDialogInternal . puFileManager ;
if ( ! g . ActiveId & & ! fdi . IsFilteredListEmpty ( ) )
{
auto & queueChar = ImGui : : GetIO ( ) . InputQueueCharacters ;
auto countFiles = fdi . GetFilteredListSize ( ) ;
// point by char
if ( ! queueChar . empty ( ) )
{
ImWchar c = queueChar . back ( ) ;
if ( prLocateFileByInputChar_InputQueueCharactersSize ! = queueChar . size ( ) )
{
if ( c = = prLocateFileByInputChar_lastChar ) // next file starting with same char until
{
if ( prLocateFileByInputChar_lastFileIdx < countFiles - 1U )
prLocateFileByInputChar_lastFileIdx + + ;
else
prLocateFileByInputChar_lastFileIdx = 0 ;
}
if ( ! prLocateItem_Loop ( vFileDialogInternal , c ) )
{
// not found, loop again from 0 this time
prLocateFileByInputChar_lastFileIdx = 0 ;
prLocateItem_Loop ( vFileDialogInternal , c ) ;
}
prLocateFileByInputChar_lastChar = c ;
}
}
prLocateFileByInputChar_InputQueueCharactersSize = queueChar . size ( ) ;
}
}
void IGFD : : KeyExplorerFeature : : prExploreWithkeys ( FileDialogInternal & vFileDialogInternal , ImGuiID vListViewID )
{
auto & fdi = vFileDialogInternal . puFileManager ;
if ( ! fdi . IsFilteredListEmpty ( ) )
{
bool canWeExplore = false ;
bool hasNav = ( ImGui : : GetIO ( ) . ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard ) ;
ImGuiContext & g = * GImGui ;
if ( ! hasNav & & ! g . ActiveId ) // no nav and no activated inputs
canWeExplore = true ;
if ( g . NavId & & g . NavId = = vListViewID )
{
if ( ImGui : : IsKeyPressedMap ( IGFD_KEY_ENTER ) | |
ImGui : : IsKeyPressedMap ( ImGuiKey_KeyPadEnter ) | |
ImGui : : IsKeyPressedMap ( ImGuiKey_Space ) )
{
ImGui : : ActivateItem ( vListViewID ) ;
ImGui : : SetActiveID ( vListViewID , g . CurrentWindow ) ;
}
}
if ( vListViewID = = g . LastActiveId - 1 ) // if listview id is the last acticated nav id (ImGui::ActivateItem(vListViewID);)
canWeExplore = true ;
if ( canWeExplore )
{
if ( ImGui : : IsKeyPressedMap ( ImGuiKey_Escape ) )
{
ImGui : : ClearActiveID ( ) ;
g . LastActiveId = 0 ;
}
auto countFiles = fdi . GetFilteredListSize ( ) ;
// explore
bool exploreByKey = false ;
bool enterInDirectory = false ;
bool exitDirectory = false ;
if ( ( hasNav & & ImGui : : IsKeyPressedMap ( ImGuiKey_UpArrow ) ) | | ( ! hasNav & & ImGui : : IsKeyPressed ( IGFD_KEY_UP ) ) )
{
exploreByKey = true ;
if ( prLocateFileByInputChar_lastFileIdx > 0 )
prLocateFileByInputChar_lastFileIdx - - ;
else
prLocateFileByInputChar_lastFileIdx = countFiles - 1U ;
}
else if ( ( hasNav & & ImGui : : IsKeyPressedMap ( ImGuiKey_DownArrow ) ) | | ( ! hasNav & & ImGui : : IsKeyPressed ( IGFD_KEY_DOWN ) ) )
{
exploreByKey = true ;
if ( prLocateFileByInputChar_lastFileIdx < countFiles - 1U )
prLocateFileByInputChar_lastFileIdx + + ;
else
prLocateFileByInputChar_lastFileIdx = 0U ;
}
else if ( ImGui : : IsKeyReleased ( IGFD_KEY_ENTER ) )
{
exploreByKey = true ;
enterInDirectory = true ;
}
else if ( ImGui : : IsKeyReleased ( IGFD_KEY_BACKSPACE ) )
{
exploreByKey = true ;
exitDirectory = true ;
}
if ( exploreByKey )
{
//float totalHeight = prFilteredFileList.size() * ImGui::GetTextLineHeightWithSpacing();
float p = ( float ) ( ( double ) prLocateFileByInputChar_lastFileIdx / ( double ) ( countFiles - 1U ) ) * ImGui : : GetScrollMaxY ( ) ; // seems not udpated in tables version outside tables
//float p = ((float)locateFileByInputChar_lastFileIdx) * ImGui::GetTextLineHeightWithSpacing();
ImGui : : SetScrollY ( p ) ;
prStartFlashItem ( prLocateFileByInputChar_lastFileIdx ) ;
auto infos = fdi . GetFilteredFileAt ( prLocateFileByInputChar_lastFileIdx ) ;
if ( infos . use_count ( ) )
{
if ( infos - > fileType = = ' d ' ) //-V522
{
if ( ! fdi . puDLGDirectoryMode | | enterInDirectory )
{
if ( enterInDirectory )
{
if ( fdi . SelectDirectory ( infos ) )
{
// changement de repertoire
vFileDialogInternal . puFileManager . OpenCurrentPath ( vFileDialogInternal ) ;
if ( prLocateFileByInputChar_lastFileIdx > countFiles - 1U )
{
prLocateFileByInputChar_lastFileIdx = 0 ;
}
}
}
}
else // directory chooser
{
fdi . SelectFileName ( vFileDialogInternal , infos ) ;
}
}
else
{
fdi . SelectFileName ( vFileDialogInternal , infos ) ;
}
if ( exitDirectory )
{
auto nfo = std : : make_shared < FileInfos > ( ) ;
nfo - > fileNameExt = " .. " ;
if ( fdi . SelectDirectory ( nfo ) )
{
// changement de repertoire
vFileDialogInternal . puFileManager . OpenCurrentPath ( vFileDialogInternal ) ;
if ( prLocateFileByInputChar_lastFileIdx > countFiles - 1U )
{
prLocateFileByInputChar_lastFileIdx = 0 ;
}
}
# ifdef WIN32
else
{
if ( fdi . GetComposerSize ( ) = = 1U )
{
if ( fdi . GetDrives ( ) )
{
fdi . ApplyFilteringOnFileList ( vFileDialogInternal ) ;
}
}
}
# endif // WIN32
}
}
}
}
}
}
bool IGFD : : KeyExplorerFeature : : prFlashableSelectable ( const char * label , bool selected ,
ImGuiSelectableFlags flags , bool vFlashing , const ImVec2 & size_arg )
{
using namespace ImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return false ;
ImGuiContext & g = * GImGui ;
const ImGuiStyle & style = g . Style ;
// Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle.
ImGuiID id = window - > GetID ( label ) ;
ImVec2 label_size = CalcTextSize ( label , nullptr , true ) ;
ImVec2 size ( size_arg . x ! = 0.0f ? size_arg . x : label_size . x , size_arg . y ! = 0.0f ? size_arg . y : label_size . y ) ; //-V550
ImVec2 pos = window - > DC . CursorPos ;
pos . y + = window - > DC . CurrLineTextBaseOffset ;
ItemSize ( size , 0.0f ) ;
// Fill horizontal space
// We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets.
const bool span_all_columns = ( flags & ImGuiSelectableFlags_SpanAllColumns ) ! = 0 ;
const float min_x = span_all_columns ? window - > ParentWorkRect . Min . x : pos . x ;
const float max_x = span_all_columns ? window - > ParentWorkRect . Max . x : window - > WorkRect . Max . x ;
if ( fabs ( size_arg . x ) < FLT_EPSILON | | ( flags & ImGuiSelectableFlags_SpanAvailWidth ) )
size . x = ImMax ( label_size . x , max_x - min_x ) ;
// Text stays at the submission position, but bounding box may be extended on both sides
const ImVec2 text_min = pos ;
const ImVec2 text_max ( min_x + size . x , pos . y + size . y ) ;
// Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable.
ImRect bb ( min_x , pos . y , text_max . x , text_max . y ) ;
if ( ( flags & ImGuiSelectableFlags_NoPadWithHalfSpacing ) = = 0 )
{
const float spacing_x = span_all_columns ? 0.0f : style . ItemSpacing . x ;
const float spacing_y = style . ItemSpacing . y ;
const float spacing_L = IM_FLOOR ( spacing_x * 0.50f ) ;
const float spacing_U = IM_FLOOR ( spacing_y * 0.50f ) ;
bb . Min . x - = spacing_L ;
bb . Min . y - = spacing_U ;
bb . Max . x + = ( spacing_x - spacing_L ) ;
bb . Max . y + = ( spacing_y - spacing_U ) ;
}
//if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); }
// Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable..
const float backup_clip_rect_min_x = window - > ClipRect . Min . x ;
const float backup_clip_rect_max_x = window - > ClipRect . Max . x ;
if ( span_all_columns )
{
window - > ClipRect . Min . x = window - > ParentWorkRect . Min . x ;
window - > ClipRect . Max . x = window - > ParentWorkRect . Max . x ;
}
bool item_add ;
const bool disabled_item = ( flags & ImGuiSelectableFlags_Disabled ) ! = 0 ;
if ( disabled_item )
{
ImGuiItemFlags backup_item_flags = g . CurrentItemFlags ;
g . CurrentItemFlags | = ImGuiItemFlags_Disabled ;
item_add = ItemAdd ( bb , id ) ;
g . CurrentItemFlags = backup_item_flags ;
}
else
{
item_add = ItemAdd ( bb , id ) ;
}
if ( span_all_columns )
{
window - > ClipRect . Min . x = backup_clip_rect_min_x ;
window - > ClipRect . Max . x = backup_clip_rect_max_x ;
}
if ( ! item_add )
return false ;
const bool disabled_global = ( g . CurrentItemFlags & ImGuiItemFlags_Disabled ) ! = 0 ;
if ( disabled_item & & ! disabled_global ) // Only testing this as an optimization
BeginDisabled ( true ) ;
// FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only,
// which would be advantageous since most selectable are not selected.
if ( span_all_columns & & window - > DC . CurrentColumns )
PushColumnsBackground ( ) ;
else if ( span_all_columns & & g . CurrentTable )
TablePushBackgroundChannel ( ) ;
// We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries
ImGuiButtonFlags button_flags = 0 ;
if ( flags & ImGuiSelectableFlags_NoHoldingActiveID ) { button_flags | = ImGuiButtonFlags_NoHoldingActiveId ; }
if ( flags & ImGuiSelectableFlags_SelectOnClick ) { button_flags | = ImGuiButtonFlags_PressedOnClick ; }
if ( flags & ImGuiSelectableFlags_SelectOnRelease ) { button_flags | = ImGuiButtonFlags_PressedOnRelease ; }
if ( flags & ImGuiSelectableFlags_AllowDoubleClick ) { button_flags | = ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick ; }
if ( flags & ImGuiSelectableFlags_AllowItemOverlap ) { button_flags | = ImGuiButtonFlags_AllowItemOverlap ; }
const bool was_selected = selected ;
bool hovered , held ;
bool pressed = ButtonBehavior ( bb , id , & hovered , & held , button_flags ) ;
// Auto-select when moved into
// - This will be more fully fleshed in the range-select branch
// - This is not exposed as it won't nicely work with some user side handling of shift/control
// - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons
// - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope())
// - (2) usage will fail with clipped items
// The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.
if ( ( flags & ImGuiSelectableFlags_SelectOnNav ) & & g . NavJustMovedToId ! = 0 & & g . NavJustMovedToFocusScopeId = = window - > DC . NavFocusScopeIdCurrent )
if ( g . NavJustMovedToId = = id )
selected = pressed = true ;
// Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard
if ( pressed | | ( hovered & & ( flags & ImGuiSelectableFlags_SetNavIdOnHover ) ) )
{
if ( ! g . NavDisableMouseHover & & g . NavWindow = = window & & g . NavLayer = = window - > DC . NavLayerCurrent )
{
SetNavID ( id , window - > DC . NavLayerCurrent , window - > DC . NavFocusScopeIdCurrent , ImRect ( bb . Min - window - > Pos , bb . Max - window - > Pos ) ) ;
g . NavDisableHighlight = true ;
}
}
if ( pressed )
MarkItemEdited ( id ) ;
if ( flags & ImGuiSelectableFlags_AllowItemOverlap )
SetItemAllowOverlap ( ) ;
// In this branch, Selectable() cannot toggle the selection so this will never trigger.
if ( selected ! = was_selected ) //-V547
g . LastItemData . StatusFlags | = ImGuiItemStatusFlags_ToggledSelection ;
// Render
if ( ( held & & ( flags & ImGuiSelectableFlags_DrawHoveredWhenHeld ) ) | | vFlashing )
hovered = true ;
if ( hovered | | selected )
{
const ImU32 col = GetColorU32 ( ( held & & hovered ) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header ) ;
RenderFrame ( bb . Min , bb . Max , col , false , 0.0f ) ;
}
RenderNavHighlight ( bb , id , ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding ) ;
if ( span_all_columns & & window - > DC . CurrentColumns )
PopColumnsBackground ( ) ;
else if ( span_all_columns & & g . CurrentTable )
TablePopBackgroundChannel ( ) ;
RenderTextClipped ( text_min , text_max , label , nullptr , & label_size , style . SelectableTextAlign , & bb ) ;
// Automatically close popups
if ( pressed & & ( window - > Flags & ImGuiWindowFlags_Popup ) & & ! ( flags & ImGuiSelectableFlags_DontClosePopups ) & & ! ( g . LastItemData . InFlags & ImGuiItemFlags_SelectableDontClosePopup ) )
CloseCurrentPopup ( ) ;
if ( disabled_item & & ! disabled_global )
EndDisabled ( ) ;
IMGUI_TEST_ENGINE_ITEM_INFO ( id , label , g . LastItemData . StatusFlags ) ;
return pressed ; //-V1020
}
void IGFD : : KeyExplorerFeature : : prStartFlashItem ( size_t vIdx )
{
prFlashAlpha = 1.0f ;
prFlashedItem = vIdx ;
}
bool IGFD : : KeyExplorerFeature : : prBeginFlashItem ( size_t vIdx )
{
bool res = false ;
if ( prFlashedItem = = vIdx & &
std : : abs ( prFlashAlpha - 0.0f ) > 0.00001f )
{
prFlashAlpha - = prFlashAlphaAttenInSecs * ImGui : : GetIO ( ) . DeltaTime ;
if ( prFlashAlpha < 0.0f ) prFlashAlpha = 0.0f ;
ImVec4 hov = ImGui : : GetStyleColorVec4 ( ImGuiCol_HeaderHovered ) ;
hov . w = prFlashAlpha ;
ImGui : : PushStyleColor ( ImGuiCol_HeaderHovered , hov ) ;
res = true ;
}
return res ;
}
void IGFD : : KeyExplorerFeature : : prEndFlashItem ( )
{
ImGui : : PopStyleColor ( ) ;
}
void IGFD : : KeyExplorerFeature : : SetFlashingAttenuationInSeconds ( float vAttenValue )
{
prFlashAlphaAttenInSecs = 1.0f / ImMax ( vAttenValue , 0.01f ) ;
}
# endif // USE_EXPLORATION_BY_KEYS
/////////////////////////////////////////////////////////////////////////////////////
//// FILE DIALOG CONSTRUCTOR / DESTRUCTOR ///////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
2022-02-23 03:41:37 +00:00
IGFD : : FileDialog : : FileDialog ( ) : BookMarkFeature ( ) , KeyExplorerFeature ( ) , ThumbnailFeature ( ) { DpiScale = 1.0f ; }
2021-12-11 07:10:09 +00:00
IGFD : : FileDialog : : ~ FileDialog ( ) = default ;
//////////////////////////////////////////////////////////////////////////////////////////////////
///// FILE DIALOG STANDARD DIALOG ////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
// path and fileNameExt can be specified
void IGFD : : FileDialog : : OpenDialog (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vPath ,
const std : : string & vFileName ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
prFileDialogInternal . ResetForNewDialog ( ) ;
prFileDialogInternal . puDLGkey = vKey ;
prFileDialogInternal . puDLGtitle = vTitle ;
prFileDialogInternal . puDLGuserDatas = vUserDatas ;
prFileDialogInternal . puDLGflags = vFlags ;
2022-04-25 23:58:17 +00:00
prFileDialogInternal . puDLGselFun = vSelectFun ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGoptionsPane = nullptr ;
prFileDialogInternal . puDLGoptionsPaneWidth = 0.0f ;
prFileDialogInternal . puDLGmodal = false ;
prFileDialogInternal . puFilterManager . puDLGdefaultExt . clear ( ) ;
prFileDialogInternal . puFilterManager . ParseFilters ( vFilters ) ;
prFileDialogInternal . puFileManager . puDLGDirectoryMode = ( vFilters = = nullptr ) ;
if ( vPath . empty ( ) )
prFileDialogInternal . puFileManager . puDLGpath = prFileDialogInternal . puFileManager . GetCurrentPath ( ) ;
else
prFileDialogInternal . puFileManager . puDLGpath = vPath ;
prFileDialogInternal . puFileManager . SetCurrentPath ( vPath ) ;
prFileDialogInternal . puFileManager . puDLGcountSelectionMax = ( size_t ) vCountSelectionMax ;
prFileDialogInternal . puFileManager . SetDefaultFileName ( vFileName ) ;
prFileDialogInternal . puFileManager . ClearAll ( ) ;
prFileDialogInternal . puShowDialog = true ; // open dialog
}
// path and filename are obtained from filePathName
void IGFD : : FileDialog : : OpenDialog (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vFilePathName ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
prFileDialogInternal . ResetForNewDialog ( ) ;
prFileDialogInternal . puDLGkey = vKey ;
prFileDialogInternal . puDLGtitle = vTitle ;
prFileDialogInternal . puDLGoptionsPane = nullptr ;
prFileDialogInternal . puDLGoptionsPaneWidth = 0.0f ;
prFileDialogInternal . puDLGuserDatas = vUserDatas ;
prFileDialogInternal . puDLGflags = vFlags ;
2022-04-25 23:58:17 +00:00
prFileDialogInternal . puDLGselFun = vSelectFun ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGmodal = false ;
auto ps = IGFD : : Utils : : ParsePathFileName ( vFilePathName ) ;
if ( ps . isOk )
{
prFileDialogInternal . puFileManager . puDLGpath = ps . path ;
prFileDialogInternal . puFileManager . SetDefaultFileName ( vFilePathName ) ;
prFileDialogInternal . puFilterManager . puDLGdefaultExt = " . " + ps . ext ;
}
else
{
prFileDialogInternal . puFileManager . puDLGpath = prFileDialogInternal . puFileManager . GetCurrentPath ( ) ;
prFileDialogInternal . puFileManager . SetDefaultFileName ( " " ) ;
prFileDialogInternal . puFilterManager . puDLGdefaultExt . clear ( ) ;
}
prFileDialogInternal . puFilterManager . ParseFilters ( vFilters ) ;
prFileDialogInternal . puFilterManager . SetSelectedFilterWithExt (
prFileDialogInternal . puFilterManager . puDLGdefaultExt ) ;
prFileDialogInternal . puFileManager . SetCurrentPath ( prFileDialogInternal . puFileManager . puDLGpath ) ;
prFileDialogInternal . puFileManager . puDLGDirectoryMode = ( vFilters = = nullptr ) ;
prFileDialogInternal . puFileManager . puDLGcountSelectionMax = vCountSelectionMax ; //-V101
prFileDialogInternal . puFileManager . ClearAll ( ) ;
prFileDialogInternal . puShowDialog = true ;
}
// with pane
// path and fileNameExt can be specified
void IGFD : : FileDialog : : OpenDialog (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vPath ,
const std : : string & vFileName ,
const PaneFun & vSidePane ,
const float & vSidePaneWidth ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
prFileDialogInternal . ResetForNewDialog ( ) ;
prFileDialogInternal . puDLGkey = vKey ;
prFileDialogInternal . puDLGtitle = vTitle ;
prFileDialogInternal . puDLGuserDatas = vUserDatas ;
prFileDialogInternal . puDLGflags = vFlags ;
2022-04-25 23:58:17 +00:00
prFileDialogInternal . puDLGselFun = vSelectFun ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGoptionsPane = vSidePane ;
prFileDialogInternal . puDLGoptionsPaneWidth = vSidePaneWidth ;
prFileDialogInternal . puDLGmodal = false ;
prFileDialogInternal . puFilterManager . puDLGdefaultExt . clear ( ) ;
prFileDialogInternal . puFilterManager . ParseFilters ( vFilters ) ;
prFileDialogInternal . puFileManager . puDLGcountSelectionMax = ( size_t ) vCountSelectionMax ;
prFileDialogInternal . puFileManager . puDLGDirectoryMode = ( vFilters = = nullptr ) ;
if ( vPath . empty ( ) )
prFileDialogInternal . puFileManager . puDLGpath = prFileDialogInternal . puFileManager . GetCurrentPath ( ) ;
else
prFileDialogInternal . puFileManager . puDLGpath = vPath ;
prFileDialogInternal . puFileManager . SetCurrentPath ( prFileDialogInternal . puFileManager . puDLGpath ) ;
prFileDialogInternal . puFileManager . SetDefaultFileName ( vFileName ) ;
prFileDialogInternal . puFileManager . ClearAll ( ) ;
prFileDialogInternal . puShowDialog = true ; // open dialog
}
// with pane
// path and filename are obtained from filePathName
void IGFD : : FileDialog : : OpenDialog (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vFilePathName ,
const PaneFun & vSidePane ,
const float & vSidePaneWidth ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
prFileDialogInternal . ResetForNewDialog ( ) ;
prFileDialogInternal . puDLGkey = vKey ;
prFileDialogInternal . puDLGtitle = vTitle ;
prFileDialogInternal . puDLGoptionsPane = vSidePane ;
prFileDialogInternal . puDLGoptionsPaneWidth = vSidePaneWidth ;
prFileDialogInternal . puDLGuserDatas = vUserDatas ;
prFileDialogInternal . puDLGflags = vFlags ;
2022-04-25 23:58:17 +00:00
prFileDialogInternal . puDLGselFun = vSelectFun ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGmodal = false ;
auto ps = IGFD : : Utils : : ParsePathFileName ( vFilePathName ) ;
if ( ps . isOk )
{
prFileDialogInternal . puFileManager . puDLGpath = ps . path ;
prFileDialogInternal . puFileManager . SetDefaultFileName ( vFilePathName ) ;
prFileDialogInternal . puFilterManager . puDLGdefaultExt = " . " + ps . ext ;
}
else
{
prFileDialogInternal . puFileManager . puDLGpath = prFileDialogInternal . puFileManager . GetCurrentPath ( ) ;
prFileDialogInternal . puFileManager . SetDefaultFileName ( " " ) ;
prFileDialogInternal . puFilterManager . puDLGdefaultExt . clear ( ) ;
}
prFileDialogInternal . puFileManager . SetCurrentPath ( prFileDialogInternal . puFileManager . puDLGpath ) ;
prFileDialogInternal . puFileManager . puDLGcountSelectionMax = vCountSelectionMax ; //-V101
prFileDialogInternal . puFileManager . puDLGDirectoryMode = ( vFilters = = nullptr ) ;
prFileDialogInternal . puFilterManager . ParseFilters ( vFilters ) ;
prFileDialogInternal . puFilterManager . SetSelectedFilterWithExt (
prFileDialogInternal . puFilterManager . puDLGdefaultExt ) ;
prFileDialogInternal . puFileManager . ClearAll ( ) ;
prFileDialogInternal . puShowDialog = true ;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
///// FILE DIALOG MODAL DIALOG ///////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
void IGFD : : FileDialog : : OpenModal (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vPath ,
const std : : string & vFileName ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
OpenDialog (
vKey , vTitle , vFilters ,
vPath , vFileName ,
2022-04-25 23:58:17 +00:00
vCountSelectionMax , vUserDatas , vFlags , vSelectFun ) ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGmodal = true ;
}
void IGFD : : FileDialog : : OpenModal (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vFilePathName ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
OpenDialog (
vKey , vTitle , vFilters ,
vFilePathName ,
2022-04-25 23:58:17 +00:00
vCountSelectionMax , vUserDatas , vFlags , vSelectFun ) ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGmodal = true ;
}
// with pane
// path and fileNameExt can be specified
void IGFD : : FileDialog : : OpenModal (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vPath ,
const std : : string & vFileName ,
const PaneFun & vSidePane ,
const float & vSidePaneWidth ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
OpenDialog (
vKey , vTitle , vFilters ,
vPath , vFileName ,
vSidePane , vSidePaneWidth ,
2022-04-25 23:58:17 +00:00
vCountSelectionMax , vUserDatas , vFlags , vSelectFun ) ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGmodal = true ;
}
// with pane
// path and filename are obtained from filePathName
void IGFD : : FileDialog : : OpenModal (
const std : : string & vKey ,
const std : : string & vTitle ,
const char * vFilters ,
const std : : string & vFilePathName ,
const PaneFun & vSidePane ,
const float & vSidePaneWidth ,
const int & vCountSelectionMax ,
UserDatas vUserDatas ,
2022-04-25 23:58:17 +00:00
ImGuiFileDialogFlags vFlags ,
SelectFun vSelectFun )
2021-12-11 07:10:09 +00:00
{
if ( prFileDialogInternal . puShowDialog ) // if already opened, quit
return ;
OpenDialog (
vKey , vTitle , vFilters ,
vFilePathName ,
vSidePane , vSidePaneWidth ,
2022-04-25 23:58:17 +00:00
vCountSelectionMax , vUserDatas , vFlags , vSelectFun ) ;
2021-12-11 07:10:09 +00:00
prFileDialogInternal . puDLGmodal = true ;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
///// FILE DIALOG DISPLAY FUNCTION ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
bool IGFD : : FileDialog : : Display ( const std : : string & vKey , ImGuiWindowFlags vFlags , ImVec2 vMinSize , ImVec2 vMaxSize )
{
bool res = false ;
if ( prFileDialogInternal . puShowDialog & & prFileDialogInternal . puDLGkey = = vKey )
{
if ( prFileDialogInternal . puUseCustomLocale )
setlocale ( prFileDialogInternal . puLocaleCategory , prFileDialogInternal . puLocaleBegin . c_str ( ) ) ;
auto & fdFile = prFileDialogInternal . puFileManager ;
auto & fdFilter = prFileDialogInternal . puFilterManager ;
static ImGuiWindowFlags flags ;
// to be sure than only one dialog is displayed per frame
ImGuiContext & g = * GImGui ;
if ( g . FrameCount = = prFileDialogInternal . puLastImGuiFrameCount ) // one instance was displayed this frame before for this key +> quit
return res ;
prFileDialogInternal . puLastImGuiFrameCount = g . FrameCount ; // mark this instance as used this frame
std : : string name = prFileDialogInternal . puDLGtitle + " ## " + prFileDialogInternal . puDLGkey ;
if ( prFileDialogInternal . puName ! = name )
{
fdFile . ClearComposer ( ) ;
fdFile . ClearFileLists ( ) ;
flags = vFlags ;
}
NewFrame ( ) ;
# ifdef IMGUI_HAS_VIEWPORT
if ( ! ImGui : : GetIO ( ) . ConfigViewportsNoDecoration )
{
// https://github.com/ocornut/imgui/issues/4534
ImGuiWindowClass window_class ;
window_class . ViewportFlagsOverrideClear = ImGuiViewportFlags_NoDecoration ;
ImGui : : SetNextWindowClass ( & window_class ) ;
}
# endif // IMGUI_HAS_VIEWPORT
ImGui : : SetNextWindowSizeConstraints ( vMinSize , vMaxSize ) ;
bool beg = false ;
if ( prFileDialogInternal . puDLGmodal & &
! prFileDialogInternal . puOkResultToConfirm ) // disable modal because the confirm dialog for overwrite is a new modal
{
ImGui : : OpenPopup ( name . c_str ( ) ) ;
beg = ImGui : : BeginPopupModal ( name . c_str ( ) , ( bool * ) nullptr ,
flags | ImGuiWindowFlags_NoScrollbar ) ;
}
else
{
2021-12-17 05:26:33 +00:00
beg = ImGui : : Begin ( name . c_str ( ) , ( bool * ) nullptr , flags | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking ) ;
2021-12-11 07:10:09 +00:00
}
if ( beg )
{
2022-01-20 05:31:36 +00:00
ImGui : : SetWindowPos ( ImVec2 ( ( ImGui : : GetMainViewport ( ) - > Size . x - ImGui : : GetWindowWidth ( ) ) * 0.5f , ( ImGui : : GetMainViewport ( ) - > Size . y - ImGui : : GetWindowHeight ( ) ) * 0.5f ) ) ;
2022-01-31 20:03:10 +00:00
if ( ImGui : : GetWindowSize ( ) . x < vMinSize . x | | ImGui : : GetWindowSize ( ) . y < vMinSize . y ) {
ImGui : : SetWindowSize ( vMinSize , ImGuiCond_Always ) ;
}
2021-12-11 07:10:09 +00:00
# ifdef IMGUI_HAS_VIEWPORT
// if decoration is enabled we disable the resizing feature of imgui for avoid crash with SDL2 and GLFW3
if ( ImGui : : GetIO ( ) . ConfigViewportsNoDecoration )
{
flags = vFlags ;
}
else
{
auto win = ImGui : : GetCurrentWindowRead ( ) ;
if ( win - > Viewport - > Idx ! = 0 )
flags | = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar ;
else
flags = vFlags ;
}
# endif // IMGUI_HAS_VIEWPORT
prFileDialogInternal . puName = name ; //-V820
puAnyWindowsHovered | = ImGui : : IsWindowHovered ( ) ;
if ( fdFile . puDLGpath . empty ( ) )
fdFile . puDLGpath = " . " ; // defaut path is '.'
fdFilter . SetDefaultFilterIfNotDefined ( ) ;
// init list of files
if ( fdFile . IsFileListEmpty ( ) & & ! fdFile . puShowDrives )
{
IGFD : : Utils : : ReplaceString ( fdFile . puDLGDefaultFileName , fdFile . puDLGpath , " " ) ; // local path
if ( ! fdFile . puDLGDefaultFileName . empty ( ) )
{
fdFile . SetDefaultFileName ( fdFile . puDLGDefaultFileName ) ;
fdFilter . SetSelectedFilterWithExt ( fdFilter . puDLGdefaultExt ) ;
}
else if ( fdFile . puDLGDirectoryMode ) // directory mode
fdFile . SetDefaultFileName ( " . " ) ;
fdFile . ScanDir ( prFileDialogInternal , fdFile . puDLGpath ) ;
}
// draw dialog parts
prDrawHeader ( ) ; // bookmark, directory, path
2022-02-01 07:52:36 +00:00
res = prDrawContent ( ) ; // bookmark, files view, side pane
bool res1 = prDrawFooter ( ) ; // file field, filter combobox, ok/cancel buttons
if ( ! res ) res = res1 ;
2021-12-11 07:10:09 +00:00
EndFrame ( ) ;
// for display in dialog center, the confirm to overwrite dlg
prFileDialogInternal . puDialogCenterPos = ImGui : : GetCurrentWindowRead ( ) - > ContentRegionRect . GetCenter ( ) ;
// when the confirm to overwrite dialog will appear we need to
// disable the modal mode of the main file dialog
// see prOkResultToConfirm under
if ( prFileDialogInternal . puDLGmodal & &
! prFileDialogInternal . puOkResultToConfirm )
ImGui : : EndPopup ( ) ;
}
// same things here regarding prOkResultToConfirm
if ( ! prFileDialogInternal . puDLGmodal | | prFileDialogInternal . puOkResultToConfirm )
ImGui : : End ( ) ;
// confirm the result and show the confirm to overwrite dialog if needed
res = prConfirm_Or_OpenOverWriteFileDialog_IfNeeded ( res , vFlags ) ;
if ( prFileDialogInternal . puUseCustomLocale )
setlocale ( prFileDialogInternal . puLocaleCategory , prFileDialogInternal . puLocaleEnd . c_str ( ) ) ;
}
return res ;
}
void IGFD : : FileDialog : : NewFrame ( )
{
prFileDialogInternal . NewFrame ( ) ;
NewThumbnailFrame ( prFileDialogInternal ) ;
}
void IGFD : : FileDialog : : EndFrame ( )
{
EndThumbnailFrame ( prFileDialogInternal ) ;
prFileDialogInternal . EndFrame ( ) ;
}
void IGFD : : FileDialog : : QuitFrame ( )
{
QuitThumbnailFrame ( prFileDialogInternal ) ;
}
void IGFD : : FileDialog : : prDrawHeader ( )
{
# ifdef USE_BOOKMARK
prDrawBookmarkButton ( ) ;
ImGui : : SameLine ( ) ;
# endif // USE_BOOKMARK
prFileDialogInternal . puFileManager . DrawDirectoryCreation ( prFileDialogInternal ) ;
ImGui : : SameLine ( ) ;
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
ImGui : : SameLine ( ) ;
prFileDialogInternal . puFileManager . DrawPathComposer ( prFileDialogInternal ) ;
# ifdef USE_THUMBNAILS
if ( ! ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_DisableThumbnailMode ) )
{
prDrawDisplayModeToolBar ( ) ;
ImGui : : SameLine ( ) ;
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
ImGui : : SameLine ( ) ;
}
# endif // USE_THUMBNAILS
prFileDialogInternal . puSearchManager . DrawSearchBar ( prFileDialogInternal ) ;
}
2022-02-01 07:52:36 +00:00
bool IGFD : : FileDialog : : prDrawContent ( )
2021-12-11 07:10:09 +00:00
{
2022-02-01 07:52:36 +00:00
bool escape = false ;
2021-12-11 07:10:09 +00:00
ImVec2 size = ImGui : : GetContentRegionAvail ( ) - ImVec2 ( 0.0f , prFileDialogInternal . puFooterHeight ) ;
# ifdef USE_BOOKMARK
if ( prBookmarkPaneShown )
{
//size.x -= prBookmarkWidth;
float otherWidth = size . x - prBookmarkWidth ;
ImGui : : PushID ( " ##splitterbookmark " ) ;
IGFD : : Utils : : Splitter ( true , 4.0f ,
& prBookmarkWidth , & otherWidth , 10.0f ,
10.0f + prFileDialogInternal . puDLGoptionsPaneWidth , size . y ) ;
ImGui : : PopID ( ) ;
size . x - = otherWidth ;
prDrawBookmarkPane ( prFileDialogInternal , size ) ;
ImGui : : SameLine ( ) ;
}
# endif // USE_BOOKMARK
size . x = ImGui : : GetContentRegionAvail ( ) . x - prFileDialogInternal . puDLGoptionsPaneWidth ;
if ( prFileDialogInternal . puDLGoptionsPane )
{
ImGui : : PushID ( " ##splittersidepane " ) ;
IGFD : : Utils : : Splitter ( true , 4.0f , & size . x , & prFileDialogInternal . puDLGoptionsPaneWidth , 10.0f , 10.0f , size . y ) ;
ImGui : : PopID ( ) ;
}
# ifdef USE_THUMBNAILS
if ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_DisableThumbnailMode )
{
prDrawFileListView ( size ) ;
}
else
{
switch ( prDisplayMode )
{
case DisplayModeEnum : : FILE_LIST :
prDrawFileListView ( size ) ;
break ;
case DisplayModeEnum : : THUMBNAILS_LIST :
prDrawThumbnailsListView ( size ) ;
break ;
case DisplayModeEnum : : THUMBNAILS_GRID :
prDrawThumbnailsGridView ( size ) ;
}
}
# else
2022-02-01 07:52:36 +00:00
escape = prDrawFileListView ( size ) ;
2021-12-11 07:10:09 +00:00
# endif // USE_THUMBNAILS
if ( prFileDialogInternal . puDLGoptionsPane )
{
prDrawSidePane ( size . y ) ;
}
2022-02-01 07:52:36 +00:00
return escape ;
2021-12-11 07:10:09 +00:00
}
bool IGFD : : FileDialog : : prDrawFooter ( )
{
auto & fdFile = prFileDialogInternal . puFileManager ;
float posY = ImGui : : GetCursorPos ( ) . y ; // height of last bar calc
if ( ! fdFile . puDLGDirectoryMode )
ImGui : : Text ( fileNameString ) ;
else // directory chooser
ImGui : : Text ( dirNameString ) ;
ImGui : : SameLine ( ) ;
// Input file fields
float width = ImGui : : GetContentRegionAvail ( ) . x ;
2022-02-23 02:54:25 +00:00
// fix this! fix this! fix this!
2021-12-11 07:10:09 +00:00
if ( ! fdFile . puDLGDirectoryMode )
2022-02-23 03:41:37 +00:00
width - = FILTER_COMBO_WIDTH * DpiScale ;
2021-12-11 07:10:09 +00:00
ImGui : : PushItemWidth ( width ) ;
ImGui : : InputText ( " ##FileName " , fdFile . puFileNameBuffer , MAX_FILE_DIALOG_NAME_BUFFER ) ;
if ( ImGui : : GetItemID ( ) = = ImGui : : GetActiveID ( ) )
prFileDialogInternal . puFileInputIsActive = true ;
ImGui : : PopItemWidth ( ) ;
// combobox of filters
prFileDialogInternal . puFilterManager . DrawFilterComboBox ( prFileDialogInternal ) ;
bool res = false ;
// OK Button
if ( prFileDialogInternal . puCanWeContinue & & strlen ( fdFile . puFileNameBuffer ) )
{
if ( IMGUI_BUTTON ( okButtonString " ##validationdialog " ) )
{
prFileDialogInternal . puIsOk = true ;
res = true ;
}
ImGui : : SameLine ( ) ;
}
// Cancel Button
if ( IMGUI_BUTTON ( cancelButtonString " ##validationdialog " ) | |
prFileDialogInternal . puNeedToExitDialog ) // dialog exit asked
{
prFileDialogInternal . puIsOk = false ;
res = true ;
}
prFileDialogInternal . puFooterHeight = ImGui : : GetCursorPosY ( ) - posY ;
return res ;
}
2022-02-01 07:52:36 +00:00
// returns 0 if not break loop, 1 if break loop, 2 if exit dialog
int IGFD : : FileDialog : : prSelectableItem ( int vidx , std : : shared_ptr < FileInfos > vInfos , bool vSelected , const char * vFmt , . . . )
2021-12-11 07:10:09 +00:00
{
if ( ! vInfos . use_count ( ) )
2022-02-01 07:52:36 +00:00
return 0 ;
2021-12-11 07:10:09 +00:00
auto & fdi = prFileDialogInternal . puFileManager ;
static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick |
ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth ;
2022-03-13 22:29:43 +00:00
// TODO BUG?!
2022-10-28 09:16:07 +00:00
// YES BUG: THIS JUST CRASHED FOR SOME REASON
2021-12-11 07:10:09 +00:00
va_list args ;
va_start ( args , vFmt ) ;
vsnprintf ( fdi . puVariadicBuffer , MAX_FILE_DIALOG_NAME_BUFFER , vFmt , args ) ;
va_end ( args ) ;
float h = 0.0f ;
# ifdef USE_THUMBNAILS
if ( prDisplayMode = = DisplayModeEnum : : THUMBNAILS_LIST )
h = DisplayMode_ThumbailsList_ImageHeight ;
# endif // USE_THUMBNAILS
# ifdef USE_EXPLORATION_BY_KEYS
bool flashed = prBeginFlashItem ( ( size_t ) vidx ) ;
bool res = prFlashableSelectable ( fdi . puVariadicBuffer , vSelected , selectableFlags ,
flashed , ImVec2 ( - 1.0f , h ) ) ;
if ( flashed )
prEndFlashItem ( ) ;
# else // USE_EXPLORATION_BY_KEYS
( void ) vidx ; // remove a warnings ofr unused var
bool res = ImGui : : Selectable ( fdi . puVariadicBuffer , vSelected , selectableFlags , ImVec2 ( - 1.0f , h ) ) ;
# endif // USE_EXPLORATION_BY_KEYS
if ( res )
{
if ( vInfos - > fileType = = ' d ' )
{
2022-02-01 07:52:36 +00:00
bool isSelectingDir = false ;
2021-12-11 07:10:09 +00:00
// nav system, selectebale cause open directory or select directory
if ( ImGui : : GetIO ( ) . ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard )
{
if ( fdi . puDLGDirectoryMode ) // directory chooser
{
fdi . SelectFileName ( prFileDialogInternal , vInfos ) ;
}
else
{
fdi . puPathClicked = fdi . SelectDirectory ( vInfos ) ;
2022-02-01 07:52:36 +00:00
isSelectingDir = true ;
2021-12-11 07:10:09 +00:00
}
}
else // no nav system => classic behavior
{
if ( ImGui : : IsMouseDoubleClicked ( 0 ) ) // 0 -> left mouse button double click
{
2022-02-01 07:52:36 +00:00
isSelectingDir = true ;
2021-12-11 07:10:09 +00:00
fdi . puPathClicked = fdi . SelectDirectory ( vInfos ) ;
}
else if ( fdi . puDLGDirectoryMode ) // directory chooser
{
fdi . SelectFileName ( prFileDialogInternal , vInfos ) ;
}
}
2022-02-01 07:52:36 +00:00
return isSelectingDir ; // needToBreakTheloop
2021-12-11 07:10:09 +00:00
}
else
{
2022-02-01 07:52:36 +00:00
if ( ImGui : : IsMouseDoubleClicked ( 0 ) ) {
fdi . SelectFileName ( prFileDialogInternal , vInfos ) ;
prFileDialogInternal . puIsOk = true ;
return 2 ;
} else {
fdi . SelectFileName ( prFileDialogInternal , vInfos ) ;
2022-04-25 23:58:17 +00:00
if ( prFileDialogInternal . puDLGselFun ! = NULL ) {
2022-10-17 00:40:14 +00:00
std : : string argPath ;
for ( auto & i : GetSelection ( ) ) {
argPath = i . second ;
}
if ( ! argPath . empty ( ) ) {
prFileDialogInternal . puDLGselFun ( argPath . c_str ( ) ) ;
}
2022-04-25 23:58:17 +00:00
}
2022-02-01 07:52:36 +00:00
}
2021-12-11 07:10:09 +00:00
}
}
2022-02-01 07:52:36 +00:00
return 0 ;
2021-12-11 07:10:09 +00:00
}
void IGFD : : FileDialog : : prBeginFileColorIconStyle ( std : : shared_ptr < FileInfos > vFileInfos , bool & vOutShowColor , std : : string & vOutStr , ImFont * * vOutFont )
{
vOutStr . clear ( ) ;
vOutShowColor = false ;
if ( vFileInfos - > fileStyle . use_count ( ) ) //-V807 //-V522
{
vOutShowColor = true ;
* vOutFont = vFileInfos - > fileStyle - > font ;
}
if ( vOutShowColor & & ! vFileInfos - > fileStyle - > icon . empty ( ) ) vOutStr = vFileInfos - > fileStyle - > icon ;
else if ( vFileInfos - > fileType = = ' d ' ) vOutStr = dirEntryString ;
else if ( vFileInfos - > fileType = = ' l ' ) vOutStr = linkEntryString ;
else if ( vFileInfos - > fileType = = ' f ' ) vOutStr = fileEntryString ;
vOutStr + = " " + vFileInfos - > fileNameExt ;
if ( vOutShowColor )
ImGui : : PushStyleColor ( ImGuiCol_Text , vFileInfos - > fileStyle - > color ) ;
if ( * vOutFont )
ImGui : : PushFont ( * vOutFont ) ;
}
void IGFD : : FileDialog : : prEndFileColorIconStyle ( const bool & vShowColor , ImFont * vFont )
{
if ( vFont )
ImGui : : PopFont ( ) ;
if ( vShowColor )
ImGui : : PopStyleColor ( ) ;
}
2022-02-01 07:52:36 +00:00
bool IGFD : : FileDialog : : prDrawFileListView ( ImVec2 vSize )
2021-12-11 07:10:09 +00:00
{
2022-02-01 07:52:36 +00:00
bool escape = false ;
2021-12-11 07:10:09 +00:00
auto & fdi = prFileDialogInternal . puFileManager ;
ImGui : : PushID ( this ) ;
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg |
ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY |
ImGuiTableFlags_NoHostExtendY
# ifndef USE_CUSTOM_SORTING_ICON
| ImGuiTableFlags_Sortable
# endif // USE_CUSTOM_SORTING_ICON
;
auto listViewID = ImGui : : GetID ( " ##FileDialog_fileTable " ) ;
if ( ImGui : : BeginTableEx ( " ##FileDialog_fileTable " , listViewID , 4 , flags , vSize , 0.0f ) ) //-V112
{
ImGui : : TableSetupScrollFreeze ( 0 , 1 ) ; // Make header always visible
ImGui : : TableSetupColumn ( fdi . puHeaderFileName . c_str ( ) , ImGuiTableColumnFlags_WidthStretch , - 1 , 0 ) ;
ImGui : : TableSetupColumn ( fdi . puHeaderFileType . c_str ( ) , ImGuiTableColumnFlags_WidthFixed |
( ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_HideColumnType ) ? ImGuiTableColumnFlags_DefaultHide : 0 ) , - 1 , 1 ) ;
ImGui : : TableSetupColumn ( fdi . puHeaderFileSize . c_str ( ) , ImGuiTableColumnFlags_WidthFixed |
( ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_HideColumnSize ) ? ImGuiTableColumnFlags_DefaultHide : 0 ) , - 1 , 2 ) ;
ImGui : : TableSetupColumn ( fdi . puHeaderFileDate . c_str ( ) , ImGuiTableColumnFlags_WidthFixed |
( ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_HideColumnDate ) ? ImGuiTableColumnFlags_DefaultHide : 0 ) , - 1 , 3 ) ;
# ifndef USE_CUSTOM_SORTING_ICON
// Sort our data if sort specs have been changed!
if ( ImGuiTableSortSpecs * sorts_specs = ImGui : : TableGetSortSpecs ( ) )
{
if ( sorts_specs - > SpecsDirty & & ! fdi . IsFileListEmpty ( ) )
{
if ( sorts_specs - > Specs - > ColumnUserID = = 0 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_FILENAME , true ) ;
else if ( sorts_specs - > Specs - > ColumnUserID = = 1 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_TYPE , true ) ;
else if ( sorts_specs - > Specs - > ColumnUserID = = 2 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_SIZE , true ) ;
else //if (sorts_specs->Specs->ColumnUserID == 3) => alwayd true for the moment, to uncomment if we add a fourth column
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_DATE , true ) ;
sorts_specs - > SpecsDirty = false ;
}
}
ImGui : : TableHeadersRow ( ) ;
# else // USE_CUSTOM_SORTING_ICON
ImGui : : TableNextRow ( ImGuiTableRowFlags_Headers ) ;
for ( int column = 0 ; column < 4 ; column + + ) //-V112
{
ImGui : : TableSetColumnIndex ( column ) ;
const char * column_name = ImGui : : TableGetColumnName ( column ) ; // Retrieve name passed to TableSetupColumn()
ImGui : : PushID ( column ) ;
ImGui : : TableHeader ( column_name ) ;
ImGui : : PopID ( ) ;
if ( ImGui : : IsItemClicked ( ) )
{
if ( column = = 0 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_FILENAME , true ) ;
else if ( column = = 1 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_TYPE , true ) ;
else if ( column = = 2 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_SIZE , true ) ;
else //if (column == 3) => alwayd true for the moment, to uncomment if we add a fourth column
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_DATE , true ) ;
}
}
# endif // USE_CUSTOM_SORTING_ICON
if ( ! fdi . IsFilteredListEmpty ( ) )
{
std : : string _str ;
ImFont * _font = nullptr ;
bool _showColor = false ;
prFileListClipper . Begin ( ( int ) fdi . GetFilteredListSize ( ) , ImGui : : GetTextLineHeightWithSpacing ( ) ) ;
while ( prFileListClipper . Step ( ) )
{
for ( int i = prFileListClipper . DisplayStart ; i < prFileListClipper . DisplayEnd ; i + + )
{
if ( i < 0 ) continue ;
auto infos = fdi . GetFilteredFileAt ( ( size_t ) i ) ;
if ( ! infos . use_count ( ) )
continue ;
prBeginFileColorIconStyle ( infos , _showColor , _str , & _font ) ;
bool selected = fdi . IsFileNameSelected ( infos - > fileNameExt ) ; // found
ImGui : : TableNextRow ( ) ;
2022-02-01 07:52:36 +00:00
int needToBreakTheloop = false ;
2021-12-11 07:10:09 +00:00
if ( ImGui : : TableNextColumn ( ) ) // file name
{
2022-03-13 22:29:43 +00:00
// TODO BUG?!?!?!
2022-10-28 09:16:07 +00:00
// YES BUG
needToBreakTheloop = prSelectableItem ( i , infos , selected , " %s " , _str . c_str ( ) ) ;
2022-02-01 07:52:36 +00:00
if ( needToBreakTheloop = = 2 ) escape = true ;
2021-12-11 07:10:09 +00:00
}
if ( ImGui : : TableNextColumn ( ) ) // file type
{
ImGui : : Text ( " %s " , infos - > fileExt . c_str ( ) ) ;
}
if ( ImGui : : TableNextColumn ( ) ) // file size
{
if ( infos - > fileType ! = ' d ' )
{
ImGui : : Text ( " %s " , infos - > formatedFileSize . c_str ( ) ) ;
}
else
{
ImGui : : Text ( " %s " , " " ) ;
}
}
if ( ImGui : : TableNextColumn ( ) ) // file date + time
{
ImGui : : Text ( " %s " , infos - > fileModifDate . c_str ( ) ) ;
}
prEndFileColorIconStyle ( _showColor , _font ) ;
2022-02-01 07:52:36 +00:00
if ( needToBreakTheloop = = 1 )
2021-12-11 07:10:09 +00:00
break ;
}
}
prFileListClipper . End ( ) ;
}
# ifdef USE_EXPLORATION_BY_KEYS
if ( ! fdi . puInputPathActivated )
{
prLocateByInputKey ( prFileDialogInternal ) ;
prExploreWithkeys ( prFileDialogInternal , listViewID ) ;
}
# endif // USE_EXPLORATION_BY_KEYS
ImGuiContext & g = * GImGui ;
if ( g . LastActiveId - 1 = = listViewID | | g . LastActiveId = = listViewID )
{
prFileDialogInternal . puFileListViewIsActive = true ;
}
ImGui : : EndTable ( ) ;
}
ImGui : : PopID ( ) ;
2022-02-01 07:52:36 +00:00
return escape ;
2021-12-11 07:10:09 +00:00
}
# ifdef USE_THUMBNAILS
void IGFD : : FileDialog : : prDrawThumbnailsListView ( ImVec2 vSize )
{
auto & fdi = prFileDialogInternal . puFileManager ;
ImGui : : PushID ( this ) ;
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg |
ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY |
ImGuiTableFlags_NoHostExtendY
# ifndef USE_CUSTOM_SORTING_ICON
| ImGuiTableFlags_Sortable
# endif // USE_CUSTOM_SORTING_ICON
;
auto listViewID = ImGui : : GetID ( " ##FileDialog_fileTable " ) ;
if ( ImGui : : BeginTableEx ( " ##FileDialog_fileTable " , listViewID , 5 , flags , vSize , 0.0f ) )
{
ImGui : : TableSetupScrollFreeze ( 0 , 1 ) ; // Make header always visible
ImGui : : TableSetupColumn ( fdi . puHeaderFileName . c_str ( ) , ImGuiTableColumnFlags_WidthStretch , - 1 , 0 ) ;
ImGui : : TableSetupColumn ( fdi . puHeaderFileType . c_str ( ) , ImGuiTableColumnFlags_WidthFixed |
( ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_HideColumnType ) ? ImGuiTableColumnFlags_DefaultHide : 0 ) , - 1 , 1 ) ;
ImGui : : TableSetupColumn ( fdi . puHeaderFileSize . c_str ( ) , ImGuiTableColumnFlags_WidthFixed |
( ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_HideColumnSize ) ? ImGuiTableColumnFlags_DefaultHide : 0 ) , - 1 , 2 ) ;
ImGui : : TableSetupColumn ( fdi . puHeaderFileDate . c_str ( ) , ImGuiTableColumnFlags_WidthFixed |
( ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_HideColumnDate ) ? ImGuiTableColumnFlags_DefaultHide : 0 ) , - 1 , 3 ) ;
// not needed to have an option for hide the thumbnails since this is why this view is used
ImGui : : TableSetupColumn ( fdi . puHeaderFileThumbnails . c_str ( ) , ImGuiTableColumnFlags_WidthFixed , - 1 , 4 ) ; //-V112
# ifndef USE_CUSTOM_SORTING_ICON
// Sort our data if sort specs have been changed!
if ( ImGuiTableSortSpecs * sorts_specs = ImGui : : TableGetSortSpecs ( ) )
{
if ( sorts_specs - > SpecsDirty & & ! fdi . IsFileListEmpty ( ) )
{
if ( sorts_specs - > Specs - > ColumnUserID = = 0 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_FILENAME , true ) ;
else if ( sorts_specs - > Specs - > ColumnUserID = = 1 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_TYPE , true ) ;
else if ( sorts_specs - > Specs - > ColumnUserID = = 2 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_SIZE , true ) ;
else if ( sorts_specs - > Specs - > ColumnUserID = = 3 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_DATE , true ) ;
else // if (sorts_specs->Specs->ColumnUserID == 4) = > always true for the moment, to uncomment if we add another column
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_THUMBNAILS , true ) ;
sorts_specs - > SpecsDirty = false ;
}
}
ImGui : : TableHeadersRow ( ) ;
# else // USE_CUSTOM_SORTING_ICON
ImGui : : TableNextRow ( ImGuiTableRowFlags_Headers ) ;
for ( int column = 0 ; column < 5 ; column + + )
{
ImGui : : TableSetColumnIndex ( column ) ;
const char * column_name = ImGui : : TableGetColumnName ( column ) ; // Retrieve name passed to TableSetupColumn()
ImGui : : PushID ( column ) ;
ImGui : : TableHeader ( column_name ) ;
ImGui : : PopID ( ) ;
if ( ImGui : : IsItemClicked ( ) )
{
if ( column = = 0 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_FILENAME , true ) ;
else if ( column = = 1 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_TYPE , true ) ;
else if ( column = = 2 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_SIZE , true ) ;
else if ( column = = 3 )
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_DATE , true ) ;
else // if (column == 4) = > always true for the moment, to uncomment if we add another column
fdi . SortFields ( prFileDialogInternal , IGFD : : FileManager : : SortingFieldEnum : : FIELD_THUMBNAILS , true ) ;
}
}
# endif // USE_CUSTOM_SORTING_ICON
if ( ! fdi . IsFilteredListEmpty ( ) )
{
std : : string _str ;
ImFont * _font = nullptr ;
bool _showColor = false ;
ImGuiContext & g = * GImGui ;
const float itemHeight = ImMax ( g . FontSize , DisplayMode_ThumbailsList_ImageHeight ) + g . Style . ItemSpacing . y ;
prFileListClipper . Begin ( ( int ) fdi . GetFilteredListSize ( ) , itemHeight ) ;
while ( prFileListClipper . Step ( ) )
{
for ( int i = prFileListClipper . DisplayStart ; i < prFileListClipper . DisplayEnd ; i + + )
{
if ( i < 0 ) continue ;
auto infos = fdi . GetFilteredFileAt ( ( size_t ) i ) ;
if ( ! infos . use_count ( ) )
continue ;
prBeginFileColorIconStyle ( infos , _showColor , _str , & _font ) ;
bool selected = fdi . IsFileNameSelected ( infos - > fileNameExt ) ; // found
ImGui : : TableNextRow ( ) ;
bool needToBreakTheloop = false ;
if ( ImGui : : TableNextColumn ( ) ) // file name
{
needToBreakTheloop = prSelectableItem ( i , infos , selected , _str . c_str ( ) ) ;
}
if ( ImGui : : TableNextColumn ( ) ) // file type
{
ImGui : : Text ( " %s " , infos - > fileExt . c_str ( ) ) ;
}
if ( ImGui : : TableNextColumn ( ) ) // file size
{
if ( infos - > fileType ! = ' d ' )
{
ImGui : : Text ( " %s " , infos - > formatedFileSize . c_str ( ) ) ;
}
else
{
ImGui : : Text ( " " ) ;
}
}
if ( ImGui : : TableNextColumn ( ) ) // file date + time
{
ImGui : : Text ( " %s " , infos - > fileModifDate . c_str ( ) ) ;
}
if ( ImGui : : TableNextColumn ( ) ) // file thumbnails
{
auto th = & infos - > thumbnailInfo ;
if ( ! th - > isLoadingOrLoaded )
{
prAddThumbnailToLoad ( infos ) ;
}
if ( th - > isReadyToDisplay & &
th - > textureID )
{
ImGui : : Image ( ( ImTextureID ) th - > textureID ,
ImVec2 ( ( float ) th - > textureWidth ,
( float ) th - > textureHeight ) ) ;
}
}
prEndFileColorIconStyle ( _showColor , _font ) ;
if ( needToBreakTheloop )
break ;
}
}
prFileListClipper . End ( ) ;
}
# ifdef USE_EXPLORATION_BY_KEYS
if ( ! fdi . puInputPathActivated )
{
prLocateByInputKey ( prFileDialogInternal ) ;
prExploreWithkeys ( prFileDialogInternal , listViewID ) ;
}
# endif // USE_EXPLORATION_BY_KEYS
ImGuiContext & g = * GImGui ;
if ( g . LastActiveId - 1 = = listViewID | | g . LastActiveId = = listViewID )
{
prFileDialogInternal . puFileListViewIsActive = true ;
}
ImGui : : EndTable ( ) ;
}
ImGui : : PopID ( ) ;
}
void IGFD : : FileDialog : : prDrawThumbnailsGridView ( ImVec2 vSize )
{
if ( ImGui : : BeginChild ( " ##thumbnailsGridsFiles " , vSize ) )
{
// todo
}
ImGui : : EndChild ( ) ;
}
# endif
void IGFD : : FileDialog : : prDrawSidePane ( float vHeight )
{
ImGui : : SameLine ( ) ;
ImGui : : BeginChild ( " ##FileTypes " , ImVec2 ( 0 , vHeight ) ) ;
prFileDialogInternal . puDLGoptionsPane (
prFileDialogInternal . puFilterManager . GetSelectedFilter ( ) . filter . c_str ( ) ,
prFileDialogInternal . puDLGuserDatas , & prFileDialogInternal . puCanWeContinue ) ;
ImGui : : EndChild ( ) ;
}
void IGFD : : FileDialog : : Close ( )
{
prFileDialogInternal . puDLGkey . clear ( ) ;
prFileDialogInternal . puShowDialog = false ;
}
bool IGFD : : FileDialog : : WasOpenedThisFrame ( const std : : string & vKey ) const
{
bool res = prFileDialogInternal . puShowDialog & & prFileDialogInternal . puDLGkey = = vKey ;
if ( res )
{
ImGuiContext & g = * GImGui ;
res & = prFileDialogInternal . puLastImGuiFrameCount = = g . FrameCount ; // return true if a dialog was displayed in this frame
}
return res ;
}
bool IGFD : : FileDialog : : WasOpenedThisFrame ( ) const
{
bool res = prFileDialogInternal . puShowDialog ;
if ( res )
{
ImGuiContext & g = * GImGui ;
res & = prFileDialogInternal . puLastImGuiFrameCount = = g . FrameCount ; // return true if a dialog was displayed in this frame
}
return res ;
}
bool IGFD : : FileDialog : : IsOpened ( const std : : string & vKey ) const
{
return ( prFileDialogInternal . puShowDialog & & prFileDialogInternal . puDLGkey = = vKey ) ;
}
bool IGFD : : FileDialog : : IsOpened ( ) const
{
return prFileDialogInternal . puShowDialog ;
}
std : : string IGFD : : FileDialog : : GetOpenedKey ( ) const
{
if ( prFileDialogInternal . puShowDialog )
return prFileDialogInternal . puDLGkey ;
return " " ;
}
std : : string IGFD : : FileDialog : : GetFilePathName ( )
{
return prFileDialogInternal . puFileManager . GetResultingFilePathName ( prFileDialogInternal ) ;
}
std : : string IGFD : : FileDialog : : GetCurrentPath ( )
{
return prFileDialogInternal . puFileManager . GetResultingPath ( ) ;
}
std : : string IGFD : : FileDialog : : GetCurrentFileName ( )
{
return prFileDialogInternal . puFileManager . GetResultingFileName ( prFileDialogInternal ) ;
}
std : : string IGFD : : FileDialog : : GetCurrentFilter ( )
{
return prFileDialogInternal . puFilterManager . GetSelectedFilter ( ) . filter ;
}
std : : map < std : : string , std : : string > IGFD : : FileDialog : : GetSelection ( )
{
return prFileDialogInternal . puFileManager . GetResultingSelection ( ) ;
}
UserDatas IGFD : : FileDialog : : GetUserDatas ( ) const
{
return prFileDialogInternal . puDLGuserDatas ;
}
bool IGFD : : FileDialog : : IsOk ( ) const
{
return prFileDialogInternal . puIsOk ;
}
void IGFD : : FileDialog : : SetFileStyle ( const IGFD_FileStyleFlags & vFlags , const char * vCriteria , const FileStyle & vInfos )
{
prFileDialogInternal . puFilterManager . SetFileStyle ( vFlags , vCriteria , vInfos ) ;
}
void IGFD : : FileDialog : : SetFileStyle ( const IGFD_FileStyleFlags & vFlags , const char * vCriteria , const ImVec4 & vColor , const std : : string & vIcon , ImFont * vFont )
{
prFileDialogInternal . puFilterManager . SetFileStyle ( vFlags , vCriteria , vColor , vIcon , vFont ) ;
}
bool IGFD : : FileDialog : : GetFileStyle ( const IGFD_FileStyleFlags & vFlags , const std : : string & vCriteria , ImVec4 * vOutColor , std : : string * vOutIcon , ImFont * * vOutFont )
{
return prFileDialogInternal . puFilterManager . GetFileStyle ( vFlags , vCriteria , vOutColor , vOutIcon , vOutFont ) ;
}
void IGFD : : FileDialog : : ClearFilesStyle ( )
{
prFileDialogInternal . puFilterManager . ClearFilesStyle ( ) ;
}
void IGFD : : FileDialog : : SetLocales ( const int & vLocaleCategory , const std : : string & vLocaleBegin , const std : : string & vLocaleEnd )
{
prFileDialogInternal . puUseCustomLocale = true ;
prFileDialogInternal . puLocaleBegin = vLocaleBegin ;
prFileDialogInternal . puLocaleEnd = vLocaleEnd ;
}
//////////////////////////////////////////////////////////////////////////////
//// OVERWRITE DIALOG ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
bool IGFD : : FileDialog : : prConfirm_Or_OpenOverWriteFileDialog_IfNeeded ( bool vLastAction , ImGuiWindowFlags vFlags )
{
// if confirmation => return true for confirm the overwrite et quit the dialog
// if cancel => return false && set IsOk to false for keep inside the dialog
// if IsOk == false => return false for quit the dialog
if ( ! prFileDialogInternal . puIsOk & & vLastAction )
{
QuitFrame ( ) ;
return true ;
}
// if IsOk == true && no check of overwrite => return true for confirm the dialog
if ( prFileDialogInternal . puIsOk & & vLastAction & & ! ( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_ConfirmOverwrite ) )
{
QuitFrame ( ) ;
return true ;
}
// if IsOk == true && check of overwrite => return false and show confirm to overwrite dialog
if ( ( prFileDialogInternal . puOkResultToConfirm | | ( prFileDialogInternal . puIsOk & & vLastAction ) ) & &
( prFileDialogInternal . puDLGflags & ImGuiFileDialogFlags_ConfirmOverwrite ) )
{
if ( prFileDialogInternal . puIsOk ) // catched only one time
{
if ( ! prFileDialogInternal . puFileManager . IsFileExist ( GetFilePathName ( ) ) ) // not existing => quit dialog
{
QuitFrame ( ) ;
return true ;
}
else // existing => confirm dialog to open
{
prFileDialogInternal . puIsOk = false ;
prFileDialogInternal . puOkResultToConfirm = true ;
}
}
std : : string name = OverWriteDialogTitleString " ## " + prFileDialogInternal . puDLGtitle + prFileDialogInternal . puDLGkey + " OverWriteDialog " ;
bool res = false ;
ImGui : : OpenPopup ( name . c_str ( ) ) ;
if ( ImGui : : BeginPopupModal ( name . c_str ( ) , ( bool * ) 0 ,
vFlags | ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) )
{
ImGui : : SetWindowPos ( prFileDialogInternal . puDialogCenterPos - ImGui : : GetWindowSize ( ) * 0.5f ) ; // next frame needed for GetWindowSize to work
ImGui : : Text ( " %s " , OverWriteDialogMessageString ) ;
if ( IMGUI_BUTTON ( OverWriteDialogConfirmButtonString ) )
{
prFileDialogInternal . puOkResultToConfirm = false ;
prFileDialogInternal . puIsOk = true ;
res = true ;
ImGui : : CloseCurrentPopup ( ) ;
}
ImGui : : SameLine ( ) ;
if ( IMGUI_BUTTON ( OverWriteDialogCancelButtonString ) )
{
prFileDialogInternal . puOkResultToConfirm = false ;
prFileDialogInternal . puIsOk = false ;
res = false ;
ImGui : : CloseCurrentPopup ( ) ;
}
ImGui : : EndPopup ( ) ;
}
if ( res )
{
QuitFrame ( ) ;
}
return res ;
}
return false ;
}
}
# endif // __cplusplus
/////////////////////////////////////////////////////////////////
///// C Interface ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// Return an initialized IGFD_Selection_Pair
IMGUIFILEDIALOG_API IGFD_Selection_Pair IGFD_Selection_Pair_Get ( void )
{
IGFD_Selection_Pair res = { } ;
res . fileName = nullptr ;
res . filePathName = nullptr ;
return res ;
}
// destroy only the content of vSelection_Pair
IMGUIFILEDIALOG_API void IGFD_Selection_Pair_DestroyContent ( IGFD_Selection_Pair * vSelection_Pair )
{
if ( vSelection_Pair )
{
delete [ ] vSelection_Pair - > fileName ;
delete [ ] vSelection_Pair - > filePathName ;
}
}
// Return an initialized IGFD_Selection
IMGUIFILEDIALOG_API IGFD_Selection IGFD_Selection_Get ( void )
{
return { nullptr , 0U } ;
}
// destroy only the content of vSelection
IMGUIFILEDIALOG_API void IGFD_Selection_DestroyContent ( IGFD_Selection * vSelection )
{
if ( vSelection )
{
if ( vSelection - > table )
{
for ( size_t i = 0U ; i < vSelection - > count ; i + + )
{
IGFD_Selection_Pair_DestroyContent ( & vSelection - > table [ i ] ) ;
}
delete [ ] vSelection - > table ;
}
vSelection - > count = 0U ;
}
}
// create an instance of ImGuiFileDialog
IMGUIFILEDIALOG_API ImGuiFileDialog * IGFD_Create ( void )
{
return new ImGuiFileDialog ( ) ;
}
// destroy the instance of ImGuiFileDialog
IMGUIFILEDIALOG_API void IGFD_Destroy ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
delete vContext ;
vContext = nullptr ;
}
}
// standard dialog
IMGUIFILEDIALOG_API void IGFD_OpenDialog (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vPath ,
const char * vFileName ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenDialog (
vKey , vTitle , vFilters , vPath , vFileName ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_OpenDialog2 (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vFilePathName ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenDialog (
vKey , vTitle , vFilters , vFilePathName ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_OpenPaneDialog (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vPath ,
const char * vFileName ,
IGFD_PaneFun vSidePane ,
const float vSidePaneWidth ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenDialog (
vKey , vTitle , vFilters ,
vPath , vFileName ,
vSidePane , vSidePaneWidth ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_OpenPaneDialog2 (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vFilePathName ,
IGFD_PaneFun vSidePane ,
const float vSidePaneWidth ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenDialog (
vKey , vTitle , vFilters ,
vFilePathName ,
vSidePane , vSidePaneWidth ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
// modal dialog
IMGUIFILEDIALOG_API void IGFD_OpenModal (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vPath ,
const char * vFileName ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenModal (
vKey , vTitle , vFilters , vPath , vFileName ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_OpenModal2 (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vFilePathName ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenModal (
vKey , vTitle , vFilters , vFilePathName ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_OpenPaneModal (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vPath ,
const char * vFileName ,
IGFD_PaneFun vSidePane ,
const float vSidePaneWidth ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenModal (
vKey , vTitle , vFilters ,
vPath , vFileName ,
vSidePane , vSidePaneWidth ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_OpenPaneModal2 (
ImGuiFileDialog * vContext ,
const char * vKey ,
const char * vTitle ,
const char * vFilters ,
const char * vFilePathName ,
IGFD_PaneFun vSidePane ,
const float vSidePaneWidth ,
const int vCountSelectionMax ,
void * vUserDatas ,
ImGuiFileDialogFlags flags )
{
if ( vContext )
{
vContext - > OpenModal (
vKey , vTitle , vFilters ,
vFilePathName ,
vSidePane , vSidePaneWidth ,
vCountSelectionMax , vUserDatas , flags ) ;
}
}
IMGUIFILEDIALOG_API bool IGFD_DisplayDialog ( ImGuiFileDialog * vContext ,
const char * vKey , ImGuiWindowFlags vFlags , ImVec2 vMinSize , ImVec2 vMaxSize )
{
if ( vContext )
{
return vContext - > Display ( vKey , vFlags , vMinSize , vMaxSize ) ;
}
return false ;
}
IMGUIFILEDIALOG_API void IGFD_CloseDialog ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
vContext - > Close ( ) ;
}
}
IMGUIFILEDIALOG_API bool IGFD_IsOk ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
return vContext - > IsOk ( ) ;
}
return false ;
}
IMGUIFILEDIALOG_API bool IGFD_WasKeyOpenedThisFrame ( ImGuiFileDialog * vContext ,
const char * vKey )
{
if ( vContext )
{
vContext - > WasOpenedThisFrame ( vKey ) ;
}
return false ;
}
IMGUIFILEDIALOG_API bool IGFD_WasOpenedThisFrame ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
vContext - > WasOpenedThisFrame ( ) ;
}
return false ;
}
IMGUIFILEDIALOG_API bool IGFD_IsKeyOpened ( ImGuiFileDialog * vContext ,
const char * vCurrentOpenedKey )
{
if ( vContext )
{
vContext - > IsOpened ( vCurrentOpenedKey ) ;
}
return false ;
}
IMGUIFILEDIALOG_API bool IGFD_IsOpened ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
vContext - > IsOpened ( ) ;
}
return false ;
}
IMGUIFILEDIALOG_API IGFD_Selection IGFD_GetSelection ( ImGuiFileDialog * vContext )
{
IGFD_Selection res = IGFD_Selection_Get ( ) ;
if ( vContext )
{
auto sel = vContext - > GetSelection ( ) ;
if ( ! sel . empty ( ) )
{
res . count = sel . size ( ) ;
res . table = new IGFD_Selection_Pair [ res . count ] ;
size_t idx = 0U ;
for ( const auto & s : sel )
{
IGFD_Selection_Pair * pair = res . table + idx + + ;
// fileNameExt
if ( ! s . first . empty ( ) )
{
size_t siz = s . first . size ( ) + 1U ;
pair - > fileName = new char [ siz ] ;
# ifndef MSVC
strncpy ( pair - > fileName , s . first . c_str ( ) , siz ) ;
# else
strncpy_s ( pair - > fileName , siz , s . first . c_str ( ) , siz ) ;
# endif
pair - > fileName [ siz - 1U ] = ' \0 ' ;
}
// filePathName
if ( ! s . second . empty ( ) )
{
size_t siz = s . first . size ( ) + 1U ;
pair - > filePathName = new char [ siz ] ;
# ifndef MSVC
strncpy ( pair - > filePathName , s . first . c_str ( ) , siz ) ;
# else
strncpy_s ( pair - > filePathName , siz , s . first . c_str ( ) , siz ) ;
# endif
pair - > filePathName [ siz - 1U ] = ' \0 ' ;
}
}
return res ;
}
}
return res ;
}
IMGUIFILEDIALOG_API char * IGFD_GetFilePathName ( ImGuiFileDialog * vContext )
{
char * res = nullptr ;
if ( vContext )
{
auto s = vContext - > GetFilePathName ( ) ;
if ( ! s . empty ( ) )
{
size_t siz = s . size ( ) + 1U ;
res = new char [ siz ] ;
# ifndef MSVC
strncpy ( res , s . c_str ( ) , siz ) ;
# else
strncpy_s ( res , siz , s . c_str ( ) , siz ) ;
# endif
res [ siz - 1U ] = ' \0 ' ;
}
}
return res ;
}
IMGUIFILEDIALOG_API char * IGFD_GetCurrentFileName ( ImGuiFileDialog * vContext )
{
char * res = nullptr ;
if ( vContext )
{
auto s = vContext - > GetCurrentFileName ( ) ;
if ( ! s . empty ( ) )
{
size_t siz = s . size ( ) + 1U ;
res = new char [ siz ] ;
# ifndef MSVC
strncpy ( res , s . c_str ( ) , siz ) ;
# else
strncpy_s ( res , siz , s . c_str ( ) , siz ) ;
# endif
res [ siz - 1U ] = ' \0 ' ;
}
}
return res ;
}
IMGUIFILEDIALOG_API char * IGFD_GetCurrentPath ( ImGuiFileDialog * vContext )
{
char * res = nullptr ;
if ( vContext )
{
auto s = vContext - > GetCurrentPath ( ) ;
if ( ! s . empty ( ) )
{
size_t siz = s . size ( ) + 1U ;
res = new char [ siz ] ;
# ifndef MSVC
strncpy ( res , s . c_str ( ) , siz ) ;
# else
strncpy_s ( res , siz , s . c_str ( ) , siz ) ;
# endif
res [ siz - 1U ] = ' \0 ' ;
}
}
return res ;
}
IMGUIFILEDIALOG_API char * IGFD_GetCurrentFilter ( ImGuiFileDialog * vContext )
{
char * res = nullptr ;
if ( vContext )
{
auto s = vContext - > GetCurrentFilter ( ) ;
if ( ! s . empty ( ) )
{
size_t siz = s . size ( ) + 1U ;
res = new char [ siz ] ;
# ifndef MSVC
strncpy ( res , s . c_str ( ) , siz ) ;
# else
strncpy_s ( res , siz , s . c_str ( ) , siz ) ;
# endif
res [ siz - 1U ] = ' \0 ' ;
}
}
return res ;
}
IMGUIFILEDIALOG_API void * IGFD_GetUserDatas ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
return vContext - > GetUserDatas ( ) ;
}
return nullptr ;
}
IMGUIFILEDIALOG_API void IGFD_SetFileStyle ( ImGuiFileDialog * vContext ,
IGFD_FileStyleFlags vFlags , const char * vCriteria , ImVec4 vColor , const char * vIcon , ImFont * vFont ) //-V813
{
if ( vContext )
{
vContext - > SetFileStyle ( vFlags , vCriteria , vColor , vIcon , vFont ) ;
}
}
IMGUIFILEDIALOG_API void IGFD_SetFileStyle2 ( ImGuiFileDialog * vContext ,
IGFD_FileStyleFlags vFlags , const char * vCriteria , float vR , float vG , float vB , float vA , const char * vIcon , ImFont * vFont )
{
if ( vContext )
{
vContext - > SetFileStyle ( vFlags , vCriteria , ImVec4 ( vR , vG , vB , vA ) , vIcon , vFont ) ;
}
}
IMGUIFILEDIALOG_API bool IGFD_GetFileStyle ( ImGuiFileDialog * vContext ,
IGFD_FileStyleFlags vFlags , const char * vCriteria , ImVec4 * vOutColor , char * * vOutIcon , ImFont * * vOutFont )
{
if ( vContext )
{
std : : string icon ;
bool res = vContext - > GetFileStyle ( vFlags , vCriteria , vOutColor , & icon , vOutFont ) ;
if ( ! icon . empty ( ) & & vOutIcon )
{
size_t siz = icon . size ( ) + 1U ;
* vOutIcon = new char [ siz ] ;
# ifndef MSVC
strncpy ( * vOutIcon , icon . c_str ( ) , siz ) ;
# else
strncpy_s ( * vOutIcon , siz , icon . c_str ( ) , siz ) ;
# endif
( * vOutIcon ) [ siz - 1U ] = ' \0 ' ;
}
return res ;
}
return false ;
}
IMGUIFILEDIALOG_API void IGFD_ClearFilesStyle ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
vContext - > ClearFilesStyle ( ) ;
}
}
IMGUIFILEDIALOG_API void SetLocales ( ImGuiFileDialog * vContext , const int vCategory , const char * vBeginLocale , const char * vEndLocale )
{
if ( vContext )
{
vContext - > SetLocales ( vCategory , ( vBeginLocale ? vBeginLocale : " " ) , ( vEndLocale ? vEndLocale : " " ) ) ;
}
}
# ifdef USE_EXPLORATION_BY_KEYS
IMGUIFILEDIALOG_API void IGFD_SetFlashingAttenuationInSeconds ( ImGuiFileDialog * vContext , float vAttenValue )
{
if ( vContext )
{
vContext - > SetFlashingAttenuationInSeconds ( vAttenValue ) ;
}
}
# endif
# ifdef USE_BOOKMARK
IMGUIFILEDIALOG_API char * IGFD_SerializeBookmarks ( ImGuiFileDialog * vContext )
{
char * res = nullptr ;
if ( vContext )
{
auto s = vContext - > SerializeBookmarks ( ) ;
if ( ! s . empty ( ) )
{
size_t siz = s . size ( ) + 1U ;
res = new char [ siz ] ;
# ifndef MSVC
strncpy ( res , s . c_str ( ) , siz ) ;
# else
strncpy_s ( res , siz , s . c_str ( ) , siz ) ;
# endif
res [ siz - 1U ] = ' \0 ' ;
}
}
return res ;
}
IMGUIFILEDIALOG_API void IGFD_DeserializeBookmarks ( ImGuiFileDialog * vContext , const char * vBookmarks )
{
if ( vContext )
{
vContext - > DeserializeBookmarks ( vBookmarks ) ;
}
}
# endif
# ifdef USE_THUMBNAILS
IMGUIFILEDIALOG_API void SetCreateThumbnailCallback ( ImGuiFileDialog * vContext , const IGFD_CreateThumbnailFun vCreateThumbnailFun )
{
if ( vContext )
{
vContext - > SetCreateThumbnailCallback ( vCreateThumbnailFun ) ;
}
}
IMGUIFILEDIALOG_API void SetDestroyThumbnailCallback ( ImGuiFileDialog * vContext , const IGFD_DestroyThumbnailFun vDestroyThumbnailFun )
{
if ( vContext )
{
vContext - > SetDestroyThumbnailCallback ( vDestroyThumbnailFun ) ;
}
}
IMGUIFILEDIALOG_API void ManageGPUThumbnails ( ImGuiFileDialog * vContext )
{
if ( vContext )
{
vContext - > ManageGPUThumbnails ( ) ;
}
}
# endif // USE_THUMBNAILS