5186 lines
		
	
	
		
			149 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			5186 lines
		
	
	
		
			149 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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
 | |
| #ifdef WIN32
 | |
| 	#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
 | |
| #elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined (__EMSCRIPTEN__) || defined(__HAIKU__)
 | |
| 	#define UNIX
 | |
| 	#define stricmp strcasecmp
 | |
| 	#include <sys/types.h>
 | |
| 	// this option need c++17
 | |
| 	#ifndef USE_STD_FILESYSTEM
 | |
| 		#include <dirent.h>
 | |
| 	#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 <IconsFontAwesome4.h>
 | |
| 
 | |
| #include <cstdlib>
 | |
| #include <algorithm>
 | |
| #include <iostream>
 | |
| 
 | |
| #define DOUBLE_CLICKED ((singleClickSel && ImGui::IsMouseReleased(0)) || (!singleClickSel && ImGui::IsMouseDoubleClicked(0)))
 | |
| 
 | |
| #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 ICON_FA_PLUS
 | |
| #endif // createDirButtonString
 | |
| #ifndef okButtonString
 | |
| #define okButtonString "OK"
 | |
| #endif // okButtonString
 | |
| #ifndef cancelButtonString
 | |
| #define cancelButtonString "Cancel"
 | |
| #endif // cancelButtonString
 | |
| #ifndef resetButtonString
 | |
| #define resetButtonString ICON_FA_REPEAT
 | |
| #endif // resetButtonString
 | |
| #ifndef drivesButtonString
 | |
| #define drivesButtonString ICON_FA_HDD_O
 | |
| #endif // drivesButtonString
 | |
| #ifndef parentDirString
 | |
| #define parentDirString ICON_FA_CHEVRON_UP
 | |
| #endif // parentDirString
 | |
| #ifndef editPathButtonString
 | |
| #define editPathButtonString ICON_FA_PENCIL
 | |
| #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 "Name:"
 | |
| #endif // fileNameString
 | |
| #ifndef dirNameString
 | |
| #define dirNameString "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 buttonParentDirString
 | |
| #define buttonParentDirString "Go to parent directory"
 | |
| #endif
 | |
| #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.path.empty()) {
 | |
|         res.path=separator;
 | |
|       }
 | |
| 
 | |
| 			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;
 | |
| 
 | |
| 			ImGui::PushItemWidth(FILTER_COMBO_WIDTH*FileDialog::Instance()->DpiScale);
 | |
| 			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("");
 | |
| 		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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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
 | |
| 					{
 | |
|             if (a==NULL || b==NULL)
 | |
|               return false;
 | |
| 						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 == "." || 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);
 | |
| 			}
 | |
| 
 | |
|       for (char& i: infos->fileExt) {
 | |
|         if (i>='A' && i<='Z') i+='a'-'A';
 | |
|       }
 | |
| 
 | |
| 			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;
 | |
| 			int n = scandir(path.c_str(), &files, nullptr, inAlphaSort);
 | |
| 			if (n>0)
 | |
| 			{
 | |
| 				int i;
 | |
| 
 | |
| 				for (i = 0; i < n; i++)
 | |
| 				{
 | |
| 					struct dirent* ent = files[i];
 | |
| 					std::string where = path + std::string("/") + std::string(ent->d_name);
 | |
| 					char fileType = 0;
 | |
| #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
 | |
| 					{
 | |
| 						struct stat filestat;
 | |
| 						if (stat(where.c_str(), &filestat) == 0)
 | |
| 						{
 | |
| 							if (S_ISDIR(filestat.st_mode))
 | |
| 							{
 | |
| 								fileType = 'd';
 | |
| 							}
 | |
| 							else
 | |
| 							{
 | |
| 								fileType = 'f';
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					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);
 | |
| 			if (result!=-1)
 | |
| 			{
 | |
| 				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);
 | |
| 				}
 | |
| 			} else {
 | |
|         vInfos->fileSize=0;
 | |
|         vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
 | |
|         vInfos->fileModifDate="???";
 | |
|       }
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	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);
 | |
| 
 | |
|     ImGui::SameLine();
 | |
|     if (IMGUI_BUTTON(parentDirString))
 | |
| 		{
 | |
| 			if (SetPathOnParentDirectoryIfAny()) {
 | |
| 			  OpenCurrentPath(vFileDialogInternal);
 | |
|       }
 | |
| 		}
 | |
| 		if (ImGui::IsItemHovered())
 | |
| 			ImGui::SetTooltip(buttonParentDirString);
 | |
| 
 | |
| #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();
 | |
| 			if (ImGui::IsKeyReleased(ImGuiKey_Enter))
 | |
| 			{
 | |
| 				puFileManager.SetCurrentPath(std::string(puFileManager.puInputPathBuffer));
 | |
| 				puFileManager.OpenCurrentPath(*this);
 | |
| 				puFileManager.puInputPathActivated = false;
 | |
| 			}
 | |
| 			if (ImGui::IsKeyReleased(ImGuiKey_Escape))
 | |
| 			{
 | |
| 				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\nYou 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\nYou 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 ///////////////////////////////////////////
 | |
| 	/////////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| 	IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {DpiScale=1.0f; singleClickSel=false; mobileMode=false;}
 | |
| 	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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		if (prFileDialogInternal.puShowDialog) // if already opened, quit
 | |
| 			return;
 | |
| 
 | |
| 		prFileDialogInternal.ResetForNewDialog();
 | |
| 
 | |
| 		prFileDialogInternal.puDLGkey = vKey;
 | |
| 		prFileDialogInternal.puDLGtitle = vTitle;
 | |
| 		prFileDialogInternal.puDLGuserDatas = vUserDatas;
 | |
| 		prFileDialogInternal.puDLGflags = vFlags;
 | |
|     prFileDialogInternal.puDLGselFun = vSelectFun;
 | |
| 		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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		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;
 | |
|     prFileDialogInternal.puDLGselFun = vSelectFun;
 | |
| 		prFileDialogInternal.puDLGmodal = false;
 | |
| 
 | |
| 		auto ps = IGFD::Utils::ParsePathFileName(vFilePathName);
 | |
| 		if (ps.isOk)
 | |
| 		{
 | |
| 			prFileDialogInternal.puFileManager.puDLGpath = ps.path;
 | |
| 			prFileDialogInternal.puFileManager.SetDefaultFileName("");
 | |
| 			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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		if (prFileDialogInternal.puShowDialog) // if already opened, quit
 | |
| 			return;
 | |
| 
 | |
| 		prFileDialogInternal.ResetForNewDialog();
 | |
| 
 | |
| 		prFileDialogInternal.puDLGkey = vKey;
 | |
| 		prFileDialogInternal.puDLGtitle = vTitle;
 | |
| 		prFileDialogInternal.puDLGuserDatas = vUserDatas;
 | |
| 		prFileDialogInternal.puDLGflags = vFlags;
 | |
|     prFileDialogInternal.puDLGselFun = vSelectFun;
 | |
| 		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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		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;
 | |
|     prFileDialogInternal.puDLGselFun = vSelectFun;
 | |
| 		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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		if (prFileDialogInternal.puShowDialog) // if already opened, quit
 | |
| 			return;
 | |
| 
 | |
| 		OpenDialog(
 | |
| 			vKey, vTitle, vFilters,
 | |
| 			vPath, vFileName,
 | |
| 			vCountSelectionMax, vUserDatas, vFlags, vSelectFun);
 | |
| 
 | |
| 		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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		if (prFileDialogInternal.puShowDialog) // if already opened, quit
 | |
| 			return;
 | |
| 
 | |
| 		OpenDialog(
 | |
| 			vKey, vTitle, vFilters,
 | |
| 			vFilePathName,
 | |
| 			vCountSelectionMax, vUserDatas, vFlags, vSelectFun);
 | |
| 
 | |
| 		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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		if (prFileDialogInternal.puShowDialog) // if already opened, quit
 | |
| 			return;
 | |
| 
 | |
| 		OpenDialog(
 | |
| 			vKey, vTitle, vFilters,
 | |
| 			vPath, vFileName,
 | |
| 			vSidePane, vSidePaneWidth,
 | |
| 			vCountSelectionMax, vUserDatas, vFlags, vSelectFun);
 | |
| 
 | |
| 		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,
 | |
| 		ImGuiFileDialogFlags vFlags,
 | |
|     SelectFun vSelectFun)
 | |
| 	{
 | |
| 		if (prFileDialogInternal.puShowDialog) // if already opened, quit
 | |
| 			return;
 | |
| 
 | |
| 		OpenDialog(
 | |
| 			vKey, vTitle, vFilters,
 | |
| 			vFilePathName,
 | |
| 			vSidePane, vSidePaneWidth,
 | |
| 			vCountSelectionMax, vUserDatas, vFlags, vSelectFun);
 | |
| 
 | |
| 		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
 | |
| 			{
 | |
| 				beg = ImGui::Begin(name.c_str(), (bool*)nullptr, flags | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking);
 | |
| 			}
 | |
| 			if (beg)
 | |
| 			{
 | |
|         ImGui::SetWindowPos(ImVec2((ImGui::GetMainViewport()->Size.x-ImGui::GetWindowWidth())*0.5f,(ImGui::GetMainViewport()->Size.y-ImGui::GetWindowHeight())*0.5f));
 | |
|         if (ImGui::GetWindowSize().x<vMinSize.x || ImGui::GetWindowSize().y<vMinSize.y) {
 | |
|           ImGui::SetWindowSize(vMinSize,ImGuiCond_Always);
 | |
|         }
 | |
| #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
 | |
| 				res = prDrawContent(); // bookmark, files view, side pane
 | |
| 				bool res1 = prDrawFooter(); // file field, filter combobox, ok/cancel buttons
 | |
|         if (!res) res=res1;
 | |
| 
 | |
| 				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);
 | |
| 	}
 | |
| 
 | |
| 	bool IGFD::FileDialog::prDrawContent()
 | |
| 	{
 | |
|     bool escape = false;
 | |
| 		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
 | |
| 		escape = prDrawFileListView(size);
 | |
| #endif // USE_THUMBNAILS
 | |
| 
 | |
| 		if (prFileDialogInternal.puDLGoptionsPane)
 | |
| 		{
 | |
| 			prDrawSidePane(size.y);
 | |
| 		}
 | |
| 
 | |
|     return escape;
 | |
| 	}
 | |
| 
 | |
| 	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;
 | |
|     // fix this! fix this! fix this!
 | |
| 		if (!fdFile.puDLGDirectoryMode)
 | |
| 			width -= FILTER_COMBO_WIDTH*DpiScale;
 | |
| 		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;
 | |
| 	}
 | |
| 
 | |
|   // 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, ...)
 | |
| 	{
 | |
| 		if (!vInfos.use_count())
 | |
| 			return 0;
 | |
| 
 | |
| 		auto& fdi = prFileDialogInternal.puFileManager;
 | |
| 
 | |
| 		static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick |
 | |
| 			ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth;
 | |
| 
 | |
|                 // TODO BUG?!
 | |
|                 // YES BUG: THIS JUST CRASHED FOR SOME REASON
 | |
| 		va_list args;
 | |
| 		va_start(args, vFmt);
 | |
| 		vsnprintf(fdi.puVariadicBuffer, MAX_FILE_DIALOG_NAME_BUFFER, vFmt, args);
 | |
| 		va_end(args);
 | |
| 
 | |
| 		float h = /*mobileMode?(ImGui::GetFontSize()+10.0f*DpiScale):*/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')
 | |
| 			{
 | |
|         bool isSelectingDir=false;
 | |
| 				// 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);
 | |
|             isSelectingDir=true;
 | |
| 					}
 | |
| 				}
 | |
| 				else // no nav system => classic behavior
 | |
| 				{
 | |
| 					if (DOUBLE_CLICKED) // 0 -> left mouse button double click
 | |
| 					{
 | |
|             isSelectingDir=true;
 | |
| 						fdi.puPathClicked = fdi.SelectDirectory(vInfos);
 | |
| 					}
 | |
| 					else if (fdi.puDLGDirectoryMode) // directory chooser
 | |
| 					{
 | |
| 						fdi.SelectFileName(prFileDialogInternal, vInfos);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				return isSelectingDir; // needToBreakTheloop
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
|         if (DOUBLE_CLICKED) {
 | |
|           fdi.SelectFileName(prFileDialogInternal, vInfos);
 | |
|           prFileDialogInternal.puIsOk = true;
 | |
|           return 2;
 | |
|         } else {
 | |
| 				  fdi.SelectFileName(prFileDialogInternal, vInfos);
 | |
|           if (prFileDialogInternal.puDLGselFun!=NULL) {
 | |
|             std::string argPath;
 | |
|             for (auto& i: GetSelection()) {
 | |
|               argPath=i.second;
 | |
|             }
 | |
|             if (!argPath.empty()) {
 | |
|               prFileDialogInternal.puDLGselFun(argPath.c_str());
 | |
|             }
 | |
|           }
 | |
|         }
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	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();
 | |
| 	}
 | |
| 
 | |
| 	bool IGFD::FileDialog::prDrawFileListView(ImVec2 vSize)
 | |
| 	{
 | |
|     bool escape = false;
 | |
| 		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();
 | |
| 
 | |
| 						int needToBreakTheloop = false;
 | |
| 
 | |
| 						if (ImGui::TableNextColumn()) // file name
 | |
| 						{
 | |
|              // TODO BUG?!?!?!
 | |
|              // YES BUG
 | |
| 							needToBreakTheloop = prSelectableItem(i, infos, selected, "%s", _str.c_str());
 | |
|               if (needToBreakTheloop==2) escape=true;
 | |
| 						}
 | |
| 						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);
 | |
| 
 | |
| 						if (needToBreakTheloop==1)
 | |
| 							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();
 | |
|     return escape;
 | |
| 	}
 | |
| 
 | |
| #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
 | 
