diff --git a/CMakeLists.txt b/CMakeLists.txt index b55f514f..a5e91fb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,11 @@ if (APPLE) else() set(WITH_RENDER_OPENGL_DEFAULT ON) endif() +if (WIN32) + set(WITH_RENDER_DX11_DEFAULT ON) +else() + set(WITH_RENDER_DX11_DEFAULT OFF) +endif() if (ANDROID) set(USE_GLES_DEFAULT ON) @@ -75,6 +80,7 @@ option(USE_BACKWARD "Use backward-cpp to print a backtrace on crash/abort." ${US option(WITH_JACK "Whether to build with JACK support. Auto-detects if JACK is available" ${WITH_JACK_DEFAULT}) option(WITH_RENDER_SDL "Whether to build with the SDL_Renderer render backend." ${WITH_RENDER_SDL_DEFAULT}) option(WITH_RENDER_OPENGL "Whether to build with the OpenGL render backend." ${WITH_RENDER_OPENGL_DEFAULT}) +option(WITH_RENDER_DX11 "Whether to build with the DirectX 11 render backend." ${WITH_RENDER_DX11_DEFAULT}) option(USE_GLES "Use OpenGL ES for the OpenGL render backend." ${USE_GLES_DEFAULT}) option(SYSTEM_FFTW "Use a system-installed version of FFTW instead of the vendored one" OFF) option(SYSTEM_FMT "Use a system-installed version of fmt instead of the vendored one" OFF) @@ -302,7 +308,7 @@ else() endif() if (BUILD_GUI) - if (NOT WITH_RENDER_SDL AND NOT WITH_RENDER_OPENGL) + if (NOT WITH_RENDER_SDL AND NOT WITH_RENDER_OPENGL AND NOT WITH_RENDER_DX11) message(FATAL_ERROR "No render backends selected!") endif() endif() @@ -731,6 +737,22 @@ if (WITH_RENDER_OPENGL) message(STATUS "UI render backend: OpenGL") endif() +if (WITH_RENDER_DX11) + if (WIN32) + if (SUPPORT_XP) + message(FATAL_ERROR "SUPPORT_XP is on. cannot enable DirectX 11 backend.") + else() + list(APPEND GUI_SOURCES src/gui/render/renderDX11.cpp) + list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_dx11.cpp) + list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_DX11) + list(APPEND DEPENDENCIES_LIBRARIES d3d11) + message(STATUS "UI render backend: DirectX 11") + endif() + else() + message(FATAL_ERROR "DirectX 11 render backend only for Windows!") + endif() +endif() + if (NOT WIN32 AND NOT APPLE) CHECK_INCLUDE_FILE(sys/io.h SYS_IO_FOUND) CHECK_INCLUDE_FILE(linux/input.h LINUX_INPUT_FOUND) diff --git a/demos/a2600/atari breakbeat.fur b/demos/a2600/atari breakbeat.fur index dd4183be..7dfbb0e3 100644 Binary files a/demos/a2600/atari breakbeat.fur and b/demos/a2600/atari breakbeat.fur differ diff --git a/demos/msx/OPLL_High_and_Rising.fur b/demos/msx/OPLL_High_and_Rising.fur new file mode 100644 index 00000000..2ecab85b Binary files /dev/null and b/demos/msx/OPLL_High_and_Rising.fur differ diff --git a/demos/snes/changeyourheart.fur b/demos/snes/changeyourheart.fur new file mode 100644 index 00000000..7b671c3a Binary files /dev/null and b/demos/snes/changeyourheart.fur differ diff --git a/doc/5-wave/README.md b/doc/5-wave/README.md index 19a07b10..a42ffd81 100644 --- a/doc/5-wave/README.md +++ b/doc/5-wave/README.md @@ -6,7 +6,11 @@ Furnace's wavetable editor is rather simple, you can draw the waveform using mou Furnace's wavetable editor features multiple ways of creating desired waveform shape: -- Shape tab allows you to select a few predefined basic shapes and indirectly edit it via "Duty", "Exponent" and "XOR Point" sliders TODO: what the last two are doing? What is amplitude/phase for?) +- Shape tab allows you to select a few predefined basic shapes and indirectly edit it via "Duty", "Exponent" and "XOR Point" sliders: + - `Duty` slider affects mainly pulse waves, determining its wisth, like on C64/VRC6 + - `Exponent` powers the waveform in the mathematical sense of the word (^2, ^3 and so on) + - `XOR Point` determines the point where the waveform gets negated. + - TODO: amplitude/phase part - FM is for creating the waveform with frequency modulation synthesis principles: One can set carrier/modulation levels, frquency multiplier, connection between operators and FM waveforms of these operators. - WaveTools allows user to fine-tune the waveform: scale said waveform in both X and Y axes, smoothen, amplify, normalize, convert to signed/unisgned, invert or even randomize the wavetable. diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index 05891a49..2f4fe3cd 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -1,6 +1,6 @@ # samples -In the context of Furnace, a sound sample (usually just referred to as a sample) is a string of numbers that hold sampled PCM audio. +In the context of Furnace, a sound sample (usually just referred to as a sample) is a string of numbers that represent sampled PCM audio. In Furnace, these samples can be generated by importing a .wav (think of it as an higher quality MP3) file. @@ -13,6 +13,7 @@ as of Furnace 0.6, the following sound chips have sample support: - PC Engine/TurboGrafx-16/HuC6280 - Amiga/Paula - SegaPCM +- NEC PC-9801/YM2608 (ADPCM channel only) - Neo Geo/Neo Geo CD/YM2610 (ADPCM channels only) - Seta/Allumer X1-010 - Atari Lynx @@ -21,12 +22,16 @@ as of Furnace 0.6, the following sound chips have sample support: - QSound - ZX Spectrum 48k (1-bit) - RF5C68 -- WonderSwan +- SNES/S-DSP +- WonderSwan (second channel only) - tildearrow Sound Unit - VERA (last channel only) - Y8950 (last channel only) - Konami K007232 -- a few more that I've forgotten to mention +- Irem GA20 +- Ensoniq OTTO/ES5506 +- Yamaha PCMD8/YMZ280B +- MMC5 (last channel only) ## compatible sample mode @@ -45,9 +50,9 @@ due to limitations in some of those sound chips, some restrictions exist: - NES: if on DPCM mode, only a limited selection of frequencies is available, and loop position isn't supported (only entire sample). - SegaPCM: your sample can't be longer than 65535, and the maximum frequency is 31.25KHz. - QSound: your sample can't be longer than 65535, and the loop length shall not be greater than 32767. -- Neo Geo (ADPCM-A): no looping supported. your samples will play at ~18.5KHz. -- Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is ~55KHz. -- YM2608: the maximum frequency is ~55KHz. +- Neo Geo (ADPCM-A): no looping supported. your samples will play at 18.518KHz. +- Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is 55.555KHz. +- YM2608: the maximum frequency is 55.555KHz. - MSM6258/MSM6295: no arbitrary frequency. - ZX Spectrum Beeper: your sample can't be longer than 2048, and it always plays at ~55KHz. - Seta/Allumer X1-010: frequency resolution is terrible in the lower end. your sample can't be longer than 131072. diff --git a/doc/7-systems/opl.md b/doc/7-systems/opl.md index b4a86e6d..80c00299 100644 --- a/doc/7-systems/opl.md +++ b/doc/7-systems/opl.md @@ -3,7 +3,7 @@ a series of FM sound chips which were very popular in DOS land. it was so popular that even Yamaha made a logo for it! essentially a downgraded version of Yamaha's other FM chips, with only 2 operators per channel. -however, it also had a drums mode, and later chips in the series added more waveforms (than just the typical sine) and even a 4-operator mode. +however, it also had a [drums mode](opll.md), and later chips in the series added more waveforms (than just the typical sine) and even a 4-operator mode. the original OPL (Yamaha YM3526) was present as an expansion for the Commodore 64 and MSX computers (erm, a variant of it). it only had 9 two-operator channels and drums mode. @@ -77,4 +77,4 @@ afterwards everyone moved to Windows and software mixed PCM streaming... - only in 4-op mode (OPL3). - `5Bxy`: set KSR of operator. - `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators". - - `y` determines whether KSR is on. \ No newline at end of file + - `y` determines whether KSR is on. diff --git a/doc/7-systems/opll.md b/doc/7-systems/opll.md index 8b16e888..115e4bd7 100644 --- a/doc/7-systems/opll.md +++ b/doc/7-systems/opll.md @@ -12,7 +12,11 @@ OPLL also spawned a few derivative chips, the best known of these is: the YM2413 is equipped with the following features: - 9 channels of 2 operator FM synthesis -- A drum/percussion mode, replacing the last 3 voices with 5 rhythm channels +- A drum/percussion mode, replacing the last 3 voices with 5 rhythm channels, with drum mode tones hard-defined in the chip itself, like FM instruments. Only pitch might be altered. + + - Drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mxier twice for 2x volume, like all drum sounds. FM channel 8 splits to Snare Drum and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. CH9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave. + - Special syntheis mentioned already is: 5 square waves are gathered from 4x, 64x and 128x the pitch of channel 8 and 16x and 64x the pitch of channel 9 and they go through a process where 2 HH bits OR'd together, then 1 HH and 1 TC bit OR'd, then the two TC bits OR'd together, and those 3 results get XOR'd. + - 1 user-definable patch (this patch can be changed throughout the course of the song) - 15 pre-defined patches which can all be used at the same time - Support for ADSR on both the modulator and the carrier @@ -60,4 +64,4 @@ the YM2413 is equipped with the following features: - `58xx`: set DR of operator 2. - `5Bxy`: set KSR of operator. - `x` is the operator (1-2). a value of 0 means "all operators". - - `y` determines whether KSR is on. \ No newline at end of file + - `y` determines whether KSR is on. diff --git a/doc/7-systems/ym2612.md b/doc/7-systems/ym2612.md index 1eeb148e..dda45266 100644 --- a/doc/7-systems/ym2612.md +++ b/doc/7-systems/ym2612.md @@ -1,6 +1,6 @@ # Yamaha YM2612 -one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player. +one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player, that via software mixing, thanks to Z80 sound CPU, can play more than one channel of straight-shot samples at once. As of Furnace 0.6pre5, Furnace offers DualPCM, which allows 2 channels of software-mixed 8-bit PCM samples at 13750 Hz. # effects diff --git a/extern/SAASound/src/SAADevice.cpp b/extern/SAASound/src/SAADevice.cpp index 9064dcab..78b6e4a4 100644 --- a/extern/SAASound/src/SAADevice.cpp +++ b/extern/SAASound/src/SAADevice.cpp @@ -316,27 +316,27 @@ void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& ri m_Noise0.Tick(); m_Noise1.Tick(); m_Amp0.TickAndOutputStereo(temp_left, temp_right); - oscBuf[0]->data[oscBuf[0]->needle++]=(temp_left+temp_right)<<4; + oscBuf[0]->data[oscBuf[0]->needle++]=(temp_left+temp_right)<<3; accum_left += temp_left; accum_right += temp_right; m_Amp1.TickAndOutputStereo(temp_left, temp_right); - oscBuf[1]->data[oscBuf[1]->needle++]=(temp_left+temp_right)<<4; + oscBuf[1]->data[oscBuf[1]->needle++]=(temp_left+temp_right)<<3; accum_left += temp_left; accum_right += temp_right; m_Amp2.TickAndOutputStereo(temp_left, temp_right); - oscBuf[2]->data[oscBuf[2]->needle++]=(temp_left+temp_right)<<4; + oscBuf[2]->data[oscBuf[2]->needle++]=(temp_left+temp_right)<<3; accum_left += temp_left; accum_right += temp_right; m_Amp3.TickAndOutputStereo(temp_left, temp_right); - oscBuf[3]->data[oscBuf[3]->needle++]=(temp_left+temp_right)<<4; + oscBuf[3]->data[oscBuf[3]->needle++]=(temp_left+temp_right)<<3; accum_left += temp_left; accum_right += temp_right; m_Amp4.TickAndOutputStereo(temp_left, temp_right); - oscBuf[4]->data[oscBuf[4]->needle++]=(temp_left+temp_right)<<4; + oscBuf[4]->data[oscBuf[4]->needle++]=(temp_left+temp_right)<<3; accum_left += temp_left; accum_right += temp_right; m_Amp5.TickAndOutputStereo(temp_left, temp_right); - oscBuf[5]->data[oscBuf[5]->needle++]=(temp_left+temp_right)<<4; + oscBuf[5]->data[oscBuf[5]->needle++]=(temp_left+temp_right)<<3; accum_left += temp_left; accum_right += temp_right; } @@ -394,4 +394,4 @@ void CSAADevice::_TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& } left_mixed = accum_left; right_mixed = accum_right; -} \ No newline at end of file +} diff --git a/extern/igfd/ImGuiFileDialog.cpp b/extern/igfd/ImGuiFileDialog.cpp index 4af6ca44..a3104839 100644 --- a/extern/igfd/ImGuiFileDialog.cpp +++ b/extern/igfd/ImGuiFileDialog.cpp @@ -26,7 +26,7 @@ SOFTWARE. */ #ifndef IMGUI_DEFINE_MATH_OPERATORS - #define IMGUI_DEFINE_MATH_OPERATORS + #define IMGUI_DEFINE_MATH_OPERATORS #endif // IMGUI_DEFINE_MATH_OPERATORS #include "ImGuiFileDialog.h" @@ -42,36 +42,24 @@ SOFTWARE. #include #include #include -// this option need c++17 -#ifdef USE_STD_FILESYSTEM - #include -#endif #if defined (__EMSCRIPTEN__) // EMSCRIPTEN - #include + #include #endif // EMSCRIPTEN #ifdef WIN32 - #define stat _stat - #define stricmp _stricmp - #include - // this option need c++17 - #ifdef USE_STD_FILESYSTEM - #include - #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 + #define stat _stat + #define stricmp _stricmp + #include + #include "dirent/dirent.h" // directly open the dirent file attached to this lib + #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 - // this option need c++17 - #ifndef USE_STD_FILESYSTEM - #include - #endif // USE_STD_FILESYSTEM - #define PATH_SEP '/' + #define UNIX + #define stricmp strcasecmp + #include + #include + #define PATH_SEP '/' #endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) #include "imgui.h" @@ -133,6 +121,9 @@ namespace IGFD #ifndef resetButtonString #define resetButtonString ICON_FA_REPEAT #endif // resetButtonString +#ifndef homeButtonString +#define homeButtonString ICON_FA_HOME +#endif // bomeButtonString #ifndef drivesButtonString #define drivesButtonString ICON_FA_HDD_O #endif // drivesButtonString @@ -170,7 +161,7 @@ namespace IGFD #define buttonEditPathString "Edit path\nYou can also right click on path buttons" #endif // buttonEditPathString #ifndef buttonResetPathString -#define buttonResetPathString "Reset to current directory" +#define buttonResetPathString "Go to home directory" #endif // buttonResetPathString #ifndef buttonParentDirString #define buttonParentDirString "Go to parent directory" @@ -238,29 +229,29 @@ namespace IGFD #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; + 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); - } + 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); + pressed = IMGUI_BUTTON(vLabel); - if (vToggled) - { - ImGui::PopStyleColor(4); //-V112 - } + if (vToggled) + { + ImGui::PopStyleColor(4); //-V112 + } - return pressed; - } + return pressed; + } #define IMGUI_RADIO_BUTTON inRadioButton #endif // IMGUI_RADIO_BUTTON #endif // USE_THUMBNAILS @@ -281,945 +272,902 @@ namespace IGFD #define removeBookmarkButtonString "-" #endif // removeBookmarkButtonString #ifndef IMGUI_TOGGLE_BUTTON - inline bool inToggleButton(const char* vLabel, bool* vToggled) - { - bool pressed = false; + 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); - } + 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); + pressed = IMGUI_BUTTON(vLabel); - if (vToggled && *vToggled) - { - ImGui::PopStyleColor(4); //-V112 - } + if (vToggled && *vToggled) + { + ImGui::PopStyleColor(4); //-V112 + } - if (vToggled && pressed) - *vToggled = !*vToggled; + if (vToggled && pressed) + *vToggled = !*vToggled; - return pressed; - } + return pressed; + } #define IMGUI_TOGGLE_BUTTON inToggleButton #endif // IMGUI_TOGGLE_BUTTON #endif // USE_BOOKMARK - ///////////////////////////////////////////////////////////////////////////////////// - //// INLINE FUNCTIONS /////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// 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 + inline int inAlphaSort(const struct dirent** a, const struct dirent** b) + { + return strcoll((*a)->d_name, (*b)->d_name); + } - ///////////////////////////////////////////////////////////////////////////////////// - //// FILE EXTENTIONS INFOS ////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// FILE EXTENTIONS INFOS ////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - IGFD::FileStyle::FileStyle() - : color(0, 0, 0, 0) - { + 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 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) - { + IGFD::FileStyle::FileStyle(const ImVec4& vColor, const std::string& vIcon, ImFont* vFont) + : color(vColor), icon(vIcon), font(vFont) + { - } + } - ///////////////////////////////////////////////////////////////////////////////////// - //// FILE INFOS ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// 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); - } + // 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; - } + 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 IGFD::Utils::WSplitStringToVector(const std::wstring& text, char delimiter, bool pushEmpty) - { - std::vector 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::vector IGFD::Utils::WSplitStringToVector(const std::wstring& text, char delimiter, bool pushEmpty) + { + std::vector 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::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; - } + 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; - } + 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 IGFD::Utils::SplitStringToVector(const std::string& text, char delimiter, bool pushEmpty) - { - std::vector 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 IGFD::Utils::SplitStringToVector(const std::string& text, char delimiter, bool pushEmpty) + { + std::vector 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 IGFD::Utils::GetDrivesList() - { - std::vector res; + std::vector IGFD::Utils::GetDrivesList() + { + std::vector res; #ifdef WIN32 - const DWORD mydrives = 2048; - char lpBuffer[2048]; + const DWORD mydrives = 2048; + char lpBuffer[2048]; #define mini(a,b) (((a) < (b)) ? (a) : (b)) - const DWORD countChars = mini(GetLogicalDriveStringsA(mydrives, lpBuffer), 2047); + 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); - } + 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; - } + return res; + } - bool IGFD::Utils::IsDirectoryExist(const std::string& name) - { - bool bExists = false; + bool IGFD::Utils::IsDirectoryExist(const std::string& name) + { + bool bExists = false; - if (!name.empty()) - { -#ifdef USE_STD_FILESYSTEM - namespace fs = std::filesystem; + if (!name.empty()) + { + DIR* pDir = nullptr; + pDir = opendir(name.c_str()); + if (pDir != nullptr) + { + bExists = true; + (void)closedir(pDir); + } + } + + 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 - 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 + std::wstring wname = IGFD::Utils::string_to_wstring(name); + if (CreateDirectoryW(wname.c_str(), nullptr)) + { + res = true; + } #elif defined(__EMSCRIPTEN__) - std::string str = std::string("FS.mkdir('") + name + "');"; - emscripten_run_script(str.c_str()); - res = true; + 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; - } + 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; - } - } - } + if (!res) { + std::cout << "Error creating directory " << name << std::endl; + } + } + } - return res; - } + 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; + IGFD::Utils::PathStruct IGFD::Utils::ParsePathFileName(const std::string& vPathFileName) + { + PathStruct res; - auto fsPath = fs::path(vPathFileName); + if (!vPathFileName.empty()) + { + std::string pfn = vPathFileName; + std::string separator(1u, PATH_SEP); + IGFD::Utils::ReplaceString(pfn, "\\", separator); + IGFD::Utils::ReplaceString(pfn, "/", separator); - if (fs::is_regular_file(fsPath)) { - res.name = fsPath.string(); - res.path = fsPath.parent_path().string(); - res.isOk = true; - } + 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; + } - 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, ""); - } + 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; - } - } + 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); + return res; + } + 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(); + 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); + strncpy_s(vBuffer, vBufferLen, str.c_str(), len); #else // MSVC - strncpy(vBuffer, str.c_str(), len); + strncpy(vBuffer, str.c_str(), len); #endif // MSVC - vBuffer[len] = '\0'; - } + vBuffer[len] = '\0'; + } - void IGFD::Utils::ResetBuffer(char* vBuffer) - { - vBuffer[0] = '\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); - } + void IGFD::Utils::SetBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr) + { + ResetBuffer(vBuffer); + AppendToBuffer(vBuffer, vBufferLen, vStr); + } - ///////////////////////////////////////////////////////////////////////////////////// - //// FILE INFOS ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// FILE INFOS ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - bool IGFD::FileInfos::IsTagFound(const std::string& vTag) const - { - if (!vTag.empty()) - { - if (fileNameExt_optimized == "..") return true; + 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 - } + 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; - } + // if tag is empty => its a special case but all is found + return true; + } - ///////////////////////////////////////////////////////////////////////////////////// - //// SEARCH MANAGER ///////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// SEARCH MANAGER ///////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - void IGFD::SearchManager::Clear() - { - puSearchTag.clear(); - IGFD::Utils::ResetBuffer(puSearchBuffer); - } + 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); - } - } + 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::PushItemWidth(ImGui::GetContentRegionAvail().x); + bool edited = ImGui::InputTextWithHint("##InputImGuiFileDialogSearchField", searchString, 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 /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// FILTER INFOS /////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - void IGFD::FilterManager::FilterInfos::clear() - { - filter.clear(); - collectionfilters.clear(); - } + void IGFD::FilterManager::FilterInfos::clear() + { + filter.clear(); + collectionfilters.clear(); + } - bool IGFD::FilterManager::FilterInfos::empty() const - { - return filter.empty() && collectionfilters.empty(); - } + 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()); - } + bool IGFD::FilterManager::FilterInfos::exist(const std::string& vFilter) const + { + return filter == vFilter || (collectionfilters.find(vFilter) != collectionfilters.end()); + } - ///////////////////////////////////////////////////////////////////////////////////// - //// FILTER MANAGER ///////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// FILTER MANAGER ///////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - void IGFD::FilterManager::ParseFilters(const char* vFilters) - { - prParsedFilters.clear(); + void IGFD::FilterManager::ParseFilters(const char* vFilters) + { + prParsedFilters.clear(); - if (vFilters) - puDLGFilters = vFilters; // file mode - else - puDLGFilters.clear(); // directory mode + 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" + if (!puDLGFilters.empty()) + { + // ".*,.cpp,.h,.hpp" + // "Source files{.cpp,.h,.hpp},Image files{.png,.gif,.jpg,.jpeg},.md" - bool currentFilterFound = false; + 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; + 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 (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; - } + if (!currentFilterFound && prSelectedFilter.filter == infos.filter) + { + currentFilterFound = true; + prSelectedFilter = infos; + } - lp = p; - if (!infos.empty()) - prParsedFilters.emplace_back(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); - } + 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(); - } - } + if (!currentFilterFound) + if (!prParsedFilters.empty()) + prSelectedFilter = *prParsedFilters.begin(); + } + } - void IGFD::FilterManager::SetSelectedFilterWithExt(const std::string& vFilter) - { - if (!prParsedFilters.empty()) - { - if (!vFilter.empty()) - { - // std::map - 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; - } - } - } - } - } + void IGFD::FilterManager::SetSelectedFilterWithExt(const std::string& vFilter) + { + if (!prParsedFilters.empty()) + { + if (!vFilter.empty()) + { + // std::map + 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(); - } - } + 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(vInfos); - prFilesStyle[vFlags][_criteria]->flags = vFlags; - } + 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(vInfos); + prFilesStyle[vFlags][_criteria]->flags = vFlags; + } - // will be called internally - // will not been exposed to IGFD API - bool IGFD::FilterManager::prFillFileStyle(std::shared_ptr 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; - } - } + // will be called internally + // will not been exposed to IGFD API + bool IGFD::FilterManager::prFillFileStyle(std::shared_ptr 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; - } + 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; - } + // 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 (_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 (_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; - } - } - } + if (vFileInfos->fileStyle.use_count()) + return true; + } + } + } - return false; - } + 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(vColor, vIcon, vFont); - prFilesStyle[vFlags][_criteria]->flags = vFlags; - } + 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(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; - } + // 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; - } - } + 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; - } + return false; + } - bool IGFD::FilterManager::DrawFilterComboBox(FileDialogInternal& vFileDialogInternal) - { - // combobox of filters - if (!puDLGFilters.empty()) - { - ImGui::SameLine(); + bool IGFD::FilterManager::DrawFilterComboBox(FileDialogInternal& vFileDialogInternal) + { + // combobox of filters + if (!puDLGFilters.empty()) + { + ImGui::SameLine(); - bool needToApllyNewFilter = false; + 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::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(); + ImGui::EndCombo(); + } + ImGui::PopItemWidth(); - if (needToApllyNewFilter) - { - vFileDialogInternal.puFileManager.OpenCurrentPath(vFileDialogInternal); - } + if (needToApllyNewFilter) + { + vFileDialogInternal.puFileManager.OpenCurrentPath(vFileDialogInternal); + } - return needToApllyNewFilter; - } + return needToApllyNewFilter; + } - return false; - } + return false; + } - IGFD::FilterManager::FilterInfos IGFD::FilterManager::GetSelectedFilter() - { - return prSelectedFilter; - } + IGFD::FilterManager::FilterInfos IGFD::FilterManager::GetSelectedFilter() + { + return prSelectedFilter; + } - std::string IGFD::FilterManager::ReplaceExtentionWithCurrentFilter(const std::string& vFile) const - { - auto result = vFile; + 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); - } + 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; - } - } + 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 - } + 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 /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// FILE MANAGER /////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - IGFD::FileManager::FileManager() - { - puFsRoot = std::string(1u, PATH_SEP); + IGFD::FileManager::FileManager() + { + puFsRoot = std::string(1u, PATH_SEP); for (int i=0; i<4; i++) { puSortingDirection[i]=true; } - } + } - void IGFD::FileManager::OpenCurrentPath(const FileDialogInternal& vFileDialogInternal) - { - puShowDrives = false; - ClearComposer(); - ClearFileLists(); - if (puDLGDirectoryMode) // directory mode - SetDefaultFileName("."); - else - SetDefaultFileName(""); + void IGFD::FileManager::OpenCurrentPath(const FileDialogInternal& vFileDialogInternal) + { + puShowDrives = false; + ClearComposer(); + ClearFileLists(); + if (puDLGDirectoryMode) // directory mode + SetDefaultFileName("."); + else + SetDefaultFileName(""); logV("IGFD: OpenCurrentPath()"); - ScanDir(vFileDialogInternal, GetCurrentPath()); - } + ScanDir(vFileDialogInternal, GetCurrentPath()); + } - void IGFD::FileManager::SortFields(const FileDialogInternal& vFileDialogInternal, const SortingFieldEnum& vSortingField, const bool vCanChangeOrder) - { + void IGFD::FileManager::SortFields(const FileDialogInternal& vFileDialogInternal, const SortingFieldEnum& vSortingField, const bool vCanChangeOrder) + { logV("IGFD: SortFields()"); - if (vSortingField != SortingFieldEnum::FIELD_NONE) - { - puHeaderFileName = tableHeaderFileNameString; - puHeaderFileType = tableHeaderFileTypeString; - puHeaderFileSize = tableHeaderFileSizeString; - puHeaderFileDate = tableHeaderFileDateString; + if (vSortingField != SortingFieldEnum::FIELD_NONE) + { + puHeaderFileName = tableHeaderFileNameString; + puHeaderFileType = tableHeaderFileTypeString; + puHeaderFileSize = tableHeaderFileSizeString; + puHeaderFileDate = tableHeaderFileDateString; #ifdef USE_THUMBNAILS - puHeaderFileThumbnails = tableHeaderFileThumbnailsString; + puHeaderFileThumbnails = tableHeaderFileThumbnailsString; #endif // #ifdef USE_THUMBNAILS - } else { + } else { logV("IGFD: sorting by NONE!"); } @@ -1227,2822 +1175,2790 @@ namespace IGFD logV("IGFD: with an empty file list?"); } - if (vSortingField == SortingFieldEnum::FIELD_FILENAME) - { + if (vSortingField == SortingFieldEnum::FIELD_FILENAME) + { logV("IGFD: sorting by name"); - if (vCanChangeOrder && puSortingField == vSortingField) { + if (vCanChangeOrder && puSortingField == vSortingField) { //printf("Change the sorting\n"); - puSortingDirection[0] = !puSortingDirection[0]; + puSortingDirection[0] = !puSortingDirection[0]; } - if (puSortingDirection[0]) - { + if (puSortingDirection[0]) + { #ifdef USE_CUSTOM_SORTING_ICON - puHeaderFileName = tableHeaderDescendingIcon + puHeaderFileName; + puHeaderFileName = tableHeaderDescendingIcon + puHeaderFileName; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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 - { + // 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; + puHeaderFileName = tableHeaderAscendingIcon + puHeaderFileName; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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) - { + // 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) + { logV("IGFD: sorting by type"); - if (vCanChangeOrder && puSortingField == vSortingField) - puSortingDirection[1] = !puSortingDirection[1]; + if (vCanChangeOrder && puSortingField == vSortingField) + puSortingDirection[1] = !puSortingDirection[1]; - if (puSortingDirection[1]) - { + if (puSortingDirection[1]) + { #ifdef USE_CUSTOM_SORTING_ICON - puHeaderFileType = tableHeaderDescendingIcon + puHeaderFileType; + puHeaderFileType = tableHeaderDescendingIcon + puHeaderFileType; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { - if (!a.use_count() || !b.use_count()) - return false; + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& 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 - { + 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; + puHeaderFileType = tableHeaderAscendingIcon + puHeaderFileType; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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 (a->fileType != b->fileType) return (a->fileType != 'd'); // directory in last + return (a->fileExt > b->fileExt); // else + }); + } + } + else if (vSortingField == SortingFieldEnum::FIELD_SIZE) + { logV("IGFD: sorting by size"); - if (vCanChangeOrder && puSortingField == vSortingField) - puSortingDirection[2] = !puSortingDirection[2]; + if (vCanChangeOrder && puSortingField == vSortingField) + puSortingDirection[2] = !puSortingDirection[2]; - if (puSortingDirection[2]) - { + if (puSortingDirection[2]) + { #ifdef USE_CUSTOM_SORTING_ICON - puHeaderFileSize = tableHeaderDescendingIcon + puHeaderFileSize; + puHeaderFileSize = tableHeaderDescendingIcon + puHeaderFileSize; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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 - { + 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; + puHeaderFileSize = tableHeaderAscendingIcon + puHeaderFileSize; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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 (a->fileType != b->fileType) return (a->fileType != 'd'); // directory in last + return (a->fileSize > b->fileSize); // else + }); + } + } + else if (vSortingField == SortingFieldEnum::FIELD_DATE) + { logV("IGFD: sorting by date"); - if (vCanChangeOrder && puSortingField == vSortingField) - puSortingDirection[3] = !puSortingDirection[3]; + if (vCanChangeOrder && puSortingField == vSortingField) + puSortingDirection[3] = !puSortingDirection[3]; - if (puSortingDirection[3]) - { + if (puSortingDirection[3]) + { #ifdef USE_CUSTOM_SORTING_ICON - puHeaderFileDate = tableHeaderDescendingIcon + puHeaderFileDate; + puHeaderFileDate = tableHeaderDescendingIcon + puHeaderFileDate; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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 - { + 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; + puHeaderFileDate = tableHeaderAscendingIcon + puHeaderFileDate; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool + { if (a==NULL || b==NULL) return false; - if (!a.use_count() || !b.use_count()) - 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 - }); - } - } + 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]; + else if (vSortingField == SortingFieldEnum::FIELD_THUMBNAILS) + { + if (vCanChangeOrder && puSortingField == vSortingField) + puSortingDirection[4] = !puSortingDirection[4]; - // we will compare thumbnails by : - // 1) width - // 2) height + // we will compare thumbnails by : + // 1) width + // 2) height - if (puSortingDirection[4]) - { + if (puSortingDirection[4]) + { #ifdef USE_CUSTOM_SORTING_ICON - puHeaderFileThumbnails = tableHeaderDescendingIcon + puHeaderFileThumbnails; + puHeaderFileThumbnails = tableHeaderDescendingIcon + puHeaderFileThumbnails; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { - if (!a.use_count() || !b.use_count()) - return false; + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& 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); - }); - } + 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 - { + else + { #ifdef USE_CUSTOM_SORTING_ICON - puHeaderFileThumbnails = tableHeaderAscendingIcon + puHeaderFileThumbnails; + puHeaderFileThumbnails = tableHeaderAscendingIcon + puHeaderFileThumbnails; #endif // USE_CUSTOM_SORTING_ICON - std::sort(prFileList.begin(), prFileList.end(), - [](const std::shared_ptr& a, const std::shared_ptr& b) -> bool - { - if (!a.use_count() || !b.use_count()) - return false; + std::sort(prFileList.begin(), prFileList.end(), + [](const std::shared_ptr& a, const std::shared_ptr& 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); - }); - } - } + 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; - } + if (vSortingField != SortingFieldEnum::FIELD_NONE) + { + puSortingField = vSortingField; + } logV("IGFD: applying filtering on file list"); - ApplyFilteringOnFileList(vFileDialogInternal); - } + ApplyFilteringOnFileList(vFileDialogInternal); + } - void IGFD::FileManager::ClearFileLists() - { - prFilteredFileList.clear(); - prFileList.clear(); - } + 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; - } + 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(); + void IGFD::FileManager::AddFile(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, const char& vFileType) + { + auto infos = std::make_shared(); - infos->filePath = vPath; - infos->fileNameExt = vFileName; - infos->fileNameExt_optimized = prOptimizeFilenameForSearchOperations(infos->fileNameExt); - infos->fileType = vFileType; + 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->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); - } + 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; - } - } + if (!vFileDialogInternal.puFilterManager.IsCoveredByFilters(infos->fileExt)) + { + return; + } + } - vFileDialogInternal.puFilterManager.prFillFileStyle(infos); + vFileDialogInternal.puFilterManager.prFillFileStyle(infos); - prCompleteFileInfos(infos); - prFileList.push_back(infos); - } + prCompleteFileInfos(infos); + prFileList.push_back(infos); + } - void IGFD::FileManager::ScanDir(const FileDialogInternal& vFileDialogInternal, const std::string& vPath) - { - std::string path = vPath; + void IGFD::FileManager::ScanDir(const FileDialogInternal& vFileDialogInternal, const std::string& vPath) + { + std::string path = vPath; logV("IGFD: ScanDir(%s)",vPath); - if (prCurrentPathDecomposition.empty()) - { + if (prCurrentPathDecomposition.empty()) + { logV("IGFD: the current path decomposition is empty. setting."); - SetCurrentDir(path); - } + SetCurrentDir(path); + } - if (!prCurrentPathDecomposition.empty()) - { + if (!prCurrentPathDecomposition.empty()) + { logV("IGFD: the current path decomposition is not empty. trying."); #ifdef WIN32 - if (path == puFsRoot) - path += std::string(1u, PATH_SEP); + if (path == puFsRoot) + path += std::string(1u, PATH_SEP); #endif // WIN32 - ClearFileLists(); + 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); + struct dirent** files = nullptr; + int n = scandir(path.c_str(), &files, nullptr, inAlphaSort); logV("IGFD: %d entries in directory",n); - if (n>0) - { - int i; + 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; + 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 + 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'; - } - } - } + { + 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; + auto fileNameExt = ent->d_name; - AddFile(vFileDialogInternal, path, fileNameExt, fileType); - } + AddFile(vFileDialogInternal, path, fileNameExt, fileType); + } - for (i = 0; i < n; i++) - { - free(files[i]); - } + for (i = 0; i < n; i++) + { + free(files[i]); + } - free(files); - } else { + free(files); + } else { logV("IGFD: it's empty"); } -#endif // USE_STD_FILESYSTEM logV("IGFD: sorting fields..."); - SortFields(vFileDialogInternal, puSortingField, false); - } else { + SortFields(vFileDialogInternal, puSortingField, false); + } else { logE("IGFD: current path decomposition is empty!"); } fileListActuallyEmpty=prFileList.empty(); - } + } - 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(); - info->fileNameExt = drive; - info->fileNameExt_optimized = prOptimizeFilenameForSearchOperations(drive); - info->fileType = 'd'; + 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(); + 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; - } + 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::IsComposerEmpty() + { + return prCurrentPathDecomposition.empty(); + } + + size_t IGFD::FileManager::GetComposerSize() + { + return prCurrentPathDecomposition.size(); + } - bool IGFD::FileManager::IsFileListEmpty() - { - return prFileList.empty(); - } + bool IGFD::FileManager::IsFileListEmpty() + { + return prFileList.empty(); + } - size_t IGFD::FileManager::GetFullFileListSize() - { - return prFileList.size(); - } + size_t IGFD::FileManager::GetFullFileListSize() + { + return prFileList.size(); + } - std::shared_ptr IGFD::FileManager::GetFullFileAt(size_t vIdx) - { - if (vIdx < prFileList.size()) - return prFileList[vIdx]; - return nullptr; - } + std::shared_ptr IGFD::FileManager::GetFullFileAt(size_t vIdx) + { + if (vIdx < prFileList.size()) + return prFileList[vIdx]; + return nullptr; + } - bool IGFD::FileManager::IsFilteredListEmpty() - { - return prFilteredFileList.empty(); - } + bool IGFD::FileManager::IsFilteredListEmpty() + { + return prFilteredFileList.empty(); + } - size_t IGFD::FileManager::GetFilteredListSize() - { - return prFilteredFileList.size(); - } + size_t IGFD::FileManager::GetFilteredListSize() + { + return prFilteredFileList.size(); + } - std::shared_ptr IGFD::FileManager::GetFilteredFileAt(size_t vIdx) - { - if (vIdx < prFilteredFileList.size()) - return prFilteredFileList[vIdx]; - return nullptr; - } + std::shared_ptr 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(); - } + bool IGFD::FileManager::IsFileNameSelected(const std::string& vFileName) + { + return prSelectedFileNames.find(vFileName) != prSelectedFileNames.end(); + } - std::string IGFD::FileManager::GetBack() - { - return prCurrentPathDecomposition.back(); - } + std::string IGFD::FileManager::GetBack() + { + return prCurrentPathDecomposition.back(); + } - void IGFD::FileManager::ClearComposer() - { - prCurrentPathDecomposition.clear(); - } + void IGFD::FileManager::ClearComposer() + { + prCurrentPathDecomposition.clear(); + } - void IGFD::FileManager::ClearAll() - { - ClearComposer(); - ClearFileLists(); - } + 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); - } - } + 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::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; + 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; + 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 - } + 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 ""; - } + return ""; + } - void IGFD::FileManager::prCompleteFileInfos(const std::shared_ptr& vInfos) - { - if (!vInfos.use_count()) - return; + void IGFD::FileManager::prCompleteFileInfos(const std::shared_ptr& 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 */ + 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; + std::string fpn; - if (vInfos->fileType == 'f' || vInfos->fileType == 'l' || vInfos->fileType == 'd') // file - fpn = vInfos->filePath + std::string(1u, PATH_SEP) + vInfos->fileNameExt; + 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); - } + 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; + 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); + 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); + 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 { + 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); + 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()); + } + } + + 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 (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; - } + if (vSetLastSelectionFileName) + prLastSelectedFileName = vFileName; + } - void IGFD::FileManager::SetCurrentDir(const std::string& vPath) - { - std::string path = vPath; + void IGFD::FileManager::SetCurrentDir(const std::string& vPath) + { + std::string path = vPath; #ifdef WIN32 - if (puFsRoot == path) - path += std::string(1u, PATH_SEP); + 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()); - } + + DIR* dir = opendir(path.c_str()); + if (dir == nullptr) + { + path = "."; + dir = opendir(path.c_str()); + } - if (dir != nullptr) -#endif // USE_STD_FILESYSTEM - { + if (dir != nullptr) + { #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()) + 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) + 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); + { + 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)); + prCurrentPathDecomposition.insert(prCurrentPathDecomposition.begin(), std::string(1u, PATH_SEP)); #endif // UNIX - if (!prCurrentPathDecomposition.empty()) - { + if (!prCurrentPathDecomposition.empty()) + { #ifdef WIN32 - puFsRoot = prCurrentPathDecomposition[0]; + puFsRoot = prCurrentPathDecomposition[0]; #endif // WIN32 - } - } -#ifndef USE_STD_FILESYSTEM - closedir(dir); -#endif - } - } + } + } + closedir(dir); + } + } - bool IGFD::FileManager::CreateDir(const std::string& vPath) - { - bool res = false; + bool IGFD::FileManager::CreateDir(const std::string& vPath) + { + bool res = false; - if (!vPath.empty()) - { - std::string path = prCurrentPath + std::string(1u, PATH_SEP) + vPath; + if (!vPath.empty()) + { + std::string path = prCurrentPath + std::string(1u, PATH_SEP) + vPath; - res = IGFD::Utils::CreateDirectoryIfNotExist(path); - } + res = IGFD::Utils::CreateDirectoryIfNotExist(path); + } - return res; - } + return res; + } - void IGFD::FileManager::ComposeNewPath(std::vector::iterator vIter) - { - std::string res; + void IGFD::FileManager::ComposeNewPath(std::vector::iterator vIter) + { + std::string res; - while (true) - { - if (!res.empty()) - { + while (true) + { + if (!res.empty()) + { #ifdef WIN32 - res = *vIter + std::string(1u, PATH_SEP) + res; + 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; + if (*vIter == puFsRoot) + res = *vIter + res; + else + res = *vIter + PATH_SEP + res; #endif // WIN32 - } - else - res = *vIter; + } + else + res = *vIter; - if (vIter == prCurrentPathDecomposition.begin()) - { + if (vIter == prCurrentPathDecomposition.begin()) + { #if defined(UNIX) // UNIX is LINUX or APPLE - if (res[0] != PATH_SEP) - res = PATH_SEP + res; + if (res[0] != PATH_SEP) + res = PATH_SEP + res; #endif // defined(UNIX) - break; - } + break; + } - --vIter; - } + --vIter; + } - prCurrentPath = std::move(res); - } + prCurrentPath = std::move(res); + } - bool IGFD::FileManager::SetPathOnParentDirectoryIfAny() - { - if (prCurrentPathDecomposition.size() > 1) - { - ComposeNewPath(prCurrentPathDecomposition.end() - 2); - return true; - } - return false; - } + 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; - } + 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; - } + 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; - } + 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); - } + 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& vInfos) - { - if (!vInfos.use_count()) - return false; + bool IGFD::FileManager::SelectDirectory(const std::shared_ptr& vInfos) + { + if (!vInfos.use_count()) + return false; - bool pathClick = false; + bool pathClick = false; - if (vInfos->fileNameExt == "..") - { - pathClick = SetPathOnParentDirectoryIfAny(); - } - else - { - std::string newPath; + if (vInfos->fileNameExt == "..") + { + pathClick = SetPathOnParentDirectoryIfAny(); + } + else + { + std::string newPath; - if (puShowDrives) - { - newPath = vInfos->fileNameExt + std::string(1u, PATH_SEP); - } - else - { + if (puShowDrives) + { + newPath = vInfos->fileNameExt + std::string(1u, PATH_SEP); + } + else + { #ifdef __linux__ - if (puFsRoot == prCurrentPath) - newPath = prCurrentPath + vInfos->fileNameExt; - else + if (puFsRoot == prCurrentPath) + newPath = prCurrentPath + vInfos->fileNameExt; + else #endif // __linux__ - newPath = prCurrentPath + std::string(1u, PATH_SEP) + vInfos->fileNameExt; - } + 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; - } - } + if (IGFD::Utils::IsDirectoryExist(newPath)) + { + if (puShowDrives) + { + prCurrentPath = vInfos->fileNameExt; + puFsRoot = prCurrentPath; + } + else + { + prCurrentPath = newPath; //-V820 + } + pathClick = true; + } + } - return pathClick; - } + return pathClick; + } - void IGFD::FileManager::SelectFileName(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr& vInfos) - { - if (!vInfos.use_count()) - return; + void IGFD::FileManager::SelectFileName(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr& 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; + 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; - } - } - } + 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); - } - } + 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; + 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 (IMGUI_BUTTON(createDirButtonString)) + { + if (!prCreateDirectoryMode) + { + prCreateDirectoryMode = true; + IGFD::Utils::ResetBuffer(puDirectoryNameBuffer); + } + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(buttonCreateDirString); - if (prCreateDirectoryMode) - { - ImGui::SameLine(); + if (prCreateDirectoryMode) + { + ImGui::SameLine(); - ImGui::PushItemWidth(100.0f); - ImGui::InputText("##DirectoryFileName", puDirectoryNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER); - ImGui::PopItemWidth(); + ImGui::PushItemWidth(100.0f); + ImGui::InputText("##DirectoryFileName", puDirectoryNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER); + ImGui::PopItemWidth(); - ImGui::SameLine(); + 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); - } + 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; - } + prCreateDirectoryMode = false; + } - ImGui::SameLine(); + ImGui::SameLine(); - if (IMGUI_BUTTON(cancelButtonString)) - { - prCreateDirectoryMode = false; - } - } - } + 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); + void IGFD::FileManager::DrawPathComposer(const FileDialogInternal& vFileDialogInternal) + { + if (IMGUI_BUTTON(homeButtonString)) + { + SetCurrentPath(FileDialog::Instance()->homePath); + OpenCurrentPath(vFileDialogInternal); + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(buttonResetPathString); ImGui::SameLine(); if (IMGUI_BUTTON(parentDirString)) - { - if (SetPathOnParentDirectoryIfAny()) { - OpenCurrentPath(vFileDialogInternal); + { + if (SetPathOnParentDirectoryIfAny()) { + OpenCurrentPath(vFileDialogInternal); } - } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip(buttonParentDirString); + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(buttonParentDirString); #ifdef WIN32 - ImGui::SameLine(); + ImGui::SameLine(); - if (IMGUI_BUTTON(drivesButtonString)) - { - puDrivesClicked = true; - } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip(buttonDriveString); + 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(); + + if (IMGUI_BUTTON(editPathButtonString)) + { + puInputPathActivated = true; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(buttonEditPathString); - ImGui::SameLine(); + ImGui::SameLine(); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); - // show current path - if (!prCurrentPathDecomposition.empty()) - { - ImGui::SameLine(); + // 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; - } - } - } - } - } + 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; + 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; - } + if (puDLGDirectoryMode) // if directory mode + { + std::string selectedDirectory = puFileNameBuffer; + if (!selectedDirectory.empty() && + selectedDirectory != ".") + path += std::string(1u, PATH_SEP) + selectedDirectory; + } - return path; - } + return path; + } - std::string IGFD::FileManager::GetResultingFileName(FileDialogInternal& vFileDialogInternal) - { - if (!puDLGDirectoryMode) // if not directory mode - { - return puFileNameBuffer; //vFileDialogInternal.puFilterManager.ReplaceExtentionWithCurrentFilter(std::string(puFileNameBuffer)); - } + std::string IGFD::FileManager::GetResultingFileName(FileDialogInternal& vFileDialogInternal) + { + if (!puDLGDirectoryMode) // if not directory mode + { + return puFileNameBuffer; //vFileDialogInternal.puFilterManager.ReplaceExtentionWithCurrentFilter(std::string(puFileNameBuffer)); + } - return ""; // directory mode - } + return ""; // directory mode + } - std::string IGFD::FileManager::GetResultingFilePathName(FileDialogInternal& vFileDialogInternal) - { - std::string result = GetResultingPath(); + std::string IGFD::FileManager::GetResultingFilePathName(FileDialogInternal& vFileDialogInternal) + { + std::string result = GetResultingPath(); - std::string filename = GetResultingFileName(vFileDialogInternal); - if (!filename.empty()) - { + std::string filename = GetResultingFileName(vFileDialogInternal); + if (!filename.empty()) + { #ifdef UNIX - if (puFsRoot != result) + if (puFsRoot != result) #endif // UNIX - result += std::string(1u, PATH_SEP); + result += std::string(1u, PATH_SEP); - result += filename; - } + result += filename; + } - return result; - } + return result; + } - std::map IGFD::FileManager::GetResultingSelection() - { - std::map res; + std::map IGFD::FileManager::GetResultingSelection() + { + std::map res; - for (auto& selectedFileName : prSelectedFileNames) - { - std::string result = GetResultingPath(); + for (auto& selectedFileName : prSelectedFileNames) + { + std::string result = GetResultingPath(); #ifdef UNIX - if (puFsRoot != result) + if (puFsRoot != result) #endif // UNIX - result += std::string(1u, PATH_SEP); + result += std::string(1u, PATH_SEP); - result += selectedFileName; + result += selectedFileName; - res[selectedFileName] = result; - } + res[selectedFileName] = result; + } - return res; - } + return res; + } - ///////////////////////////////////////////////////////////////////////////////////// - //// FILE DIALOG INTERNAL /////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// 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; + 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 + 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; - } - } + { + puSearchManager.puSearchInputIsActive = false; + puFileInputIsActive = false; + puFileListViewIsActive = false; + } + } - void IGFD::FileDialogInternal::EndFrame() - { - // directory change - if (puFileManager.puPathClicked) - { - puFileManager.OpenCurrentPath(*this); - } + void IGFD::FileDialogInternal::EndFrame() + { + // directory change + if (puFileManager.puPathClicked) + { + puFileManager.OpenCurrentPath(*this); + } - if (puFileManager.puDrivesClicked) - { - if (puFileManager.GetDrives()) - { - puFileManager.ApplyFilteringOnFileList(*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; - } - } - } + 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() - { - puFileManager.fileListActuallyEmpty=false; - } + void IGFD::FileDialogInternal::ResetForNewDialog() + { + puFileManager.fileListActuallyEmpty=false; + } - ///////////////////////////////////////////////////////////////////////////////////// - //// THUMBNAIL FEATURE ////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// THUMBNAIL FEATURE ////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - IGFD::ThumbnailFeature::ThumbnailFeature() - { + IGFD::ThumbnailFeature::ThumbnailFeature() + { #ifdef USE_THUMBNAILS - prDisplayMode = DisplayModeEnum::FILE_LIST; + prDisplayMode = DisplayModeEnum::FILE_LIST; #endif - } + } - IGFD::ThumbnailFeature::~ThumbnailFeature() = default; + IGFD::ThumbnailFeature::~ThumbnailFeature() = default; - void IGFD::ThumbnailFeature::NewThumbnailFrame(FileDialogInternal& vFileDialogInternal) - { - (void)vFileDialogInternal; + void IGFD::ThumbnailFeature::NewThumbnailFrame(FileDialogInternal& vFileDialogInternal) + { + (void)vFileDialogInternal; #ifdef USE_THUMBNAILS - prStartThumbnailFileDatasExtraction(); + prStartThumbnailFileDatasExtraction(); #endif - } + } - void IGFD::ThumbnailFeature::EndThumbnailFrame(FileDialogInternal& vFileDialogInternal) - { + void IGFD::ThumbnailFeature::EndThumbnailFrame(FileDialogInternal& vFileDialogInternal) + { #ifdef USE_THUMBNAILS - prClearThumbnails(vFileDialogInternal); + prClearThumbnails(vFileDialogInternal); #endif - } + } - void IGFD::ThumbnailFeature::QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal) - { + void IGFD::ThumbnailFeature::QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal) + { #ifdef USE_THUMBNAILS - prStopThumbnailFileDatasExtraction(); - prClearThumbnails(vFileDialogInternal); + 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( - new std::thread(&IGFD::ThumbnailFeature::prThreadThumbnailFileDatasExtractionFunc, this), - [this](std::thread* obj) - { - prIsWorking = false; - if (obj) - obj->join(); - }); - } - } + void IGFD::ThumbnailFeature::prStartThumbnailFileDatasExtraction() + { + const bool res = prThumbnailGenerationThread.use_count() && prThumbnailGenerationThread->joinable(); + if (!res) + { + prIsWorking = true; + prCountFiles = 0U; + prThumbnailGenerationThread = std::shared_ptr( + 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(); - } + 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; + return res; + } + + void IGFD::ThumbnailFeature::prThreadThumbnailFileDatasExtractionFunc() + { + prCountFiles = 0U; + prIsWorking = true; - // infinite loop while is thread working - while(prIsWorking) - { - if (!prThumbnailFileDatasToGet.empty()) - { - std::shared_ptr file = nullptr; - prThumbnailFileDatasToGetMutex.lock(); - //get the first file in the list - file = (*prThumbnailFileDatasToGet.begin()); - prThumbnailFileDatasToGetMutex.unlock(); + // infinite loop while is thread working + while(prIsWorking) + { + if (!prThumbnailFileDatasToGet.empty()) + { + std::shared_ptr 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; + // 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; + 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 + 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; + if (resizeSucceeded) + { + auto th = &file->thumbnailInfo; - th->textureFileDatas = resizedData; - th->textureWidth = newWidth; - th->textureHeight = newHeight; - th->textureChannels = 4; //-V112 + 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; + // 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 - } + // 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); - } - } - } + 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(); - } - } - } - } + // 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); - } - } + 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::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& 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& vFileInfos) - { - if (vFileInfos.use_count()) - { - // write => thread concurency issues - prThumbnailToCreateMutex.lock(); - prThumbnailToCreate.push_back(vFileInfos); - prThumbnailToCreateMutex.unlock(); - } - } + void IGFD::ThumbnailFeature::prAddThumbnailToLoad(const std::shared_ptr& 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& 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::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::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::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::SetCreateThumbnailCallback(const CreateThumbnailFun& vCreateThumbnailFun) + { + prCreateThumbnailFun = vCreateThumbnailFun; + } - void IGFD::ThumbnailFeature::SetDestroyThumbnailCallback(const DestroyThumbnailFun& vCreateThumbnailFun) - { - prDestroyThumbnailFun = 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"); - } + 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"); - } - } + 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 /////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// BOOKMARK FEATURE /////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - IGFD::BookMarkFeature::BookMarkFeature() - { + IGFD::BookMarkFeature::BookMarkFeature() + { #ifdef USE_BOOKMARK - prBookmarkWidth = defaultBookmarkPaneWith; + prBookmarkWidth = defaultBookmarkPaneWith; #endif // USE_BOOKMARK - } + } #ifdef USE_BOOKMARK - void IGFD::BookMarkFeature::prDrawBookmarkButton() - { - IMGUI_TOGGLE_BUTTON(bookmarksButtonString, &prBookmarkPaneShown); + 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; + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(bookmarksButtonHelpString); + } + bool IGFD::BookMarkFeature::prDrawBookmarkPane(FileDialogInternal& vFileDialogInternal, const ImVec2& vSize) + { + bool res = false; - ImGui::BeginChild("##bookmarkpane", vSize); + ImGui::BeginChild("##bookmarkpane", vSize); - static int selectedBookmarkForEdition = -1; + 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 (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(); + 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::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(); + 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 (!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(); - } + 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(); + ImGui::EndChild(); - return res; - } + return res; + } - std::string IGFD::BookMarkFeature::SerializeBookmarks() - { - std::string 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; - } + 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; - } + 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); - } - } - } - } + 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 /////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// KEY EXPLORER FEATURE /////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - KeyExplorerFeature::KeyExplorerFeature() = default; + KeyExplorerFeature::KeyExplorerFeature() = default; #ifdef USE_EXPLORATION_BY_KEYS - bool IGFD::KeyExplorerFeature::prLocateItem_Loop(FileDialogInternal& vFileDialogInternal, ImWchar vC) - { - bool found = false; + 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& 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); - } + 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; - } - } - } - } - } + found = true; + break; + } + } + } + } + } - return found; - } + 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(); + 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; - } + // 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); - } + if (!prLocateItem_Loop(vFileDialogInternal, c)) + { + // not found, loop again from 0 this time + prLocateFileByInputChar_lastFileIdx = 0; + prLocateItem_Loop(vFileDialogInternal, c); + } - prLocateFileByInputChar_lastChar = c; - } - } + prLocateFileByInputChar_lastChar = c; + } + } - prLocateFileByInputChar_InputQueueCharactersSize = queueChar.size(); - } - } + 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; + 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 (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; - } + if (canWeExplore) + { + if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + { + ImGui::ClearActiveID(); + g.LastActiveId = 0; + } - auto countFiles = fdi.GetFilteredListSize(); + auto countFiles = fdi.GetFilteredListSize(); - // explore - bool exploreByKey = false; - bool enterInDirectory = false; - bool exitDirectory = false; + // 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 ((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); + 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); - } + 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(); - nfo->fileNameExt = ".."; + if (exitDirectory) + { + auto nfo = std::make_shared(); + nfo->fileNameExt = ".."; - if (fdi.SelectDirectory(nfo)) - { - // changement de repertoire - vFileDialogInternal.puFileManager.OpenCurrentPath(vFileDialogInternal); - if (prLocateFileByInputChar_lastFileIdx > countFiles - 1U) - { - prLocateFileByInputChar_lastFileIdx = 0; - } - } + 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); - } - } - } + 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; + 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; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + 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); + // 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); + // 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); + // 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)); } + // 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; - } + // 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); - } + 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 (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; + 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); + 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(); + // 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; } + // 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); + 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; + // 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); + // 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(); + 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; + // 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); + // 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(); + 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); + 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(); + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); - if (disabled_item && !disabled_global) - EndDisabled(); + if (disabled_item && !disabled_global) + EndDisabled(); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); - return pressed; //-V1020 - } + 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; - } + void IGFD::KeyExplorerFeature::prStartFlashItem(size_t vIdx) + { + prFlashAlpha = 1.0f; + prFlashedItem = vIdx; + } - bool IGFD::KeyExplorerFeature::prBeginFlashItem(size_t vIdx) - { - bool res = false; + 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; + 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; - } + ImVec4 hov = ImGui::GetStyleColorVec4(ImGuiCol_HeaderHovered); + hov.w = prFlashAlpha; + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hov); + res = true; + } - return res; - } + return res; + } - void IGFD::KeyExplorerFeature::prEndFlashItem() - { - ImGui::PopStyleColor(); - } + void IGFD::KeyExplorerFeature::prEndFlashItem() + { + ImGui::PopStyleColor(); + } - void IGFD::KeyExplorerFeature::SetFlashingAttenuationInSeconds(float vAttenValue) - { - prFlashAlphaAttenInSecs = 1.0f / ImMax(vAttenValue, 0.01f); - } + void IGFD::KeyExplorerFeature::SetFlashingAttenuationInSeconds(float vAttenValue) + { + prFlashAlphaAttenInSecs = 1.0f / ImMax(vAttenValue, 0.01f); + } #endif // USE_EXPLORATION_BY_KEYS - ///////////////////////////////////////////////////////////////////////////////////// - //// FILE DIALOG CONSTRUCTOR / DESTRUCTOR /////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// + //// FILE DIALOG CONSTRUCTOR / DESTRUCTOR /////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////// - IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {DpiScale=1.0f; singleClickSel=false; mobileMode=false;} - IGFD::FileDialog::~FileDialog() = default; + IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {DpiScale=1.0f; singleClickSel=false; mobileMode=false;} + IGFD::FileDialog::~FileDialog() = default; - ////////////////////////////////////////////////////////////////////////////////////////////////// - ///// FILE DIALOG STANDARD DIALOG //////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + ///// 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, + // 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - prFileDialogInternal.ResetForNewDialog(); + prFileDialogInternal.ResetForNewDialog(); - prFileDialogInternal.puDLGkey = vKey; - prFileDialogInternal.puDLGtitle = vTitle; - prFileDialogInternal.puDLGuserDatas = vUserDatas; - prFileDialogInternal.puDLGflags = vFlags; + 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.puDLGoptionsPane = nullptr; + prFileDialogInternal.puDLGoptionsPaneWidth = 0.0f; + prFileDialogInternal.puDLGmodal = false; - prFileDialogInternal.puFilterManager.puDLGdefaultExt.clear(); - prFileDialogInternal.puFilterManager.ParseFilters(vFilters); + 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.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 - } + 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, + // 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - prFileDialogInternal.ResetForNewDialog(); + prFileDialogInternal.ResetForNewDialog(); - prFileDialogInternal.puDLGkey = vKey; - prFileDialogInternal.puDLGtitle = vTitle; - prFileDialogInternal.puDLGoptionsPane = nullptr; - prFileDialogInternal.puDLGoptionsPaneWidth = 0.0f; - prFileDialogInternal.puDLGuserDatas = vUserDatas; - prFileDialogInternal.puDLGflags = vFlags; + 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; + 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(); - } + 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.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.puDLGDirectoryMode = (vFilters == nullptr); + prFileDialogInternal.puFileManager.puDLGcountSelectionMax = vCountSelectionMax; //-V101 - prFileDialogInternal.puFileManager.ClearAll(); - - prFileDialogInternal.puShowDialog = true; - } + 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, + // 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - prFileDialogInternal.ResetForNewDialog(); + prFileDialogInternal.ResetForNewDialog(); - prFileDialogInternal.puDLGkey = vKey; - prFileDialogInternal.puDLGtitle = vTitle; - prFileDialogInternal.puDLGuserDatas = vUserDatas; - prFileDialogInternal.puDLGflags = vFlags; + 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.puDLGoptionsPane = vSidePane; + prFileDialogInternal.puDLGoptionsPaneWidth = vSidePaneWidth; + prFileDialogInternal.puDLGmodal = false; - prFileDialogInternal.puFilterManager.puDLGdefaultExt.clear(); - prFileDialogInternal.puFilterManager.ParseFilters(vFilters); + 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.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.SetCurrentPath(prFileDialogInternal.puFileManager.puDLGpath); - prFileDialogInternal.puFileManager.SetDefaultFileName(vFileName); + prFileDialogInternal.puFileManager.SetDefaultFileName(vFileName); - prFileDialogInternal.puFileManager.ClearAll(); - - prFileDialogInternal.puShowDialog = true; // open dialog - } + 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, + // 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - prFileDialogInternal.ResetForNewDialog(); + prFileDialogInternal.ResetForNewDialog(); - prFileDialogInternal.puDLGkey = vKey; - prFileDialogInternal.puDLGtitle = vTitle; - prFileDialogInternal.puDLGoptionsPane = vSidePane; - prFileDialogInternal.puDLGoptionsPaneWidth = vSidePaneWidth; - prFileDialogInternal.puDLGuserDatas = vUserDatas; - prFileDialogInternal.puDLGflags = vFlags; + prFileDialogInternal.puDLGkey = vKey; + prFileDialogInternal.puDLGtitle = vTitle; + prFileDialogInternal.puDLGoptionsPane = vSidePane; + prFileDialogInternal.puDLGoptionsPaneWidth = vSidePaneWidth; + prFileDialogInternal.puDLGuserDatas = vUserDatas; + prFileDialogInternal.puDLGflags = vFlags; prFileDialogInternal.puDLGselFun = vSelectFun; - prFileDialogInternal.puDLGmodal = false; + 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(); - } + 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.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.puDLGcountSelectionMax = vCountSelectionMax; //-V101 + prFileDialogInternal.puFileManager.puDLGDirectoryMode = (vFilters == nullptr); + prFileDialogInternal.puFilterManager.ParseFilters(vFilters); + prFileDialogInternal.puFilterManager.SetSelectedFilterWithExt( + prFileDialogInternal.puFilterManager.puDLGdefaultExt); - prFileDialogInternal.puFileManager.ClearAll(); + prFileDialogInternal.puFileManager.ClearAll(); - prFileDialogInternal.puShowDialog = true; - } + prFileDialogInternal.puShowDialog = true; + } - ////////////////////////////////////////////////////////////////////////////////////////////////// - ///// FILE DIALOG MODAL DIALOG /////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + ///// 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, + 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - OpenDialog( - vKey, vTitle, vFilters, - vPath, vFileName, - vCountSelectionMax, vUserDatas, vFlags, vSelectFun); + OpenDialog( + vKey, vTitle, vFilters, + vPath, vFileName, + vCountSelectionMax, vUserDatas, vFlags, vSelectFun); - prFileDialogInternal.puDLGmodal = true; - } + 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, + 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - OpenDialog( - vKey, vTitle, vFilters, - vFilePathName, - vCountSelectionMax, vUserDatas, vFlags, vSelectFun); + OpenDialog( + vKey, vTitle, vFilters, + vFilePathName, + vCountSelectionMax, vUserDatas, vFlags, vSelectFun); - prFileDialogInternal.puDLGmodal = true; - } + 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, + // 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - OpenDialog( - vKey, vTitle, vFilters, - vPath, vFileName, - vSidePane, vSidePaneWidth, - vCountSelectionMax, vUserDatas, vFlags, vSelectFun); + OpenDialog( + vKey, vTitle, vFilters, + vPath, vFileName, + vSidePane, vSidePaneWidth, + vCountSelectionMax, vUserDatas, vFlags, vSelectFun); - prFileDialogInternal.puDLGmodal = true; - } + 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, + // 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; + { + if (prFileDialogInternal.puShowDialog) // if already opened, quit + return; - OpenDialog( - vKey, vTitle, vFilters, - vFilePathName, - vSidePane, vSidePaneWidth, - vCountSelectionMax, vUserDatas, vFlags, vSelectFun); + OpenDialog( + vKey, vTitle, vFilters, + vFilePathName, + vSidePane, vSidePaneWidth, + vCountSelectionMax, vUserDatas, vFlags, vSelectFun); - prFileDialogInternal.puDLGmodal = true; - } + prFileDialogInternal.puDLGmodal = true; + } - ////////////////////////////////////////////////////////////////////////////////////////////////// - ///// FILE DIALOG DISPLAY FUNCTION /////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + ///// FILE DIALOG DISPLAY FUNCTION /////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// - bool IGFD::FileDialog::Display(const std::string& vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize) - { - bool res = false; + 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()); + if (prFileDialogInternal.puShowDialog && prFileDialogInternal.puDLGkey == vKey) + { + if (prFileDialogInternal.puUseCustomLocale) + setlocale(prFileDialogInternal.puLocaleCategory, prFileDialogInternal.puLocaleBegin.c_str()); - auto& fdFile = prFileDialogInternal.puFileManager; - auto& fdFilter = prFileDialogInternal.puFilterManager; + auto& fdFile = prFileDialogInternal.puFileManager; + auto& fdFilter = prFileDialogInternal.puFilterManager; - static ImGuiWindowFlags flags; + 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 + // 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; - } + std::string name = prFileDialogInternal.puDLGtitle + "##" + prFileDialogInternal.puDLGkey; + if (prFileDialogInternal.puName != name) + { + fdFile.ClearComposer(); + fdFile.ClearFileLists(); + flags = vFlags; + } - NewFrame(); + 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); - } + 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); + 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) - { + 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().xViewport->Idx != 0) - flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar; - else - flags = vFlags; - } + // 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(); + prFileDialogInternal.puName = name; //-V820 + puAnyWindowsHovered |= ImGui::IsWindowHovered(); - if (fdFile.puDLGpath.empty()) - fdFile.puDLGpath = "."; // defaut path is '.' + if (fdFile.puDLGpath.empty()) + fdFile.puDLGpath = "."; // defaut path is '.' - fdFilter.SetDefaultFilterIfNotDefined(); + fdFilter.SetDefaultFilterIfNotDefined(); - // init list of files - if (fdFile.IsFileListEmpty() && !fdFile.puShowDrives && !fdFile.fileListActuallyEmpty) - { - 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("."); + // init list of files + if (fdFile.IsFileListEmpty() && !fdFile.puShowDrives && !fdFile.fileListActuallyEmpty) + { + 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("."); } logV("IGFD: fdFile.IsFileListEmpty() and !fdFile.puShowDrives"); - fdFile.ScanDir(prFileDialogInternal, fdFile.puDLGpath); - } + 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 + // 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(); + EndFrame(); - // for display in dialog center, the confirm to overwrite dlg - prFileDialogInternal.puDialogCenterPos = ImGui::GetCurrentWindowRead()->ContentRegionRect.GetCenter(); + // 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(); - } + // 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(); + // 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()); - } + // 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; - } + 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::NewFrame() + { + prFileDialogInternal.NewFrame(); + NewThumbnailFrame(prFileDialogInternal); + } + + void IGFD::FileDialog::EndFrame() + { + EndThumbnailFrame(prFileDialogInternal); + prFileDialogInternal.EndFrame(); + + } + void IGFD::FileDialog::QuitFrame() + { + QuitThumbnailFrame(prFileDialogInternal); + } - void IGFD::FileDialog::prDrawHeader() - { + void IGFD::FileDialog::prDrawHeader() + { #ifdef USE_BOOKMARK - prDrawBookmarkButton(); - ImGui::SameLine(); + prDrawBookmarkButton(); + ImGui::SameLine(); #endif // USE_BOOKMARK - prFileDialogInternal.puFileManager.DrawDirectoryCreation(prFileDialogInternal); - ImGui::SameLine(); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); - ImGui::SameLine(); - prFileDialogInternal.puFileManager.DrawPathComposer(prFileDialogInternal); + 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(); - } + if (!(prFileDialogInternal.puDLGflags & ImGuiFileDialogFlags_DisableThumbnailMode)) + { + prDrawDisplayModeToolBar(); + ImGui::SameLine(); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(); + } #endif // USE_THUMBNAILS - prFileDialogInternal.puSearchManager.DrawSearchBar(prFileDialogInternal); - } + prFileDialogInternal.puSearchManager.DrawSearchBar(prFileDialogInternal); + } - bool IGFD::FileDialog::prDrawContent() - { + bool IGFD::FileDialog::prDrawContent() + { bool escape = false; - ImVec2 size = ImGui::GetContentRegionAvail() - ImVec2(0.0f, prFileDialogInternal.puFooterHeight); + 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(); - } + 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; + 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(); - } + 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); - } - } + 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); + escape = prDrawFileListView(size); #endif // USE_THUMBNAILS - if (prFileDialogInternal.puDLGoptionsPane) - { - prDrawSidePane(size.y); - } + 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 + 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); + if (!fdFile.puDLGDirectoryMode) + ImGui::Text(fileNameString); + else // directory chooser + ImGui::Text(dirNameString); - ImGui::SameLine(); + ImGui::SameLine(); - // Input file fields - float width = ImGui::GetContentRegionAvail().x; + // 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(); + 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); + // combobox of filters + prFileDialogInternal.puFilterManager.DrawFilterComboBox(prFileDialogInternal); - bool res = false; + bool res = false; - // OK Button - if (prFileDialogInternal.puCanWeContinue && strlen(fdFile.puFileNameBuffer)) - { - if (IMGUI_BUTTON(okButtonString "##validationdialog")) - { - prFileDialogInternal.puIsOk = true; - res = true; - } + // OK Button + if (prFileDialogInternal.puCanWeContinue && strlen(fdFile.puFileNameBuffer)) + { + if (IMGUI_BUTTON(okButtonString "##validationdialog")) + { + prFileDialogInternal.puIsOk = true; + res = true; + } - ImGui::SameLine(); - } + ImGui::SameLine(); + } - // Cancel Button - if (IMGUI_BUTTON(cancelButtonString "##validationdialog") || - prFileDialogInternal.puNeedToExitDialog) // dialog exit asked - { - prFileDialogInternal.puIsOk = false; - res = true; - } + // Cancel Button + if (IMGUI_BUTTON(cancelButtonString "##validationdialog") || + prFileDialogInternal.puNeedToExitDialog) // dialog exit asked + { + prFileDialogInternal.puIsOk = false; + res = true; + } - prFileDialogInternal.puFooterHeight = ImGui::GetCursorPosY() - posY; + prFileDialogInternal.puFooterHeight = ImGui::GetCursorPosY() - posY; - return res; - } + 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 vInfos, bool vSelected, const char* vFmt, ...) - { - if (!vInfos.use_count()) - return 0; + int IGFD::FileDialog::prSelectableItem(int vidx, std::shared_ptr vInfos, bool vSelected, const char* vFmt, ...) + { + if (!vInfos.use_count()) + return 0; - auto& fdi = prFileDialogInternal.puFileManager; + auto& fdi = prFileDialogInternal.puFileManager; - static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick | - ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth; + 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); + 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; + float h = /*mobileMode?(ImGui::GetFontSize()+10.0f*DpiScale):*/0.0f; #ifdef USE_THUMBNAILS - if (prDisplayMode == DisplayModeEnum::THUMBNAILS_LIST) - h = DisplayMode_ThumbailsList_ImageHeight; + 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(); + 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 + (void)vidx; // remove a warnings ofr unused var - bool res = ImGui::Selectable(fdi.puVariadicBuffer, vSelected, selectableFlags, ImVec2(-1.0f, h)); + bool res = ImGui::Selectable(fdi.puVariadicBuffer, vSelected, selectableFlags, ImVec2(-1.0f, h)); #endif // USE_EXPLORATION_BY_KEYS - if (res) - { - if (vInfos->fileType == 'd') - { + 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); + // 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 - { + } + } + 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); - } - } + fdi.puPathClicked = fdi.SelectDirectory(vInfos); + } + else if (fdi.puDLGDirectoryMode) // directory chooser + { + fdi.SelectFileName(prFileDialogInternal, vInfos); + } + } - return isSelectingDir; // needToBreakTheloop - } - else - { + return isSelectingDir; // needToBreakTheloop + } + else + { if (DOUBLE_CLICKED) { fdi.SelectFileName(prFileDialogInternal, vInfos); prFileDialogInternal.puIsOk = true; return 2; } else { - fdi.SelectFileName(prFileDialogInternal, vInfos); + fdi.SelectFileName(prFileDialogInternal, vInfos); if (prFileDialogInternal.puDLGselFun!=NULL) { std::string argPath; for (auto& i: GetSelection()) { @@ -4053,581 +3969,581 @@ namespace IGFD } } } - } - } + } + } - return 0; - } + return 0; + } - void IGFD::FileDialog::prBeginFileColorIconStyle(std::shared_ptr vFileInfos, bool& vOutShowColor, std::string& vOutStr, ImFont** vOutFont) - { - vOutStr.clear(); - vOutShowColor = false; + void IGFD::FileDialog::prBeginFileColorIconStyle(std::shared_ptr vFileInfos, bool& vOutShowColor, std::string& vOutStr, ImFont** vOutFont) + { + vOutStr.clear(); + vOutShowColor = false; - if (vFileInfos->fileStyle.use_count()) //-V807 //-V522 - { - vOutShowColor = true; + if (vFileInfos->fileStyle.use_count()) //-V807 //-V522 + { + vOutShowColor = true; - *vOutFont = vFileInfos->fileStyle->font; - } + *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; + 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; + vOutStr += " " + vFileInfos->fileNameExt; - if (vOutShowColor) - ImGui::PushStyleColor(ImGuiCol_Text, vFileInfos->fileStyle->color); - if (*vOutFont) - ImGui::PushFont(*vOutFont); - } + 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(); - } + void IGFD::FileDialog::prEndFileColorIconStyle(const bool& vShowColor, ImFont* vFont) + { + if (vFont) + ImGui::PopFont(); + if (vShowColor) + ImGui::PopStyleColor(); + } - bool IGFD::FileDialog::prDrawFileListView(ImVec2 vSize) - { + bool IGFD::FileDialog::prDrawFileListView(ImVec2 vSize) + { bool escape = false; - auto& fdi = prFileDialogInternal.puFileManager; + auto& fdi = prFileDialogInternal.puFileManager; - ImGui::PushID(this); + ImGui::PushID(this); - static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | - ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | - ImGuiTableFlags_NoHostExtendY + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | + ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | + ImGuiTableFlags_NoHostExtendY #ifndef USE_CUSTOM_SORTING_ICON - | ImGuiTableFlags_Sortable + | 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); + ; + 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); + // 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; - } - } + sorts_specs->SpecsDirty = false; + } + } - ImGui::TableHeadersRow(); + 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); - } - } + 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; + 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; + auto infos = fdi.GetFilteredFileAt((size_t)i); + if (!infos.use_count()) + continue; - prBeginFileColorIconStyle(infos, _showColor, _str, &_font); - - bool selected = fdi.IsFileNameSelected(infos->fileNameExt); // found + prBeginFileColorIconStyle(infos, _showColor, _str, &_font); + + bool selected = fdi.IsFileNameSelected(infos->fileNameExt); // found - ImGui::TableNextRow(); + ImGui::TableNextRow(); - int needToBreakTheloop = false; + int needToBreakTheloop = false; - if (ImGui::TableNextColumn()) // file name - { + if (ImGui::TableNextColumn()) // file name + { // TODO BUG?!?!?! // YES BUG - needToBreakTheloop = prSelectableItem(i, infos, selected, "%s", _str.c_str()); + 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()); - } + } + 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); + prEndFileColorIconStyle(_showColor, _font); - if (needToBreakTheloop==1) - break; - } - } - prFileListClipper.End(); - } + if (needToBreakTheloop==1) + break; + } + } + prFileListClipper.End(); + } #ifdef USE_EXPLORATION_BY_KEYS - if (!fdi.puInputPathActivated) - { - prLocateByInputKey(prFileDialogInternal); - prExploreWithkeys(prFileDialogInternal, listViewID); - } + 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; - } + ImGuiContext& g = *GImGui; + if (g.LastActiveId - 1 == listViewID || g.LastActiveId == listViewID) + { + prFileDialogInternal.puFileListViewIsActive = true; + } - ImGui::EndTable(); - } + ImGui::EndTable(); + } - ImGui::PopID(); + ImGui::PopID(); return escape; - } + } #ifdef USE_THUMBNAILS - void IGFD::FileDialog::prDrawThumbnailsListView(ImVec2 vSize) - { - auto& fdi = prFileDialogInternal.puFileManager; + void IGFD::FileDialog::prDrawThumbnailsListView(ImVec2 vSize) + { + auto& fdi = prFileDialogInternal.puFileManager; - ImGui::PushID(this); + ImGui::PushID(this); - static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | - ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | - ImGuiTableFlags_NoHostExtendY + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | + ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | + ImGuiTableFlags_NoHostExtendY #ifndef USE_CUSTOM_SORTING_ICON - | ImGuiTableFlags_Sortable + | 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 + ; + 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; - } - } + // 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(); + 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); - } - } + 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; + 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; + 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; + 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; + auto infos = fdi.GetFilteredFileAt((size_t)i); + if (!infos.use_count()) + continue; - prBeginFileColorIconStyle(infos, _showColor, _str, &_font); + prBeginFileColorIconStyle(infos, _showColor, _str, &_font); - bool selected = fdi.IsFileNameSelected(infos->fileNameExt); // found + bool selected = fdi.IsFileNameSelected(infos->fileNameExt); // found - ImGui::TableNextRow(); + ImGui::TableNextRow(); - bool needToBreakTheloop = false; + 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 (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)); - } - } + 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); + prEndFileColorIconStyle(_showColor, _font); - if (needToBreakTheloop) - break; - } - } - prFileListClipper.End(); - } + if (needToBreakTheloop) + break; + } + } + prFileListClipper.End(); + } #ifdef USE_EXPLORATION_BY_KEYS - if (!fdi.puInputPathActivated) - { - prLocateByInputKey(prFileDialogInternal); - prExploreWithkeys(prFileDialogInternal, listViewID); - } + 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; - } + ImGuiContext& g = *GImGui; + if (g.LastActiveId - 1 == listViewID || g.LastActiveId == listViewID) + { + prFileDialogInternal.puFileListViewIsActive = true; + } - ImGui::EndTable(); - } + ImGui::EndTable(); + } - ImGui::PopID(); - } + ImGui::PopID(); + } - void IGFD::FileDialog::prDrawThumbnailsGridView(ImVec2 vSize) - { - if (ImGui::BeginChild("##thumbnailsGridsFiles", vSize)) - { - // todo - } + void IGFD::FileDialog::prDrawThumbnailsGridView(ImVec2 vSize) + { + if (ImGui::BeginChild("##thumbnailsGridsFiles", vSize)) + { + // todo + } - ImGui::EndChild(); - } + ImGui::EndChild(); + } #endif - void IGFD::FileDialog::prDrawSidePane(float vHeight) - { - ImGui::SameLine(); + void IGFD::FileDialog::prDrawSidePane(float vHeight) + { + ImGui::SameLine(); - ImGui::BeginChild("##FileTypes", ImVec2(0, vHeight)); + ImGui::BeginChild("##FileTypes", ImVec2(0, vHeight)); - prFileDialogInternal.puDLGoptionsPane( - prFileDialogInternal.puFilterManager.GetSelectedFilter().filter.c_str(), - prFileDialogInternal.puDLGuserDatas, &prFileDialogInternal.puCanWeContinue); + prFileDialogInternal.puDLGoptionsPane( + prFileDialogInternal.puFilterManager.GetSelectedFilter().filter.c_str(), + prFileDialogInternal.puDLGuserDatas, &prFileDialogInternal.puCanWeContinue); - ImGui::EndChild(); - } + ImGui::EndChild(); + } - void IGFD::FileDialog::Close() - { - prFileDialogInternal.puDLGkey.clear(); - prFileDialogInternal.puShowDialog = false; - } + 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 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::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 std::string& vKey) const + { + return (prFileDialogInternal.puShowDialog && prFileDialogInternal.puDLGkey == vKey); + } - bool IGFD::FileDialog::IsOpened() const - { - return prFileDialogInternal.puShowDialog; - } + 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::GetOpenedKey() const + { + if (prFileDialogInternal.puShowDialog) + return prFileDialogInternal.puDLGkey; + return ""; + } - std::string IGFD::FileDialog::GetFilePathName() - { - return prFileDialogInternal.puFileManager.GetResultingFilePathName(prFileDialogInternal); - } + std::string IGFD::FileDialog::GetFilePathName() + { + return prFileDialogInternal.puFileManager.GetResultingFilePathName(prFileDialogInternal); + } - std::string IGFD::FileDialog::GetCurrentPath() - { - return prFileDialogInternal.puFileManager.GetResultingPath(); - } + std::string IGFD::FileDialog::GetCurrentPath() + { + return prFileDialogInternal.puFileManager.GetResultingPath(); + } - std::string IGFD::FileDialog::GetCurrentFileName() - { - return prFileDialogInternal.puFileManager.GetResultingFileName(prFileDialogInternal); - } + std::string IGFD::FileDialog::GetCurrentFileName() + { + return prFileDialogInternal.puFileManager.GetResultingFileName(prFileDialogInternal); + } - std::string IGFD::FileDialog::GetCurrentFilter() - { - return prFileDialogInternal.puFilterManager.GetSelectedFilter().filter; - } + std::string IGFD::FileDialog::GetCurrentFilter() + { + return prFileDialogInternal.puFilterManager.GetSelectedFilter().filter; + } - std::map IGFD::FileDialog::GetSelection() - { - return prFileDialogInternal.puFileManager.GetResultingSelection(); - } + std::map IGFD::FileDialog::GetSelection() + { + return prFileDialogInternal.puFileManager.GetResultingSelection(); + } - UserDatas IGFD::FileDialog::GetUserDatas() const - { - return prFileDialogInternal.puDLGuserDatas; - } + UserDatas IGFD::FileDialog::GetUserDatas() const + { + return prFileDialogInternal.puDLGuserDatas; + } - bool IGFD::FileDialog::IsOk() const - { - return prFileDialogInternal.puIsOk; - } + 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 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); - } + 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); - } + 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::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; - } + 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 //////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + //// 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 + 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 == 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 && 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; - } - } + // 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"; + std::string name = OverWriteDialogTitleString "##" + prFileDialogInternal.puDLGtitle + prFileDialogInternal.puDLGkey + "OverWriteDialog"; - bool res = false; + 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::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); + ImGui::Text("%s", OverWriteDialogMessageString); - if (IMGUI_BUTTON(OverWriteDialogConfirmButtonString)) - { - prFileDialogInternal.puOkResultToConfirm = false; - prFileDialogInternal.puIsOk = true; - res = true; - ImGui::CloseCurrentPopup(); - } + if (IMGUI_BUTTON(OverWriteDialogConfirmButtonString)) + { + prFileDialogInternal.puOkResultToConfirm = false; + prFileDialogInternal.puIsOk = true; + res = true; + ImGui::CloseCurrentPopup(); + } - ImGui::SameLine(); + ImGui::SameLine(); - if (IMGUI_BUTTON(OverWriteDialogCancelButtonString)) - { - prFileDialogInternal.puOkResultToConfirm = false; - prFileDialogInternal.puIsOk = false; - res = false; - ImGui::CloseCurrentPopup(); - } + if (IMGUI_BUTTON(OverWriteDialogCancelButtonString)) + { + prFileDialogInternal.puOkResultToConfirm = false; + prFileDialogInternal.puIsOk = false; + res = false; + ImGui::CloseCurrentPopup(); + } - ImGui::EndPopup(); - } + ImGui::EndPopup(); + } - if (res) - { - QuitFrame(); - } - return res; - } + if (res) + { + QuitFrame(); + } + return res; + } - return false; - } + return false; + } } #endif // __cplusplus @@ -4639,574 +4555,574 @@ namespace IGFD // 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; + 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; - } + 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 }; + 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; - } + 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(); + return new ImGuiFileDialog(); } // destroy the instance of ImGuiFileDialog IMGUIFILEDIALOG_API void IGFD_Destroy(ImGuiFileDialog* vContext) { - if (vContext) - { - delete vContext; - vContext = nullptr; - } + 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) + 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); - } + 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) + 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); - } + 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) + 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); - } + 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) + 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); - } + 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) + 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); - } + 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) + 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); - } + 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) + 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); - } + 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) + 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); - } + 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) + const char* vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize) { - if (vContext) - { - return vContext->Display(vKey, vFlags, vMinSize, vMaxSize); - } + if (vContext) + { + return vContext->Display(vKey, vFlags, vMinSize, vMaxSize); + } - return false; + return false; } IMGUIFILEDIALOG_API void IGFD_CloseDialog(ImGuiFileDialog* vContext) { - if (vContext) - { - vContext->Close(); - } + if (vContext) + { + vContext->Close(); + } } IMGUIFILEDIALOG_API bool IGFD_IsOk(ImGuiFileDialog* vContext) { - if (vContext) - { - return vContext->IsOk(); - } + if (vContext) + { + return vContext->IsOk(); + } - return false; + return false; } IMGUIFILEDIALOG_API bool IGFD_WasKeyOpenedThisFrame(ImGuiFileDialog* vContext, - const char* vKey) + const char* vKey) { - if (vContext) - { - vContext->WasOpenedThisFrame(vKey); - } + if (vContext) + { + vContext->WasOpenedThisFrame(vKey); + } - return false; + return false; } IMGUIFILEDIALOG_API bool IGFD_WasOpenedThisFrame(ImGuiFileDialog* vContext) { - if (vContext) - { - vContext->WasOpenedThisFrame(); - } + if (vContext) + { + vContext->WasOpenedThisFrame(); + } - return false; + return false; } IMGUIFILEDIALOG_API bool IGFD_IsKeyOpened(ImGuiFileDialog* vContext, - const char* vCurrentOpenedKey) + const char* vCurrentOpenedKey) { - if (vContext) - { - vContext->IsOpened(vCurrentOpenedKey); - } + if (vContext) + { + vContext->IsOpened(vCurrentOpenedKey); + } - return false; + return false; } IMGUIFILEDIALOG_API bool IGFD_IsOpened(ImGuiFileDialog* vContext) { - if (vContext) - { - vContext->IsOpened(); - } + if (vContext) + { + vContext->IsOpened(); + } - return false; + return false; } IMGUIFILEDIALOG_API IGFD_Selection IGFD_GetSelection(ImGuiFileDialog* vContext) { - IGFD_Selection res = IGFD_Selection_Get(); + 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]; + 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++; + 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]; + // 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); + strncpy(pair->fileName, s.first.c_str(), siz); #else - strncpy_s(pair->fileName, siz, s.first.c_str(), siz); + strncpy_s(pair->fileName, siz, s.first.c_str(), siz); #endif - pair->fileName[siz - 1U] = '\0'; - } + pair->fileName[siz - 1U] = '\0'; + } - // filePathName - if (!s.second.empty()) - { - size_t siz = s.first.size() + 1U; - pair->filePathName = new char[siz]; + // 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); + strncpy(pair->filePathName, s.first.c_str(), siz); #else - strncpy_s(pair->filePathName, siz, s.first.c_str(), siz); + strncpy_s(pair->filePathName, siz, s.first.c_str(), siz); #endif - pair->filePathName[siz - 1U] = '\0'; - } - } + pair->filePathName[siz - 1U] = '\0'; + } + } - return res; - } - } + return res; + } + } - return res; + return res; } IMGUIFILEDIALOG_API char* IGFD_GetFilePathName(ImGuiFileDialog* vContext) { - char* res = nullptr; + char* res = nullptr; - if (vContext) - { - auto s = vContext->GetFilePathName(); - if (!s.empty()) - { - size_t siz = s.size() + 1U; - res = new char[siz]; + 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); + strncpy(res, s.c_str(), siz); #else - strncpy_s(res, siz, s.c_str(), siz); + strncpy_s(res, siz, s.c_str(), siz); #endif - res[siz - 1U] = '\0'; - } - } + res[siz - 1U] = '\0'; + } + } - return res; + return res; } IMGUIFILEDIALOG_API char* IGFD_GetCurrentFileName(ImGuiFileDialog* vContext) { - char* res = nullptr; + char* res = nullptr; - if (vContext) - { - auto s = vContext->GetCurrentFileName(); - if (!s.empty()) - { - size_t siz = s.size() + 1U; - res = new char[siz]; + 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); + strncpy(res, s.c_str(), siz); #else - strncpy_s(res, siz, s.c_str(), siz); + strncpy_s(res, siz, s.c_str(), siz); #endif - res[siz - 1U] = '\0'; - } - } + res[siz - 1U] = '\0'; + } + } - return res; + return res; } IMGUIFILEDIALOG_API char* IGFD_GetCurrentPath(ImGuiFileDialog* vContext) { - char* res = nullptr; + char* res = nullptr; - if (vContext) - { - auto s = vContext->GetCurrentPath(); - if (!s.empty()) - { - size_t siz = s.size() + 1U; - res = new char[siz]; + 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); + strncpy(res, s.c_str(), siz); #else - strncpy_s(res, siz, s.c_str(), siz); + strncpy_s(res, siz, s.c_str(), siz); #endif - res[siz - 1U] = '\0'; - } - } + res[siz - 1U] = '\0'; + } + } - return res; + return res; } IMGUIFILEDIALOG_API char* IGFD_GetCurrentFilter(ImGuiFileDialog* vContext) { - char* res = nullptr; + char* res = nullptr; - if (vContext) - { - auto s = vContext->GetCurrentFilter(); - if (!s.empty()) - { - size_t siz = s.size() + 1U; - res = new char[siz]; + 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); + strncpy(res, s.c_str(), siz); #else - strncpy_s(res, siz, s.c_str(), siz); + strncpy_s(res, siz, s.c_str(), siz); #endif - res[siz - 1U] = '\0'; - } - } + res[siz - 1U] = '\0'; + } + } - return res; + return res; } IMGUIFILEDIALOG_API void* IGFD_GetUserDatas(ImGuiFileDialog* vContext) { - if (vContext) - { - return vContext->GetUserDatas(); - } + if (vContext) + { + return vContext->GetUserDatas(); + } - return nullptr; + return nullptr; } IMGUIFILEDIALOG_API void IGFD_SetFileStyle(ImGuiFileDialog* vContext, - IGFD_FileStyleFlags vFlags, const char* vCriteria, ImVec4 vColor, const char* vIcon, ImFont* vFont) //-V813 + IGFD_FileStyleFlags vFlags, const char* vCriteria, ImVec4 vColor, const char* vIcon, ImFont* vFont) //-V813 { - if (vContext) - { - vContext->SetFileStyle(vFlags, vCriteria, vColor, vIcon, vFont); - } + 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) + 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); - } + 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) + 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]; + 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); + strncpy(*vOutIcon, icon.c_str(), siz); #else - strncpy_s(*vOutIcon, siz, icon.c_str(), siz); + strncpy_s(*vOutIcon, siz, icon.c_str(), siz); #endif - (*vOutIcon)[siz - 1U] = '\0'; - } - return res; - } + (*vOutIcon)[siz - 1U] = '\0'; + } + return res; + } - return false; + return false; } IMGUIFILEDIALOG_API void IGFD_ClearFilesStyle(ImGuiFileDialog* vContext) { - if (vContext) - { - vContext->ClearFilesStyle(); - } + 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 : "")); - } + 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); - } + if (vContext) + { + vContext->SetFlashingAttenuationInSeconds(vAttenValue); + } } #endif #ifdef USE_BOOKMARK IMGUIFILEDIALOG_API char* IGFD_SerializeBookmarks(ImGuiFileDialog* vContext) { - char* res = nullptr; + char* res = nullptr; - if (vContext) - { - auto s = vContext->SerializeBookmarks(); - if (!s.empty()) - { - size_t siz = s.size() + 1U; - res = new char[siz]; + 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); + strncpy(res, s.c_str(), siz); #else - strncpy_s(res, siz, s.c_str(), siz); + strncpy_s(res, siz, s.c_str(), siz); #endif - res[siz - 1U] = '\0'; - } - } + res[siz - 1U] = '\0'; + } + } - return res; + return res; } IMGUIFILEDIALOG_API void IGFD_DeserializeBookmarks(ImGuiFileDialog* vContext, const char* vBookmarks) { - if (vContext) - { - vContext->DeserializeBookmarks(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); - } + if (vContext) + { + vContext->SetCreateThumbnailCallback(vCreateThumbnailFun); + } } IMGUIFILEDIALOG_API void SetDestroyThumbnailCallback(ImGuiFileDialog* vContext, const IGFD_DestroyThumbnailFun vDestroyThumbnailFun) { - if (vContext) - { - vContext->SetDestroyThumbnailCallback(vDestroyThumbnailFun); - } + if (vContext) + { + vContext->SetDestroyThumbnailCallback(vDestroyThumbnailFun); + } } IMGUIFILEDIALOG_API void ManageGPUThumbnails(ImGuiFileDialog* vContext) { - if (vContext) - { - vContext->ManageGPUThumbnails(); - } + if (vContext) + { + vContext->ManageGPUThumbnails(); + } } #endif // USE_THUMBNAILS diff --git a/extern/igfd/ImGuiFileDialog.h b/extern/igfd/ImGuiFileDialog.h index 827a987e..5ab7f6c8 100644 --- a/extern/igfd/ImGuiFileDialog.h +++ b/extern/igfd/ImGuiFileDialog.h @@ -85,20 +85,20 @@ void drawGui() { // open Dialog Simple if (ImGui::Button("Open File Dialog")) - ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", "."); + ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", "."); // display if (ImGuiFileDialog::Instance()->FileDialog("ChooseFileDlgKey")) { - // action if OK - if (ImGuiFileDialog::Instance()->IsOk == true) - { - std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); - std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); - // action - } - // close - ImGuiFileDialog::Instance()->CloseDialog("ChooseFileDlgKey"); + // action if OK + if (ImGuiFileDialog::Instance()->IsOk == true) + { + std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); + // action + } + // close + ImGuiFileDialog::Instance()->CloseDialog("ChooseFileDlgKey"); } } @@ -121,40 +121,40 @@ Example code : static bool canValidateDialog = false; inline void InfosPane(std::string& vFilter, IGFD::UserDatas vUserDatas, bool *vCantContinue) // if vCantContinue is false, the user cant validate the dialog { - ImGui::TextColored(ImVec4(0, 1, 1, 1), "Infos Pane"); - ImGui::Text("Selected Filter : %s", vFilter.c_str()); - if (vUserDatas) - ImGui::Text("UserDatas : %s", vUserDatas); - ImGui::Checkbox("if not checked you cant validate the dialog", &canValidateDialog); - if (vCantContinue) - *vCantContinue = canValidateDialog; + ImGui::TextColored(ImVec4(0, 1, 1, 1), "Infos Pane"); + ImGui::Text("Selected Filter : %s", vFilter.c_str()); + if (vUserDatas) + ImGui::Text("UserDatas : %s", vUserDatas); + ImGui::Checkbox("if not checked you cant validate the dialog", &canValidateDialog); + if (vCantContinue) + *vCantContinue = canValidateDialog; } void drawGui() { // open Dialog with Pane if (ImGui::Button("Open File Dialog with a custom pane")) - ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", - ".", "", std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 350, 1, IGFD::UserDatas("InfosPane")); + ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", + ".", "", std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 350, 1, IGFD::UserDatas("InfosPane")); // display and action if ok if (ImGuiFileDialog::Instance()->FileDialog("ChooseFileDlgKey")) { - if (ImGuiFileDialog::Instance()->IsOk == true) - { - std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); - std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); - std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter(); - // here convert from string because a string was passed as a userDatas, but it can be what you want - std::string userDatas; - if (ImGuiFileDialog::Instance()->GetUserDatas()) - userDatas = std::string((const char*)ImGuiFileDialog::Instance()->GetUserDatas()); - auto selection = ImGuiFileDialog::Instance()->GetSelection(); // multiselection + if (ImGuiFileDialog::Instance()->IsOk == true) + { + std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); + std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter(); + // here convert from string because a string was passed as a userDatas, but it can be what you want + std::string userDatas; + if (ImGuiFileDialog::Instance()->GetUserDatas()) + userDatas = std::string((const char*)ImGuiFileDialog::Instance()->GetUserDatas()); + auto selection = ImGuiFileDialog::Instance()->GetSelection(); // multiselection - // action - } - // close - ImGuiFileDialog::Instance()->CloseDialog("ChooseFileDlgKey"); + // action + } + // close + ImGuiFileDialog::Instance()->CloseDialog("ChooseFileDlgKey"); } } @@ -170,13 +170,13 @@ the general form is : ImGuiFileDialog::Instance()->SetFileStyle(styleType, criteria, color, icon, font); styleType can be thoses : -IGFD_FileStyle_None // define none style -IGFD_FileStyleByTypeFile // define style for all files -IGFD_FileStyleByTypeDir // define style for all dir -IGFD_FileStyleByTypeLink // define style for all link -IGFD_FileStyleByExtention // define style by extention, for files or links -IGFD_FileStyleByFullName // define style for particular file/dir/link full name (filename + extention) -IGFD_FileStyleByContainedInFullName // define style for file/dir/link when criteria is contained in full name +IGFD_FileStyle_None // define none style +IGFD_FileStyleByTypeFile // define style for all files +IGFD_FileStyleByTypeDir // define style for all dir +IGFD_FileStyleByTypeLink // define style for all link +IGFD_FileStyleByExtention // define style by extention, for files or links +IGFD_FileStyleByFullName // define style for particular file/dir/link full name (filename + extention) +IGFD_FileStyleByContainedInFullName // define style for file/dir/link when criteria is contained in full name samples : @@ -341,14 +341,14 @@ define if a dialog will be for Open or Save behavior. (and its wanted :) ) Example code For Standard Dialog : Example code : ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", - ICON_IGFD_SAVE " Choose a File", filters, - ".", "", 1, nullptr, ImGuiFileDialogFlags_ConfirmOverwrite); + ICON_IGFD_SAVE " Choose a File", filters, + ".", "", 1, nullptr, ImGuiFileDialogFlags_ConfirmOverwrite); Example code For Modal Dialog : Example code : ImGuiFileDialog::Instance()->OpenModal("ChooseFileDlgKey", - ICON_IGFD_SAVE " Choose a File", filters, - ".", "", 1, nullptr, ImGuiFileDialogFlags_ConfirmOverwrite); + ICON_IGFD_SAVE " Choose a File", filters, + ".", "", 1, nullptr, ImGuiFileDialogFlags_ConfirmOverwrite); This dialog will only verify the file in the file field. So Not to be used with GetSelection() @@ -372,8 +372,8 @@ Example code : ----------------------------------------------------------------------------------------------------------------- flag must be specified in OpenDialog or OpenModal -* ImGuiFileDialogFlags_ConfirmOverwrite => show confirm to overwrite dialog -* ImGuiFileDialogFlags_DontShowHiddenFiles => dont show hidden file (file starting with a .) +* ImGuiFileDialogFlags_ConfirmOverwrite => show confirm to overwrite dialog +* ImGuiFileDialogFlags_DontShowHiddenFiles => dont show hidden file (file starting with a .) ----------------------------------------------------------------------------------------------------------------- ## Open / Save dialog Behavior : @@ -419,43 +419,43 @@ Example code : // Create thumbnails texture ImGuiFileDialog::Instance()->SetCreateThumbnailCallback([](IGFD_Thumbnail_Info *vThumbnail_Info) -> void { - if (vThumbnail_Info && - vThumbnail_Info->isReadyToUpload && - vThumbnail_Info->textureFileDatas) - { - GLuint textureId = 0; - glGenTextures(1, &textureId); - vThumbnail_Info->textureID = (void*)textureId; + if (vThumbnail_Info && + vThumbnail_Info->isReadyToUpload && + vThumbnail_Info->textureFileDatas) + { + GLuint textureId = 0; + glGenTextures(1, &textureId); + vThumbnail_Info->textureID = (void*)textureId; - glBindTexture(GL_TEXTURE_2D, textureId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - (GLsizei)vThumbnail_Info->textureWidth, (GLsizei)vThumbnail_Info->textureHeight, - 0, GL_RGBA, GL_UNSIGNED_BYTE, vThumbnail_Info->textureFileDatas); - glFinish(); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D, textureId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + (GLsizei)vThumbnail_Info->textureWidth, (GLsizei)vThumbnail_Info->textureHeight, + 0, GL_RGBA, GL_UNSIGNED_BYTE, vThumbnail_Info->textureFileDatas); + glFinish(); + glBindTexture(GL_TEXTURE_2D, 0); - delete[] vThumbnail_Info->textureFileDatas; - vThumbnail_Info->textureFileDatas = nullptr; + delete[] vThumbnail_Info->textureFileDatas; + vThumbnail_Info->textureFileDatas = nullptr; - vThumbnail_Info->isReadyToUpload = false; - vThumbnail_Info->isReadyToDisplay = true; - } + vThumbnail_Info->isReadyToUpload = false; + vThumbnail_Info->isReadyToDisplay = true; + } }); Example code : // Destroy thumbnails texture ImGuiFileDialog::Instance()->SetDestroyThumbnailCallback([](IGFD_Thumbnail_Info* vThumbnail_Info) { - if (vThumbnail_Info) - { - GLuint texID = (GLuint)vThumbnail_Info->textureID; - glDeleteTextures(1, &texID); - glFinish(); - } + if (vThumbnail_Info) + { + GLuint texID = (GLuint)vThumbnail_Info->textureID; + glDeleteTextures(1, &texID); + glFinish(); + } }); Example code : @@ -477,17 +477,17 @@ ImGuiFileDialog *cfileDialog = IGFD_Create(); // open dialog if (igButton("Open File", buttonSize)) { - IGFD_OpenDialog(cfiledialog, - "filedlg", // dialog key (make it possible to have different treatment reagrding the dialog key - "Open a File", // dialog title - "c files(*.c *.h){.c,.h}", // dialog filter syntax : simple => .h,.c,.pp, etc and collections : text1{filter0,filter1,filter2}, text2{filter0,filter1,filter2}, etc.. - ".", // base directory for files scan - "", // base filename - 0, // a fucntion for display a right pane if you want - 0.0f, // base width of the pane - 0, // count selection : 0 infinite, 1 one file (default), n (n files) - "User data !", // some user datas - ImGuiFileDialogFlags_ConfirmOverwrite); // ImGuiFileDialogFlags + IGFD_OpenDialog(cfiledialog, + "filedlg", // dialog key (make it possible to have different treatment reagrding the dialog key + "Open a File", // dialog title + "c files(*.c *.h){.c,.h}", // dialog filter syntax : simple => .h,.c,.pp, etc and collections : text1{filter0,filter1,filter2}, text2{filter0,filter1,filter2}, etc.. + ".", // base directory for files scan + "", // base filename + 0, // a fucntion for display a right pane if you want + 0.0f, // base width of the pane + 0, // count selection : 0 infinite, 1 one file (default), n (n files) + "User data !", // some user datas + ImGuiFileDialogFlags_ConfirmOverwrite); // ImGuiFileDialogFlags } ImGuiIO* ioptr = igGetIO(); @@ -501,56 +501,46 @@ minSize.y = maxSize.y * 0.25f; // display dialog if (IGFD_DisplayDialog(cfiledialog, "filedlg", ImGuiWindowFlags_NoCollapse, minSize, maxSize)) { - if (IGFD_IsOk(cfiledialog)) // result ok - { - char* cfilePathName = IGFD_GetFilePathName(cfiledialog); - printf("GetFilePathName : %s\n", cfilePathName); - char* cfilePath = IGFD_GetCurrentPath(cfiledialog); - printf("GetCurrentPath : %s\n", cfilePath); - char* cfilter = IGFD_GetCurrentFilter(cfiledialog); - printf("GetCurrentFilter : %s\n", cfilter); - // here convert from string because a string was passed as a userDatas, but it can be what you want - void* cdatas = IGFD_GetUserDatas(cfiledialog); - if (cdatas) - printf("GetUserDatas : %s\n", (const char*)cdatas); - struct IGFD_Selection csel = IGFD_GetSelection(cfiledialog); // multi selection - printf("Selection :\n"); - for (int i = 0; i < (int)csel.count; i++) - { - printf("(%i) FileName %s => path %s\n", i, csel.table[i].fileName, csel.table[i].filePathName); - } - // action + if (IGFD_IsOk(cfiledialog)) // result ok + { + char* cfilePathName = IGFD_GetFilePathName(cfiledialog); + printf("GetFilePathName : %s\n", cfilePathName); + char* cfilePath = IGFD_GetCurrentPath(cfiledialog); + printf("GetCurrentPath : %s\n", cfilePath); + char* cfilter = IGFD_GetCurrentFilter(cfiledialog); + printf("GetCurrentFilter : %s\n", cfilter); + // here convert from string because a string was passed as a userDatas, but it can be what you want + void* cdatas = IGFD_GetUserDatas(cfiledialog); + if (cdatas) + printf("GetUserDatas : %s\n", (const char*)cdatas); + struct IGFD_Selection csel = IGFD_GetSelection(cfiledialog); // multi selection + printf("Selection :\n"); + for (int i = 0; i < (int)csel.count; i++) + { + printf("(%i) FileName %s => path %s\n", i, csel.table[i].fileName, csel.table[i].filePathName); + } + // action - // destroy - if (cfilePathName) free(cfilePathName); - if (cfilePath) free(cfilePath); - if (cfilter) free(cfilter); + // destroy + if (cfilePathName) free(cfilePathName); + if (cfilePath) free(cfilePath); + if (cfilter) free(cfilter); - IGFD_Selection_DestroyContent(&csel); - } - IGFD_CloseDialog(cfiledialog); + IGFD_Selection_DestroyContent(&csel); + } + IGFD_CloseDialog(cfiledialog); } // destroy ImGuiFileDialog IGFD_Destroy(cfiledialog); ------------------------------------------------------------------------------------------------------------------ -## Std::filesystem (c++17) can be used instead of dirent.h ------------------------------------------------------------------------------------------------------------------ - -you just need to uncomment that in the config file - -#define USE_STD_FILESYSTEM - -in this mode dirent is not more required - ----------------------------------------------------------------------------------------------------------------- ## How to Integrate ImGuiFileDialog in your project ----------------------------------------------------------------------------------------------------------------- ### ImGuiFileDialog require : -* dirent v1.23 (only when USE_STD_FILESYSTEM is not defined) (https://github.com/tronkko/dirent/tree/v1.23) lib, only for windows. Successfully tested with version v1.23 only +* dirent v1.23 (https://github.com/tronkko/dirent/tree/v1.23) lib, only for windows. Successfully tested with version v1.23 only * Dear ImGui (https://github.com/ocornut/imgui/tree/master) (with/without tables widgets) ### Customize ImGuiFileDialog : @@ -582,9 +572,9 @@ ImGuiFontStudio is using also ImGuiFileDialog. #define IMGUIFILEDIALOG_H #if defined(__WIN32__) || defined(_WIN32) - #ifndef WIN32 - #define WIN32 - #endif // WIN32 + #ifndef WIN32 + #define WIN32 + #endif // WIN32 #endif // defined(__WIN32__) || defined(_WIN32) #define IMGUIFILEDIALOG_VERSION "v0.6.4" @@ -599,43 +589,43 @@ ImGuiFontStudio is using also ImGuiFileDialog. typedef int IGFD_FileStyleFlags; // -> enum IGFD_FileStyleFlags_ enum IGFD_FileStyleFlags_ // by evaluation / priority order { - IGFD_FileStyle_None = 0, // define none style - IGFD_FileStyleByTypeFile = (1 << 0), // define style for all files - IGFD_FileStyleByTypeDir = (1 << 1), // define style for all dir - IGFD_FileStyleByTypeLink = (1 << 2), // define style for all link - IGFD_FileStyleByExtention = (1 << 3), // define style by extention, for files or links - IGFD_FileStyleByFullName = (1 << 4), // define style for particular file/dir/link full name (filename + extention) - IGFD_FileStyleByContainedInFullName = (1 << 5), // define style for file/dir/link when criteria is contained in full name + IGFD_FileStyle_None = 0, // define none style + IGFD_FileStyleByTypeFile = (1 << 0), // define style for all files + IGFD_FileStyleByTypeDir = (1 << 1), // define style for all dir + IGFD_FileStyleByTypeLink = (1 << 2), // define style for all link + IGFD_FileStyleByExtention = (1 << 3), // define style by extention, for files or links + IGFD_FileStyleByFullName = (1 << 4), // define style for particular file/dir/link full name (filename + extention) + IGFD_FileStyleByContainedInFullName = (1 << 5), // define style for file/dir/link when criteria is contained in full name }; typedef int ImGuiFileDialogFlags; // -> enum ImGuiFileDialogFlags_ enum ImGuiFileDialogFlags_ { - ImGuiFileDialogFlags_None = 0, - ImGuiFileDialogFlags_ConfirmOverwrite = (1 << 0), // show confirm to overwrite dialog - ImGuiFileDialogFlags_DontShowHiddenFiles = (1 << 1), // dont show hidden file (file starting with a .) - ImGuiFileDialogFlags_DisableCreateDirectoryButton = (1 << 2), // disable the create directory button - ImGuiFileDialogFlags_HideColumnType = (1 << 3), // hide column file type - ImGuiFileDialogFlags_HideColumnSize = (1 << 4), // hide column file size - ImGuiFileDialogFlags_HideColumnDate = (1 << 5), // hide column file date + ImGuiFileDialogFlags_None = 0, + ImGuiFileDialogFlags_ConfirmOverwrite = (1 << 0), // show confirm to overwrite dialog + ImGuiFileDialogFlags_DontShowHiddenFiles = (1 << 1), // dont show hidden file (file starting with a .) + ImGuiFileDialogFlags_DisableCreateDirectoryButton = (1 << 2), // disable the create directory button + ImGuiFileDialogFlags_HideColumnType = (1 << 3), // hide column file type + ImGuiFileDialogFlags_HideColumnSize = (1 << 4), // hide column file size + ImGuiFileDialogFlags_HideColumnDate = (1 << 5), // hide column file date #ifdef USE_THUMBNAILS - ImGuiFileDialogFlags_DisableThumbnailMode = (1 << 6), // disable the thumbnail mode + ImGuiFileDialogFlags_DisableThumbnailMode = (1 << 6), // disable the thumbnail mode #endif - ImGuiFileDialogFlags_Default = ImGuiFileDialogFlags_ConfirmOverwrite + ImGuiFileDialogFlags_Default = ImGuiFileDialogFlags_ConfirmOverwrite }; #ifdef USE_THUMBNAILS struct IGFD_Thumbnail_Info { - int isReadyToDisplay = 0; // ready to be rendered, so texture created - int isReadyToUpload = 0; // ready to upload to gpu - int isLoadingOrLoaded = 0; // was sent to laoding or loaded - void* textureID = 0; // 2d texture id (void* is like ImtextureID type) (GL, DX, VK, Etc..) - unsigned char* textureFileDatas = 0; // file texture datas, will be rested to null after gpu upload - int textureWidth = 0; // width of the texture to upload - int textureHeight = 0; // height of the texture to upload - int textureChannels = 0; // count channels of the texture to upload - void* userDatas = 0; // user datas + int isReadyToDisplay = 0; // ready to be rendered, so texture created + int isReadyToUpload = 0; // ready to upload to gpu + int isLoadingOrLoaded = 0; // was sent to laoding or loaded + void* textureID = 0; // 2d texture id (void* is like ImtextureID type) (GL, DX, VK, Etc..) + unsigned char* textureFileDatas = 0; // file texture datas, will be rested to null after gpu upload + int textureWidth = 0; // width of the texture to upload + int textureHeight = 0; // height of the texture to upload + int textureChannels = 0; // count channels of the texture to upload + void* userDatas = 0; // user datas }; #endif // USE_THUMBNAILS @@ -669,678 +659,680 @@ namespace IGFD #define MAX_PATH_BUFFER_SIZE 1024 #endif // MAX_PATH_BUFFER_SIZE - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class FileDialogInternal; + class FileDialogInternal; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class SearchManager - { - public: - std::string puSearchTag; - char puSearchBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; - bool puSearchInputIsActive = false; + class SearchManager + { + public: + std::string puSearchTag; + char puSearchBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; + bool puSearchInputIsActive = false; - public: - void Clear(); // clear datas - void DrawSearchBar(FileDialogInternal& vFileDialogInternal); // draw the search bar - }; + public: + void Clear(); // clear datas + void DrawSearchBar(FileDialogInternal& vFileDialogInternal); // draw the search bar + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class Utils - { - public: - struct PathStruct - { - std::string path; - std::string name; - std::string ext; - bool isOk = false; - }; + class Utils + { + public: + struct PathStruct + { + std::string path; + std::string name; + std::string ext; + bool isOk = false; + }; - public: - static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f); - static bool ReplaceString(std::string& str, const std::string& oldStr, const std::string& newStr); - static bool IsDirectoryExist(const std::string& name); - static bool CreateDirectoryIfNotExist(const std::string& name); - static PathStruct ParsePathFileName(const std::string& vPathFileName); - static void AppendToBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr); - static void ResetBuffer(char* vBuffer); - static void SetBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr); + public: + static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f); + static bool ReplaceString(std::string& str, const std::string& oldStr, const std::string& newStr); + static bool IsDirectoryExist(const std::string& name); + static bool CreateDirectoryIfNotExist(const std::string& name); + static PathStruct ParsePathFileName(const std::string& vPathFileName); + static void AppendToBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr); + static void ResetBuffer(char* vBuffer); + static void SetBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr); #ifdef WIN32 - static bool WReplaceString(std::wstring& str, const std::wstring& oldStr, const std::wstring& newStr); - static std::vector WSplitStringToVector(const std::wstring& text, char delimiter, bool pushEmpty); - static std::string wstring_to_string(const std::wstring& wstr); - static std::wstring string_to_wstring(const std::string& mbstr); + static bool WReplaceString(std::wstring& str, const std::wstring& oldStr, const std::wstring& newStr); + static std::vector WSplitStringToVector(const std::wstring& text, char delimiter, bool pushEmpty); + static std::string wstring_to_string(const std::wstring& wstr); + static std::wstring string_to_wstring(const std::string& mbstr); #endif - static std::vector SplitStringToVector(const std::string& text, char delimiter, bool pushEmpty); - static std::vector GetDrivesList(); - }; + static std::vector SplitStringToVector(const std::string& text, char delimiter, bool pushEmpty); + static std::vector GetDrivesList(); + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class FileStyle - { - public: - ImVec4 color = ImVec4(0, 0, 0, 0); - std::string icon; - ImFont* font = nullptr; - IGFD_FileStyleFlags flags = 0; + class FileStyle + { + public: + ImVec4 color = ImVec4(0, 0, 0, 0); + std::string icon; + ImFont* font = nullptr; + IGFD_FileStyleFlags flags = 0; - public: - FileStyle(); - FileStyle(const FileStyle& vStyle); - FileStyle(const ImVec4& vColor, const std::string& vIcon = "", ImFont* vFont = nullptr); - }; + public: + FileStyle(); + FileStyle(const FileStyle& vStyle); + FileStyle(const ImVec4& vColor, const std::string& vIcon = "", ImFont* vFont = nullptr); + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class FileInfos; - class FilterManager - { - public: - class FilterInfos - { - public: - std::string filter; - std::set collectionfilters; + class FileInfos; + class FilterManager + { + public: + class FilterInfos + { + public: + std::string filter; + std::set collectionfilters; - public: - void clear(); // clear the datas - bool empty() const; // is filter empty - bool exist(const std::string& vFilter) const; // is filter exist - }; + public: + void clear(); // clear the datas + bool empty() const; // is filter empty + bool exist(const std::string& vFilter) const; // is filter exist + }; - private: - std::vector prParsedFilters; - std::unordered_map>> prFilesStyle; // file infos for file extention only - FilterInfos prSelectedFilter; + private: + std::vector prParsedFilters; + std::unordered_map>> prFilesStyle; // file infos for file extention only + FilterInfos prSelectedFilter; - public: - std::string puDLGFilters; - std::string puDLGdefaultExt; + public: + std::string puDLGFilters; + std::string puDLGdefaultExt; - public: - void ParseFilters(const char* vFilters); // Parse filter syntax, detect and parse filter collection - void SetSelectedFilterWithExt(const std::string& vFilter); // Select filter - - bool prFillFileStyle(std::shared_ptr vFileInfos) const; // fill with the good style - - void SetFileStyle( - const IGFD_FileStyleFlags& vFlags, - const char* vCriteria, - const FileStyle& vInfos); // Set FileStyle - void SetFileStyle( - const IGFD_FileStyleFlags& vFlags, - const char* vCriteria, - const ImVec4& vColor, - const std::string& vIcon, - ImFont* vFont); // link file style to Color and Icon and Font - bool GetFileStyle( - const IGFD_FileStyleFlags& vFlags, - const std::string& vCriteria, - ImVec4* vOutColor, - std::string* vOutIcon, - ImFont** vOutFont); // Get Color and Icon for Filter - void ClearFilesStyle(); // clear prFileStyle + public: + void ParseFilters(const char* vFilters); // Parse filter syntax, detect and parse filter collection + void SetSelectedFilterWithExt(const std::string& vFilter); // Select filter + + bool prFillFileStyle(std::shared_ptr vFileInfos) const; // fill with the good style + + void SetFileStyle( + const IGFD_FileStyleFlags& vFlags, + const char* vCriteria, + const FileStyle& vInfos); // Set FileStyle + void SetFileStyle( + const IGFD_FileStyleFlags& vFlags, + const char* vCriteria, + const ImVec4& vColor, + const std::string& vIcon, + ImFont* vFont); // link file style to Color and Icon and Font + bool GetFileStyle( + const IGFD_FileStyleFlags& vFlags, + const std::string& vCriteria, + ImVec4* vOutColor, + std::string* vOutIcon, + ImFont** vOutFont); // Get Color and Icon for Filter + void ClearFilesStyle(); // clear prFileStyle - bool IsCoveredByFilters(const std::string& vTag) const; // check if current file extention (vTag) is covered by current filter - bool DrawFilterComboBox(FileDialogInternal& vFileDialogInternal); // draw the filter combobox - FilterInfos GetSelectedFilter(); // get the current selected filter - std::string ReplaceExtentionWithCurrentFilter(const std::string& vFile) const; // replace the extention of the current file by the selected filter - void SetDefaultFilterIfNotDefined(); // define the first filter if no filter is selected - }; + bool IsCoveredByFilters(const std::string& vTag) const; // check if current file extention (vTag) is covered by current filter + bool DrawFilterComboBox(FileDialogInternal& vFileDialogInternal); // draw the filter combobox + FilterInfos GetSelectedFilter(); // get the current selected filter + std::string ReplaceExtentionWithCurrentFilter(const std::string& vFile) const; // replace the extention of the current file by the selected filter + void SetDefaultFilterIfNotDefined(); // define the first filter if no filter is selected + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class FileInfos - { - public: - char fileType = ' '; // dirent fileType (f:file, d:directory, l:link) - std::string filePath; // path of the file - std::string fileNameExt; // filename of the file (file name + extention) (but no path) - std::string fileNameExt_optimized; // optimized for search => insensitivecase - std::string fileExt; // extention of the file - size_t fileSize = 0; // for sorting operations - std::string formatedFileSize; // file size formated (10 o, 10 ko, 10 mo, 10 go) - std::string fileModifDate; // file user defined format of the date (data + time by default) - std::shared_ptr fileStyle = nullptr; // style of the file + class FileInfos + { + public: + char fileType = ' '; // dirent fileType (f:file, d:directory, l:link) + std::string filePath; // path of the file + std::string fileNameExt; // filename of the file (file name + extention) (but no path) + std::string fileNameExt_optimized; // optimized for search => insensitivecase + std::string fileExt; // extention of the file + size_t fileSize = 0; // for sorting operations + std::string formatedFileSize; // file size formated (10 o, 10 ko, 10 mo, 10 go) + std::string fileModifDate; // file user defined format of the date (data + time by default) + std::shared_ptr fileStyle = nullptr; // style of the file #ifdef USE_THUMBNAILS - IGFD_Thumbnail_Info thumbnailInfo; // structre for the display for image file tetxure + IGFD_Thumbnail_Info thumbnailInfo; // structre for the display for image file tetxure #endif // USE_THUMBNAILS - public: - bool IsTagFound(const std::string& vTag) const; - }; + public: + bool IsTagFound(const std::string& vTag) const; + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class FileManager - { - public: // types - enum class SortingFieldEnum // sorting for filetering of the file lsit - { - FIELD_NONE = 0, // no sorting preference, result indetermined haha.. - FIELD_FILENAME, // sorted by filename - FIELD_TYPE, // sorted by filetype - FIELD_SIZE, // sorted by filesize (formated file size) - FIELD_DATE, // sorted by filedate + class FileManager + { + public: // types + enum class SortingFieldEnum // sorting for filetering of the file lsit + { + FIELD_NONE = 0, // no sorting preference, result indetermined haha.. + FIELD_FILENAME, // sorted by filename + FIELD_TYPE, // sorted by filetype + FIELD_SIZE, // sorted by filesize (formated file size) + FIELD_DATE, // sorted by filedate #ifdef USE_THUMBNAILS - FIELD_THUMBNAILS, // sorted by thumbnails (comparaison by width then by height) + FIELD_THUMBNAILS, // sorted by thumbnails (comparaison by width then by height) #endif // USE_THUMBNAILS - }; + }; - private: - std::string prCurrentPath; // current path (to be decomposed in prCurrentPathDecomposition - std::vector prCurrentPathDecomposition; // part words - std::vector> prFileList; // base container - std::vector> prFilteredFileList; // filtered container (search, sorting, etc..) - std::string prLastSelectedFileName; // for shift multi selection - std::set prSelectedFileNames; // the user selection of FilePathNames - bool prCreateDirectoryMode = false; // for create directory widget + private: + std::string prCurrentPath; // current path (to be decomposed in prCurrentPathDecomposition + std::vector prCurrentPathDecomposition; // part words + std::vector> prFileList; // base container + std::vector> prFilteredFileList; // filtered container (search, sorting, etc..) + std::string prLastSelectedFileName; // for shift multi selection + std::set prSelectedFileNames; // the user selection of FilePathNames + bool prCreateDirectoryMode = false; // for create directory widget - public: - char puVariadicBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // called by prSelectableItem - bool puInputPathActivated = false; // show input for path edition - bool puDrivesClicked = false; // event when a drive button is clicked - bool puPathClicked = false; // event when a path button was clicked - char puInputPathBuffer[MAX_PATH_BUFFER_SIZE] = ""; // input path buffer for imgui widget input text (displayed in palce of composer) - char puFileNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // file name buffer in footer for imgui widget input text - char puDirectoryNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // directory name buffer in footer for imgui widget input text (when is directory mode) - std::string puHeaderFileName; // detail view name of column file - std::string puHeaderFileType; // detail view name of column type - std::string puHeaderFileSize; // detail view name of column size - std::string puHeaderFileDate; // detail view name of column date + time + public: + char puVariadicBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // called by prSelectableItem + bool puInputPathActivated = false; // show input for path edition + bool puDrivesClicked = false; // event when a drive button is clicked + bool puPathClicked = false; // event when a path button was clicked + char puInputPathBuffer[MAX_PATH_BUFFER_SIZE] = ""; // input path buffer for imgui widget input text (displayed in palce of composer) + char puFileNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // file name buffer in footer for imgui widget input text + char puDirectoryNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // directory name buffer in footer for imgui widget input text (when is directory mode) + std::string puHeaderFileName; // detail view name of column file + std::string puHeaderFileType; // detail view name of column type + std::string puHeaderFileSize; // detail view name of column size + std::string puHeaderFileDate; // detail view name of column date + time #ifdef USE_THUMBNAILS - std::string puHeaderFileThumbnails; // detail view name of column thumbnails - bool puSortingDirection[5]; // detail view // true => Descending, false => Ascending + std::string puHeaderFileThumbnails; // detail view name of column thumbnails + bool puSortingDirection[5]; // detail view // true => Descending, false => Ascending #else - bool puSortingDirection[4]; // detail view // true => Descending, false => Ascending + bool puSortingDirection[4]; // detail view // true => Descending, false => Ascending #endif - SortingFieldEnum puSortingField = SortingFieldEnum::FIELD_FILENAME; // detail view sorting column - bool puShowDrives = false; // drives are shown (only on os windows) + SortingFieldEnum puSortingField = SortingFieldEnum::FIELD_FILENAME; // detail view sorting column + bool puShowDrives = false; // drives are shown (only on os windows) bool fileListActuallyEmpty = false; - std::string puDLGpath; // base path set by user when OpenDialog/OpenModal was called - std::string puDLGDefaultFileName; // base default file path name set by user when OpenDialog/OpenModal was called - size_t puDLGcountSelectionMax = 1U; // 0 for infinite // base max selection count set by user when OpenDialog/OpenModal was called - bool puDLGDirectoryMode = false; // is directory mode (defiend like : puDLGDirectoryMode = (filters.empty())) + std::string puDLGpath; // base path set by user when OpenDialog/OpenModal was called + std::string puError; // last error + std::string puDLGDefaultFileName; // base default file path name set by user when OpenDialog/OpenModal was called + size_t puDLGcountSelectionMax = 1U; // 0 for infinite // base max selection count set by user when OpenDialog/OpenModal was called + bool puDLGDirectoryMode = false; // is directory mode (defiend like : puDLGDirectoryMode = (filters.empty())) - std::string puFsRoot; + std::string puFsRoot; - private: - static std::string prRoundNumber(double vvalue, int n); // custom rounding number - static std::string prFormatFileSize(size_t vByteSize); // format file size field - static std::string prOptimizeFilenameForSearchOperations(const std::string& vFileNameExt); // turn all text in lower case for search facilitie - static void prCompleteFileInfos(const std::shared_ptr& FileInfos); // set time and date infos of a file (detail view mode) - void prRemoveFileNameInSelection(const std::string& vFileName); // selection : remove a file name - void prAddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName); // selection : add a file name - void AddFile(const FileDialogInternal& vFileDialogInternal, - const std::string& vPath, const std::string& vFileName, const char& vFileType); // add file called by scandir + private: + static std::string prRoundNumber(double vvalue, int n); // custom rounding number + static std::string prFormatFileSize(size_t vByteSize); // format file size field + static std::string prOptimizeFilenameForSearchOperations(const std::string& vFileNameExt); // turn all text in lower case for search facilitie + static void prCompleteFileInfos(const std::shared_ptr& FileInfos); // set time and date infos of a file (detail view mode) + void prRemoveFileNameInSelection(const std::string& vFileName); // selection : remove a file name + void prAddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName); // selection : add a file name + void AddFile(const FileDialogInternal& vFileDialogInternal, + const std::string& vPath, const std::string& vFileName, const char& vFileType); // add file called by scandir - public: - FileManager(); - bool IsComposerEmpty(); - size_t GetComposerSize(); - bool IsFileListEmpty(); - bool IsFilteredListEmpty(); - size_t GetFullFileListSize(); - std::shared_ptr GetFullFileAt(size_t vIdx); - size_t GetFilteredListSize(); - std::shared_ptr GetFilteredFileAt(size_t vIdx); - bool IsFileNameSelected(const std::string& vFileName); - std::string GetBack(); - void ClearComposer(); - void ClearFileLists(); // clear file list, will destroy thumbnail textures - void ClearAll(); - void ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal); - void OpenCurrentPath(const FileDialogInternal& vFileDialogInternal); // set the path of the dialog, will launch the directory scan for populate the file listview - void SortFields(const FileDialogInternal& vFileDialogInternal, - const SortingFieldEnum& vSortingField, const bool vCanChangeOrder); // will sort a column - bool GetDrives(); // list drives on windows platform - bool CreateDir(const std::string& vPath); // create a directory on the file system - void ComposeNewPath(std::vector::iterator vIter); // compose a path from the compose path widget - bool SetPathOnParentDirectoryIfAny(); // compose paht on parent directory - std::string GetCurrentPath(); // get the current path - void SetCurrentPath(const std::string& vCurrentPath); // set the current path - static bool IsFileExist(const std::string& vFile); - void SetDefaultFileName(const std::string& vFileName); - bool SelectDirectory(const std::shared_ptr& vInfos); // enter directory - void SelectFileName(const FileDialogInternal& vFileDialogInternal, - const std::shared_ptr& vInfos); // select filename - - //depend of dirent.h - void SetCurrentDir(const std::string& vPath); // define current directory for scan - void ScanDir(const FileDialogInternal& vFileDialogInternal, const std::string& vPath); // scan the directory for retrieve the file list + public: + FileManager(); + bool IsComposerEmpty(); + size_t GetComposerSize(); + bool IsFileListEmpty(); + bool IsFilteredListEmpty(); + size_t GetFullFileListSize(); + std::shared_ptr GetFullFileAt(size_t vIdx); + size_t GetFilteredListSize(); + std::shared_ptr GetFilteredFileAt(size_t vIdx); + bool IsFileNameSelected(const std::string& vFileName); + std::string GetBack(); + void ClearComposer(); + void ClearFileLists(); // clear file list, will destroy thumbnail textures + void ClearAll(); + void ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal); + void OpenCurrentPath(const FileDialogInternal& vFileDialogInternal); // set the path of the dialog, will launch the directory scan for populate the file listview + void SortFields(const FileDialogInternal& vFileDialogInternal, + const SortingFieldEnum& vSortingField, const bool vCanChangeOrder); // will sort a column + bool GetDrives(); // list drives on windows platform + bool CreateDir(const std::string& vPath); // create a directory on the file system + void ComposeNewPath(std::vector::iterator vIter); // compose a path from the compose path widget + bool SetPathOnParentDirectoryIfAny(); // compose paht on parent directory + std::string GetCurrentPath(); // get the current path + void SetCurrentPath(const std::string& vCurrentPath); // set the current path + static bool IsFileExist(const std::string& vFile); + void SetDefaultFileName(const std::string& vFileName); + bool SelectDirectory(const std::shared_ptr& vInfos); // enter directory + void SelectFileName(const FileDialogInternal& vFileDialogInternal, + const std::shared_ptr& vInfos); // select filename + + //depend of dirent.h + void SetCurrentDir(const std::string& vPath); // define current directory for scan + void ScanDir(const FileDialogInternal& vFileDialogInternal, const std::string& vPath); // scan the directory for retrieve the file list - public: - std::string GetResultingPath(); - std::string GetResultingFileName(FileDialogInternal& vFileDialogInternal); - std::string GetResultingFilePathName(FileDialogInternal& vFileDialogInternal); - std::map GetResultingSelection(); + public: + std::string GetResultingPath(); + std::string GetResultingFileName(FileDialogInternal& vFileDialogInternal); + std::string GetResultingFilePathName(FileDialogInternal& vFileDialogInternal); + std::map GetResultingSelection(); - public: - void DrawDirectoryCreation(const FileDialogInternal& vFileDialogInternal); // draw directory creation widget - void DrawPathComposer(const FileDialogInternal& vFileDialogInternal); // draw path composer widget - }; + public: + void DrawDirectoryCreation(const FileDialogInternal& vFileDialogInternal); // draw directory creation widget + void DrawPathComposer(const FileDialogInternal& vFileDialogInternal); // draw path composer widget + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef USE_THUMBNAILS - typedef std::function CreateThumbnailFun; // texture 2d creation function binding - typedef std::function DestroyThumbnailFun; // texture 2d destroy function binding + typedef std::function CreateThumbnailFun; // texture 2d creation function binding + typedef std::function DestroyThumbnailFun; // texture 2d destroy function binding #endif - class ThumbnailFeature - { - protected: - ThumbnailFeature(); - ~ThumbnailFeature(); + class ThumbnailFeature + { + protected: + ThumbnailFeature(); + ~ThumbnailFeature(); - void NewThumbnailFrame(FileDialogInternal& vFileDialogInternal); - void EndThumbnailFrame(FileDialogInternal& vFileDialogInternal); - void QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal); + void NewThumbnailFrame(FileDialogInternal& vFileDialogInternal); + void EndThumbnailFrame(FileDialogInternal& vFileDialogInternal); + void QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal); #ifdef USE_THUMBNAILS - protected: - enum class DisplayModeEnum - { - FILE_LIST = 0, - THUMBNAILS_LIST, - THUMBNAILS_GRID - }; + protected: + enum class DisplayModeEnum + { + FILE_LIST = 0, + THUMBNAILS_LIST, + THUMBNAILS_GRID + }; - private: - uint32_t prCountFiles = 0U; - bool prIsWorking = false; - std::shared_ptr prThumbnailGenerationThread = nullptr; - std::list> prThumbnailFileDatasToGet; // base container - std::mutex prThumbnailFileDatasToGetMutex; - std::list> prThumbnailToCreate; // base container - std::mutex prThumbnailToCreateMutex; - std::list prThumbnailToDestroy; // base container - std::mutex prThumbnailToDestroyMutex; + private: + uint32_t prCountFiles = 0U; + bool prIsWorking = false; + std::shared_ptr prThumbnailGenerationThread = nullptr; + std::list> prThumbnailFileDatasToGet; // base container + std::mutex prThumbnailFileDatasToGetMutex; + std::list> prThumbnailToCreate; // base container + std::mutex prThumbnailToCreateMutex; + std::list prThumbnailToDestroy; // base container + std::mutex prThumbnailToDestroyMutex; - CreateThumbnailFun prCreateThumbnailFun = nullptr; - DestroyThumbnailFun prDestroyThumbnailFun = nullptr; + CreateThumbnailFun prCreateThumbnailFun = nullptr; + DestroyThumbnailFun prDestroyThumbnailFun = nullptr; - protected: - DisplayModeEnum prDisplayMode = DisplayModeEnum::FILE_LIST; + protected: + DisplayModeEnum prDisplayMode = DisplayModeEnum::FILE_LIST; - protected: - // will be call in cpu zone (imgui computations, will call a texture file retrieval thread) - void prStartThumbnailFileDatasExtraction(); // start the thread who will get byte buffer from image files - bool prStopThumbnailFileDatasExtraction(); // stop the thread who will get byte buffer from image files - void prThreadThumbnailFileDatasExtractionFunc(); // the thread who will get byte buffer from image files - void prDrawThumbnailGenerationProgress(); // a little progressbar who will display the texture gen status - void prAddThumbnailToLoad(const std::shared_ptr& vFileInfos); // add texture to load in the thread - void prAddThumbnailToCreate(const std::shared_ptr& vFileInfos); - void prAddThumbnailToDestroy(const IGFD_Thumbnail_Info& vIGFD_Thumbnail_Info); - void prDrawDisplayModeToolBar(); // draw display mode toolbar (file list, thumbnails list, small thumbnails grid, big thumbnails grid) - void prClearThumbnails(FileDialogInternal& vFileDialogInternal); + protected: + // will be call in cpu zone (imgui computations, will call a texture file retrieval thread) + void prStartThumbnailFileDatasExtraction(); // start the thread who will get byte buffer from image files + bool prStopThumbnailFileDatasExtraction(); // stop the thread who will get byte buffer from image files + void prThreadThumbnailFileDatasExtractionFunc(); // the thread who will get byte buffer from image files + void prDrawThumbnailGenerationProgress(); // a little progressbar who will display the texture gen status + void prAddThumbnailToLoad(const std::shared_ptr& vFileInfos); // add texture to load in the thread + void prAddThumbnailToCreate(const std::shared_ptr& vFileInfos); + void prAddThumbnailToDestroy(const IGFD_Thumbnail_Info& vIGFD_Thumbnail_Info); + void prDrawDisplayModeToolBar(); // draw display mode toolbar (file list, thumbnails list, small thumbnails grid, big thumbnails grid) + void prClearThumbnails(FileDialogInternal& vFileDialogInternal); - public: - void SetCreateThumbnailCallback(const CreateThumbnailFun& vCreateThumbnailFun); - void SetDestroyThumbnailCallback(const DestroyThumbnailFun& vCreateThumbnailFun); - - // must be call in gpu zone (rendering, possibly one rendering thread) - void ManageGPUThumbnails(); // in gpu rendering zone, whill create or destroy texture + public: + void SetCreateThumbnailCallback(const CreateThumbnailFun& vCreateThumbnailFun); + void SetDestroyThumbnailCallback(const DestroyThumbnailFun& vCreateThumbnailFun); + + // must be call in gpu zone (rendering, possibly one rendering thread) + void ManageGPUThumbnails(); // in gpu rendering zone, whill create or destroy texture #endif - }; + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class BookMarkFeature - { - protected: - BookMarkFeature(); + class BookMarkFeature + { + protected: + BookMarkFeature(); #ifdef USE_BOOKMARK - private: - struct BookmarkStruct - { - std::string name; // name of the bookmark - - // todo: the path could be relative, better if the app is movedn but bookmarked path can be outside of the app - std::string path; // absolute path of the bookmarked directory - }; + private: + struct BookmarkStruct + { + std::string name; // name of the bookmark + + // todo: the path could be relative, better if the app is movedn but bookmarked path can be outside of the app + std::string path; // absolute path of the bookmarked directory + }; - private: - ImGuiListClipper prBookmarkClipper; - std::vector prBookmarks; - char prBookmarkEditBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; + private: + ImGuiListClipper prBookmarkClipper; + std::vector prBookmarks; + char prBookmarkEditBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; - protected: - float prBookmarkWidth = 200.0f; - bool prBookmarkPaneShown = false; - - protected: - void prDrawBookmarkButton(); // draw bookmark button - bool prDrawBookmarkPane(FileDialogInternal& vFileDialogInternal, const ImVec2& vSize); // draw bookmark Pane + protected: + float prBookmarkWidth = 200.0f; + bool prBookmarkPaneShown = false; + + protected: + void prDrawBookmarkButton(); // draw bookmark button + bool prDrawBookmarkPane(FileDialogInternal& vFileDialogInternal, const ImVec2& vSize); // draw bookmark Pane - public: - std::string SerializeBookmarks(); // serialize bookmarks : return bookmark buffer to save in a file - void DeserializeBookmarks( // deserialize bookmarks : load bookmark buffer to load in the dialog (saved from previous use with SerializeBookmarks()) - const std::string& vBookmarks); // bookmark buffer to load + public: + std::string SerializeBookmarks(); // serialize bookmarks : return bookmark buffer to save in a file + void DeserializeBookmarks( // deserialize bookmarks : load bookmark buffer to load in the dialog (saved from previous use with SerializeBookmarks()) + const std::string& vBookmarks); // bookmark buffer to load #endif // USE_BOOKMARK - }; + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // file localization by input chat // widget flashing - class KeyExplorerFeature - { - protected: - KeyExplorerFeature(); + // file localization by input chat // widget flashing + class KeyExplorerFeature + { + protected: + KeyExplorerFeature(); #ifdef USE_EXPLORATION_BY_KEYS - private: - size_t prFlashedItem = 0; // flash when select by char - float prFlashAlpha = 0.0f; // flash when select by char - float prFlashAlphaAttenInSecs = 1.0f; // fps display dependant - size_t prLocateFileByInputChar_lastFileIdx = 0; - ImWchar prLocateFileByInputChar_lastChar = 0; - int prLocateFileByInputChar_InputQueueCharactersSize = 0; - bool prLocateFileByInputChar_lastFound = false; + private: + size_t prFlashedItem = 0; // flash when select by char + float prFlashAlpha = 0.0f; // flash when select by char + float prFlashAlphaAttenInSecs = 1.0f; // fps display dependant + size_t prLocateFileByInputChar_lastFileIdx = 0; + ImWchar prLocateFileByInputChar_lastChar = 0; + int prLocateFileByInputChar_InputQueueCharactersSize = 0; + bool prLocateFileByInputChar_lastFound = false; - protected: - void prLocateByInputKey(FileDialogInternal& vFileDialogInternal); // select a file line in listview according to char key - bool prLocateItem_Loop(FileDialogInternal& vFileDialogInternal, ImWchar vC); // restrat for start of list view if not found a corresponding file - void prExploreWithkeys(FileDialogInternal& vFileDialogInternal, ImGuiID vListViewID); // select file/directory line in listview accroding to up/down enter/backspace keys - static bool prFlashableSelectable( // custom flashing selectable widgets, for flash the selected line in a short time - const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, - bool vFlashing = false, const ImVec2& size = ImVec2(0, 0)); - void prStartFlashItem(size_t vIdx); // define than an item must be flashed - bool prBeginFlashItem(size_t vIdx); // start the flashing of a line in lsit view - static void prEndFlashItem(); // end the fleshing accrdoin to var prFlashAlphaAttenInSecs + protected: + void prLocateByInputKey(FileDialogInternal& vFileDialogInternal); // select a file line in listview according to char key + bool prLocateItem_Loop(FileDialogInternal& vFileDialogInternal, ImWchar vC); // restrat for start of list view if not found a corresponding file + void prExploreWithkeys(FileDialogInternal& vFileDialogInternal, ImGuiID vListViewID); // select file/directory line in listview accroding to up/down enter/backspace keys + static bool prFlashableSelectable( // custom flashing selectable widgets, for flash the selected line in a short time + const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, + bool vFlashing = false, const ImVec2& size = ImVec2(0, 0)); + void prStartFlashItem(size_t vIdx); // define than an item must be flashed + bool prBeginFlashItem(size_t vIdx); // start the flashing of a line in lsit view + static void prEndFlashItem(); // end the fleshing accrdoin to var prFlashAlphaAttenInSecs - public: - void SetFlashingAttenuationInSeconds( // set the flashing time of the line in file list when use exploration keys - float vAttenValue); // set the attenuation (from flashed to not flashed) in seconds + public: + void SetFlashingAttenuationInSeconds( // set the flashing time of the line in file list when use exploration keys + float vAttenValue); // set the attenuation (from flashed to not flashed) in seconds #endif // USE_EXPLORATION_BY_KEYS - }; + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - typedef void* UserDatas; - typedef std::function PaneFun; // side pane function binding + typedef void* UserDatas; + typedef std::function PaneFun; // side pane function binding typedef std::function SelectFun; // click on file function binding - class FileDialogInternal - { - public: - FileManager puFileManager; - FilterManager puFilterManager; - SearchManager puSearchManager; + class FileDialogInternal + { + public: + FileManager puFileManager; + FilterManager puFilterManager; + SearchManager puSearchManager; - public: - std::string puName; - bool puShowDialog = false; - ImVec2 puDialogCenterPos = ImVec2(0, 0); // center pos for display the confirm overwrite dialog - int puLastImGuiFrameCount = 0; // to be sure than only one dialog displayed per frame - float puFooterHeight = 0.0f; - bool puCanWeContinue = true; // events - bool puOkResultToConfirm = false; // to confim if ok for OverWrite - bool puIsOk = false; - bool puFileInputIsActive = false; // when input text for file or directory is active - bool puFileListViewIsActive = false; // when list view is active - std::string puDLGkey; - std::string puDLGtitle; - ImGuiFileDialogFlags puDLGflags = ImGuiFileDialogFlags_None; - UserDatas puDLGuserDatas = nullptr; - PaneFun puDLGoptionsPane = nullptr; + public: + std::string puName; + bool puShowDialog = false; + ImVec2 puDialogCenterPos = ImVec2(0, 0); // center pos for display the confirm overwrite dialog + int puLastImGuiFrameCount = 0; // to be sure than only one dialog displayed per frame + float puFooterHeight = 0.0f; + bool puCanWeContinue = true; // events + bool puOkResultToConfirm = false; // to confim if ok for OverWrite + bool puIsOk = false; + bool puFileInputIsActive = false; // when input text for file or directory is active + bool puFileListViewIsActive = false; // when list view is active + std::string puDLGkey; + std::string puDLGtitle; + ImGuiFileDialogFlags puDLGflags = ImGuiFileDialogFlags_None; + UserDatas puDLGuserDatas = nullptr; + PaneFun puDLGoptionsPane = nullptr; SelectFun puDLGselFun = nullptr; - float puDLGoptionsPaneWidth = 0.0f; - bool puDLGmodal = false; - bool puNeedToExitDialog = false; + float puDLGoptionsPaneWidth = 0.0f; + bool puDLGmodal = false; + bool puNeedToExitDialog = false; - bool puUseCustomLocale = false; - int puLocaleCategory = LC_ALL; // locale category to use - std::string puLocaleBegin; // the locale who will be applied at start of the display dialog - std::string puLocaleEnd; // the locale who will be applaied at end of the display dialog + bool puUseCustomLocale = false; + int puLocaleCategory = LC_ALL; // locale category to use + std::string puLocaleBegin; // the locale who will be applied at start of the display dialog + std::string puLocaleEnd; // the locale who will be applaied at end of the display dialog - public: - void NewFrame(); // new frame, so maybe neded to do somethings, like reset events - void EndFrame(); // end frame, so maybe neded to do somethings fater all - void ResetForNewDialog(); // reset what is needed to reset for the openging of a new dialog - }; + public: + void NewFrame(); // new frame, so maybe neded to do somethings, like reset events + void EndFrame(); // end frame, so maybe neded to do somethings fater all + void ResetForNewDialog(); // reset what is needed to reset for the openging of a new dialog + }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - class FileDialog : - public BookMarkFeature, - public KeyExplorerFeature, - public ThumbnailFeature - { - private: - FileDialogInternal prFileDialogInternal; - ImGuiListClipper prFileListClipper; + class FileDialog : + public BookMarkFeature, + public KeyExplorerFeature, + public ThumbnailFeature + { + private: + FileDialogInternal prFileDialogInternal; + ImGuiListClipper prFileListClipper; - public: - bool puAnyWindowsHovered = false; // not remember why haha :) todo : to check if we can remove + public: + bool puAnyWindowsHovered = false; // not remember why haha :) todo : to check if we can remove double DpiScale; bool singleClickSel; bool mobileMode; + std::string homePath; - public: - static FileDialog* Instance() // Singleton for easier accces form anywhere but only one dialog at a time - { - static FileDialog _instance; - return &_instance; - } + public: + static FileDialog* Instance() // Singleton for easier accces form anywhere but only one dialog at a time + { + static FileDialog _instance; + return &_instance; + } - public: - FileDialog(); // ImGuiFileDialog Constructor. can be used for have many dialog at same tiem (not possible with singleton) - virtual ~FileDialog(); // ImGuiFileDialog Destructor + public: + FileDialog(); // ImGuiFileDialog Constructor. can be used for have many dialog at same tiem (not possible with singleton) + virtual ~FileDialog(); // ImGuiFileDialog Destructor - // standard dialog - void OpenDialog( // open simple dialog (path and fileName can be specified) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vPath, // path - const std::string& vFileName, // defaut file name - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + // standard dialog + void OpenDialog( // open simple dialog (path and fileName can be specified) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vPath, // path + const std::string& vFileName, // defaut file name + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - void OpenDialog( // open simple dialog (path and filename are obtained from filePathName) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + void OpenDialog( // open simple dialog (path and filename are obtained from filePathName) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - // with pane - void OpenDialog( // open dialog with custom right pane (path and fileName can be specified) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vPath, // path - const std::string& vFileName, // defaut file name - const PaneFun& vSidePane, // side pane - const float& vSidePaneWidth = 250.0f, // side pane width - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + // with pane + void OpenDialog( // open dialog with custom right pane (path and fileName can be specified) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vPath, // path + const std::string& vFileName, // defaut file name + const PaneFun& vSidePane, // side pane + const float& vSidePaneWidth = 250.0f, // side pane width + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - void OpenDialog( // open dialog with custom right pane (path and filename are obtained from filePathName) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) - const PaneFun& vSidePane, // side pane - const float& vSidePaneWidth = 250.0f, // side pane width - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + void OpenDialog( // open dialog with custom right pane (path and filename are obtained from filePathName) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) + const PaneFun& vSidePane, // side pane + const float& vSidePaneWidth = 250.0f, // side pane width + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - // modal dialog - void OpenModal( // open simple modal (path and fileName can be specified) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vPath, // path - const std::string& vFileName, // defaut file name - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + // modal dialog + void OpenModal( // open simple modal (path and fileName can be specified) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vPath, // path + const std::string& vFileName, // defaut file name + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - void OpenModal( // open simple modal (path and fielname are obtained from filePathName) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + void OpenModal( // open simple modal (path and fielname are obtained from filePathName) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - // with pane - void OpenModal( // open modal with custom right pane (path and filename are obtained from filePathName) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vPath, // path - const std::string& vFileName, // defaut file name - const PaneFun& vSidePane, // side pane - const float& vSidePaneWidth = 250.0f, // side pane width - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + // with pane + void OpenModal( // open modal with custom right pane (path and filename are obtained from filePathName) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vPath, // path + const std::string& vFileName, // defaut file name + const PaneFun& vSidePane, // side pane + const float& vSidePaneWidth = 250.0f, // side pane width + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - void OpenModal( // open modal with custom right pane (path and fielname are obtained from filePathName) - const std::string& vKey, // key dialog - const std::string& vTitle, // title - const char* vFilters, // filters - const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) - const PaneFun& vSidePane, // side pane - const float& vSidePaneWidth = 250.0f, // side pane width - const int& vCountSelectionMax = 1, // count selection max - UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags - SelectFun vSelectFun = nullptr); // function to be called on file click + void OpenModal( // open modal with custom right pane (path and fielname are obtained from filePathName) + const std::string& vKey, // key dialog + const std::string& vTitle, // title + const char* vFilters, // filters + const std::string& vFilePathName, // file path name (will be decompsoed in path and fileName) + const PaneFun& vSidePane, // side pane + const float& vSidePaneWidth = 250.0f, // side pane width + const int& vCountSelectionMax = 1, // count selection max + UserDatas vUserDatas = nullptr, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags = 0, // ImGuiFileDialogFlags + SelectFun vSelectFun = nullptr); // function to be called on file click - // Display / Close dialog form - bool Display( // Display the dialog. return true if a result was obtained (Ok or not) - const std::string& vKey, // key dialog to display (if not the same key as defined by OpenDialog/Modal => no opening) - ImGuiWindowFlags vFlags = ImGuiWindowFlags_NoCollapse, // ImGuiWindowFlags - ImVec2 vMinSize = ImVec2(0, 0), // mininmal size contraint for the ImGuiWindow - ImVec2 vMaxSize = ImVec2(FLT_MAX, FLT_MAX)); // maximal size contraint for the ImGuiWindow - void Close(); // close dialog + // Display / Close dialog form + bool Display( // Display the dialog. return true if a result was obtained (Ok or not) + const std::string& vKey, // key dialog to display (if not the same key as defined by OpenDialog/Modal => no opening) + ImGuiWindowFlags vFlags = ImGuiWindowFlags_NoCollapse, // ImGuiWindowFlags + ImVec2 vMinSize = ImVec2(0, 0), // mininmal size contraint for the ImGuiWindow + ImVec2 vMaxSize = ImVec2(FLT_MAX, FLT_MAX)); // maximal size contraint for the ImGuiWindow + void Close(); // close dialog - // queries - bool WasOpenedThisFrame(const std::string& vKey) const; // say if the dialog key was already opened this frame - bool WasOpenedThisFrame() const; // say if the dialog was already opened this frame - bool IsOpened(const std::string& vKey) const; // say if the key is opened - bool IsOpened() const; // say if the dialog is opened somewhere - std::string GetOpenedKey() const; // return the dialog key who is opened, return nothing if not opened + // queries + bool WasOpenedThisFrame(const std::string& vKey) const; // say if the dialog key was already opened this frame + bool WasOpenedThisFrame() const; // say if the dialog was already opened this frame + bool IsOpened(const std::string& vKey) const; // say if the key is opened + bool IsOpened() const; // say if the dialog is opened somewhere + std::string GetOpenedKey() const; // return the dialog key who is opened, return nothing if not opened - // get result - bool IsOk() const; // true => Dialog Closed with Ok result / false : Dialog closed with cancel result - std::map GetSelection(); // Open File behavior : will return selection via a map - std::string GetFilePathName(); // Save File behavior : will always return the content of the field with current filter extention and current path - std::string GetCurrentFileName(); // Save File behavior : will always return the content of the field with current filter extention - std::string GetCurrentPath(); // will return current path - std::string GetCurrentFilter(); // will return selected filter - UserDatas GetUserDatas() const; // will return user datas send with Open Dialog/Modal + // get result + bool IsOk() const; // true => Dialog Closed with Ok result / false : Dialog closed with cancel result + std::map GetSelection(); // Open File behavior : will return selection via a map + std::string GetFilePathName(); // Save File behavior : will always return the content of the field with current filter extention and current path + std::string GetCurrentFileName(); // Save File behavior : will always return the content of the field with current filter extention + std::string GetCurrentPath(); // will return current path + std::string GetCurrentFilter(); // will return selected filter + UserDatas GetUserDatas() const; // will return user datas send with Open Dialog/Modal - // file style by extentions - void SetFileStyle( // SetExtention datas for have custom display of particular file type - const IGFD_FileStyleFlags& vFlags, // file style - const char* vCriteria, // extention filter to tune - const FileStyle& vInfos); // Filter Extention Struct who contain Color and Icon/Text for the display of the file with extention filter - void SetFileStyle( // SetExtention datas for have custom display of particular file type - const IGFD_FileStyleFlags& vFlags, // file style - const char* vCriteria, // extention filter to tune - const ImVec4& vColor, // wanted color for the display of the file with extention filter - const std::string& vIcon = "", // wanted text or icon of the file with extention filter - ImFont *vFont = nullptr); // wantes font - bool GetFileStyle( // GetExtention datas. return true is extention exist - const IGFD_FileStyleFlags& vFlags, // file style - const std::string& vCriteria, // extention filter (same as used in SetExtentionInfos) - ImVec4* vOutColor, // color to retrieve - std::string* vOutIcon = nullptr, // icon or text to retrieve + // file style by extentions + void SetFileStyle( // SetExtention datas for have custom display of particular file type + const IGFD_FileStyleFlags& vFlags, // file style + const char* vCriteria, // extention filter to tune + const FileStyle& vInfos); // Filter Extention Struct who contain Color and Icon/Text for the display of the file with extention filter + void SetFileStyle( // SetExtention datas for have custom display of particular file type + const IGFD_FileStyleFlags& vFlags, // file style + const char* vCriteria, // extention filter to tune + const ImVec4& vColor, // wanted color for the display of the file with extention filter + const std::string& vIcon = "", // wanted text or icon of the file with extention filter + ImFont *vFont = nullptr); // wantes font + bool GetFileStyle( // GetExtention datas. return true is extention exist + const IGFD_FileStyleFlags& vFlags, // file style + const std::string& vCriteria, // extention filter (same as used in SetExtentionInfos) + ImVec4* vOutColor, // color to retrieve + std::string* vOutIcon = nullptr, // icon or text to retrieve ImFont** vOutFont = nullptr); // font to retreive - void ClearFilesStyle(); // clear extentions setttings + void ClearFilesStyle(); // clear extentions setttings - void SetLocales( // set locales to use before and after the dialog display - const int& vLocaleCategory, // set local category - const std::string& vLocaleBegin, // locale to use at begining of the dialog display - const std::string& vLocaleEnd); // locale to use at the end of the dialog display + void SetLocales( // set locales to use before and after the dialog display + const int& vLocaleCategory, // set local category + const std::string& vLocaleBegin, // locale to use at begining of the dialog display + const std::string& vLocaleEnd); // locale to use at the end of the dialog display - protected: - void NewFrame(); // new frame just at begining of display - void EndFrame(); // end frame just at end of display - void QuitFrame(); // quit frame when qui quit the dialog + protected: + void NewFrame(); // new frame just at begining of display + void EndFrame(); // end frame just at end of display + void QuitFrame(); // quit frame when qui quit the dialog - // others - bool prConfirm_Or_OpenOverWriteFileDialog_IfNeeded( - bool vLastAction, ImGuiWindowFlags vFlags); // treatment of the result, start the confirm to overwrite dialog if needed (if defined with flag) - - public: - // dialog parts - virtual void prDrawHeader(); // draw header part of the dialog (bookmark btn, dir creation, path composer, search bar) - virtual bool prDrawContent(); // draw content part of the dialog (bookmark pane, file list, side pane) - virtual bool prDrawFooter(); // draw footer part of the dialog (file field, fitler combobox, ok/cancel btn's) + // others + bool prConfirm_Or_OpenOverWriteFileDialog_IfNeeded( + bool vLastAction, ImGuiWindowFlags vFlags); // treatment of the result, start the confirm to overwrite dialog if needed (if defined with flag) + + public: + // dialog parts + virtual void prDrawHeader(); // draw header part of the dialog (bookmark btn, dir creation, path composer, search bar) + virtual bool prDrawContent(); // draw content part of the dialog (bookmark pane, file list, side pane) + virtual bool prDrawFooter(); // draw footer part of the dialog (file field, fitler combobox, ok/cancel btn's) - // widgets components - virtual void prDrawSidePane(float vHeight); // draw side pane - virtual int prSelectableItem(int vidx, - std::shared_ptr vInfos, - bool vSelected, const char* vFmt, ...); // draw a custom selectable behavior item - virtual bool prDrawFileListView(ImVec2 vSize); // draw file list view (default mode) + // widgets components + virtual void prDrawSidePane(float vHeight); // draw side pane + virtual int prSelectableItem(int vidx, + std::shared_ptr vInfos, + bool vSelected, const char* vFmt, ...); // draw a custom selectable behavior item + virtual bool prDrawFileListView(ImVec2 vSize); // draw file list view (default mode) #ifdef USE_THUMBNAILS - virtual void prDrawThumbnailsListView(ImVec2 vSize); // draw file list view with small thumbnails on the same line - virtual void prDrawThumbnailsGridView(ImVec2 vSize); // draw a grid of small thumbnails + virtual void prDrawThumbnailsListView(ImVec2 vSize); // draw file list view with small thumbnails on the same line + virtual void prDrawThumbnailsGridView(ImVec2 vSize); // draw a grid of small thumbnails #endif - // to be called only by these function and theirs overrides - // - prDrawFileListView - // - prDrawThumbnailsListView - // - prDrawThumbnailsGridView - void prBeginFileColorIconStyle( - std::shared_ptr vFileInfos, - bool& vOutShowColor, - std::string& vOutStr, - ImFont** vOutFont); // begin style apply of filter with color an icon if any - void prEndFileColorIconStyle( - const bool& vShowColor, - ImFont* vFont); // end style apply of filter - }; + // to be called only by these function and theirs overrides + // - prDrawFileListView + // - prDrawThumbnailsListView + // - prDrawThumbnailsGridView + void prBeginFileColorIconStyle( + std::shared_ptr vFileInfos, + bool& vOutShowColor, + std::string& vOutStr, + ImFont** vOutFont); // begin style apply of filter with color an icon if any + void prEndFileColorIconStyle( + const bool& vShowColor, + ImFont* vFont); // end style apply of filter + }; } typedef IGFD::UserDatas IGFDUserDatas; @@ -1382,229 +1374,229 @@ typedef struct IGFD_Selection IGFD_Selection; struct IGFD_Selection_Pair { - char* fileName; - char* filePathName; + char* fileName; + char* filePathName; }; -IMGUIFILEDIALOG_API IGFD_Selection_Pair IGFD_Selection_Pair_Get(); // return an initialized IGFD_Selection_Pair -IMGUIFILEDIALOG_API void IGFD_Selection_Pair_DestroyContent(IGFD_Selection_Pair* vSelection_Pair); // destroy the content of a IGFD_Selection_Pair +IMGUIFILEDIALOG_API IGFD_Selection_Pair IGFD_Selection_Pair_Get(); // return an initialized IGFD_Selection_Pair +IMGUIFILEDIALOG_API void IGFD_Selection_Pair_DestroyContent(IGFD_Selection_Pair* vSelection_Pair); // destroy the content of a IGFD_Selection_Pair struct IGFD_Selection { - IGFD_Selection_Pair* table; // 0 - size_t count; // 0U + IGFD_Selection_Pair* table; // 0 + size_t count; // 0U }; -IMGUIFILEDIALOG_API IGFD_Selection IGFD_Selection_Get(); // return an initialized IGFD_Selection -IMGUIFILEDIALOG_API void IGFD_Selection_DestroyContent(IGFD_Selection* vSelection); // destroy the content of a IGFD_Selection +IMGUIFILEDIALOG_API IGFD_Selection IGFD_Selection_Get(); // return an initialized IGFD_Selection +IMGUIFILEDIALOG_API void IGFD_Selection_DestroyContent(IGFD_Selection* vSelection); // destroy the content of a IGFD_Selection // constructor / destructor -IMGUIFILEDIALOG_API ImGuiFileDialog* IGFD_Create(void); // create the filedialog context -IMGUIFILEDIALOG_API void IGFD_Destroy(ImGuiFileDialog* vContext); // destroy the filedialog context +IMGUIFILEDIALOG_API ImGuiFileDialog* IGFD_Create(void); // create the filedialog context +IMGUIFILEDIALOG_API void IGFD_Destroy(ImGuiFileDialog* vContext); // destroy the filedialog context -typedef void (*IGFD_PaneFun)(const char*, void*, bool*); // callback fucntion for display the pane +typedef void (*IGFD_PaneFun)(const char*, void*, bool*); // callback fucntion for display the pane #ifdef USE_THUMBNAILS -typedef void (*IGFD_CreateThumbnailFun)(IGFD_Thumbnail_Info*); // callback function for create thumbnail texture -typedef void (*IGFD_DestroyThumbnailFun)(IGFD_Thumbnail_Info*); // callback fucntion for destroy thumbnail texture +typedef void (*IGFD_CreateThumbnailFun)(IGFD_Thumbnail_Info*); // callback function for create thumbnail texture +typedef void (*IGFD_DestroyThumbnailFun)(IGFD_Thumbnail_Info*); // callback fucntion for destroy thumbnail texture #endif // USE_THUMBNAILS -IMGUIFILEDIALOG_API void IGFD_OpenDialog( // open a standard dialog - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vPath, // path - const char* vFileName, // defaut file name - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenDialog( // open a standard dialog + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vPath, // path + const char* vFileName, // defaut file name + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenDialog2( // open a standard dialog - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vFilePathName, // defaut file path name (path and filename witl be extracted from it) - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenDialog2( // open a standard dialog + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vFilePathName, // defaut file path name (path and filename witl be extracted from it) + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenPaneDialog( // open a standard dialog with pane - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vPath, // path - const char* vFileName, // defaut file name - const IGFD_PaneFun vSidePane, // side pane - const float vSidePaneWidth, // side pane base width - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenPaneDialog( // open a standard dialog with pane + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vPath, // path + const char* vFileName, // defaut file name + const IGFD_PaneFun vSidePane, // side pane + const float vSidePaneWidth, // side pane base width + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenPaneDialog2( // open a standard dialog with pane - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vFilePathName, // defaut file name (path and filename witl be extracted from it) - const IGFD_PaneFun vSidePane, // side pane - const float vSidePaneWidth, // side pane base width - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenPaneDialog2( // open a standard dialog with pane + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vFilePathName, // defaut file name (path and filename witl be extracted from it) + const IGFD_PaneFun vSidePane, // side pane + const float vSidePaneWidth, // side pane base width + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenModal( // open a modal dialog - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vPath, // path - const char* vFileName, // defaut file name - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenModal( // open a modal dialog + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vPath, // path + const char* vFileName, // defaut file name + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenModal2( // open a modal dialog - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vFilePathName, // defaut file name (path and filename witl be extracted from it) - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenModal2( // open a modal dialog + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vFilePathName, // defaut file name (path and filename witl be extracted from it) + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenPaneModal( // open a modal dialog with pane - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vPath, // path - const char* vFileName, // defaut file name - const IGFD_PaneFun vSidePane, // side pane - const float vSidePaneWidth, // side pane base width - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenPaneModal( // open a modal dialog with pane + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vPath, // path + const char* vFileName, // defaut file name + const IGFD_PaneFun vSidePane, // side pane + const float vSidePaneWidth, // side pane base width + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API void IGFD_OpenPaneModal2( // open a modal dialog with pane - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog - const char* vTitle, // title - const char* vFilters, // filters/filter collections. set it to null for directory mode - const char* vFilePathName, // defaut file name (path and filename witl be extracted from it) - const IGFD_PaneFun vSidePane, // side pane - const float vSidePaneWidth, // side pane base width - const int vCountSelectionMax, // count selection max - void* vUserDatas, // user datas (can be retrieved in pane) - ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags +IMGUIFILEDIALOG_API void IGFD_OpenPaneModal2( // open a modal dialog with pane + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog + const char* vTitle, // title + const char* vFilters, // filters/filter collections. set it to null for directory mode + const char* vFilePathName, // defaut file name (path and filename witl be extracted from it) + const IGFD_PaneFun vSidePane, // side pane + const float vSidePaneWidth, // side pane base width + const int vCountSelectionMax, // count selection max + void* vUserDatas, // user datas (can be retrieved in pane) + ImGuiFileDialogFlags vFlags); // ImGuiFileDialogFlags -IMGUIFILEDIALOG_API bool IGFD_DisplayDialog( // Display the dialog - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey, // key dialog to display (if not the same key as defined by OpenDialog/Modal => no opening) - ImGuiWindowFlags vFlags, // ImGuiWindowFlags - ImVec2 vMinSize, // mininmal size contraint for the ImGuiWindow - ImVec2 vMaxSize); // maximal size contraint for the ImGuiWindow +IMGUIFILEDIALOG_API bool IGFD_DisplayDialog( // Display the dialog + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey, // key dialog to display (if not the same key as defined by OpenDialog/Modal => no opening) + ImGuiWindowFlags vFlags, // ImGuiWindowFlags + ImVec2 vMinSize, // mininmal size contraint for the ImGuiWindow + ImVec2 vMaxSize); // maximal size contraint for the ImGuiWindow -IMGUIFILEDIALOG_API void IGFD_CloseDialog( // Close the dialog - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API void IGFD_CloseDialog( // Close the dialog + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API bool IGFD_IsOk( // true => Dialog Closed with Ok result / false : Dialog closed with cancel result - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API bool IGFD_IsOk( // true => Dialog Closed with Ok result / false : Dialog closed with cancel result + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API bool IGFD_WasKeyOpenedThisFrame( // say if the dialog key was already opened this frame - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vKey); +IMGUIFILEDIALOG_API bool IGFD_WasKeyOpenedThisFrame( // say if the dialog key was already opened this frame + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vKey); -IMGUIFILEDIALOG_API bool IGFD_WasOpenedThisFrame( // say if the dialog was already opened this frame - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API bool IGFD_WasOpenedThisFrame( // say if the dialog was already opened this frame + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API bool IGFD_IsKeyOpened( // say if the dialog key is opened - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vCurrentOpenedKey); // the dialog key +IMGUIFILEDIALOG_API bool IGFD_IsKeyOpened( // say if the dialog key is opened + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vCurrentOpenedKey); // the dialog key -IMGUIFILEDIALOG_API bool IGFD_IsOpened( // say if the dialog is opened somewhere - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API bool IGFD_IsOpened( // say if the dialog is opened somewhere + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API IGFD_Selection IGFD_GetSelection( // Open File behavior : will return selection via a map - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API IGFD_Selection IGFD_GetSelection( // Open File behavior : will return selection via a map + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API char* IGFD_GetFilePathName( // Save File behavior : will always return the content of the field with current filter extention and current path - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API char* IGFD_GetFilePathName( // Save File behavior : will always return the content of the field with current filter extention and current path + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API char* IGFD_GetCurrentFileName( // Save File behavior : will always return the content of the field with current filter extention - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API char* IGFD_GetCurrentFileName( // Save File behavior : will always return the content of the field with current filter extention + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API char* IGFD_GetCurrentPath( // will return current path - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API char* IGFD_GetCurrentPath( // will return current path + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API char* IGFD_GetCurrentFilter( // will return selected filter - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API char* IGFD_GetCurrentFilter( // will return selected filter + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API void* IGFD_GetUserDatas( // will return user datas send with Open Dialog/Modal - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API void* IGFD_GetUserDatas( // will return user datas send with Open Dialog/Modal + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API void IGFD_SetFileStyle( // SetExtention datas for have custom display of particular file type - ImGuiFileDialog* vContext, // ImGuiFileDialog context - IGFD_FileStyleFlags vFileStyleFlags, // file style type - const char* vFilter, // extention filter to tune - ImVec4 vColor, // wanted color for the display of the file with extention filter - const char* vIconText, // wanted text or icon of the file with extention filter (can be sued with font icon) - ImFont* vFont); // wanted font pointer +IMGUIFILEDIALOG_API void IGFD_SetFileStyle( // SetExtention datas for have custom display of particular file type + ImGuiFileDialog* vContext, // ImGuiFileDialog context + IGFD_FileStyleFlags vFileStyleFlags, // file style type + const char* vFilter, // extention filter to tune + ImVec4 vColor, // wanted color for the display of the file with extention filter + const char* vIconText, // wanted text or icon of the file with extention filter (can be sued with font icon) + ImFont* vFont); // wanted font pointer -IMGUIFILEDIALOG_API void IGFD_SetFileStyle2( // SetExtention datas for have custom display of particular file type - ImGuiFileDialog* vContext, // ImGuiFileDialog context - IGFD_FileStyleFlags vFileStyleFlags, // file style type - const char* vFilter, // extention filter to tune - float vR, float vG, float vB, float vA, // wanted color channels RGBA for the display of the file with extention filter - const char* vIconText, // wanted text or icon of the file with extention filter (can be sued with font icon) - ImFont* vFont); // wanted font pointer +IMGUIFILEDIALOG_API void IGFD_SetFileStyle2( // SetExtention datas for have custom display of particular file type + ImGuiFileDialog* vContext, // ImGuiFileDialog context + IGFD_FileStyleFlags vFileStyleFlags, // file style type + const char* vFilter, // extention filter to tune + float vR, float vG, float vB, float vA, // wanted color channels RGBA for the display of the file with extention filter + const char* vIconText, // wanted text or icon of the file with extention filter (can be sued with font icon) + ImFont* vFont); // wanted font pointer IMGUIFILEDIALOG_API bool IGFD_GetFileStyle( - ImGuiFileDialog* vContext, // ImGuiFileDialog context - IGFD_FileStyleFlags vFileStyleFlags, // file style type - const char* vFilter, // extention filter (same as used in SetExtentionInfos) - ImVec4* vOutColor, // color to retrieve - char** vOutIconText, // icon or text to retrieve - ImFont** vOutFont); // font pointer to retrived + ImGuiFileDialog* vContext, // ImGuiFileDialog context + IGFD_FileStyleFlags vFileStyleFlags, // file style type + const char* vFilter, // extention filter (same as used in SetExtentionInfos) + ImVec4* vOutColor, // color to retrieve + char** vOutIconText, // icon or text to retrieve + ImFont** vOutFont); // font pointer to retrived -IMGUIFILEDIALOG_API void IGFD_ClearFilesStyle( // clear extentions setttings - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API void IGFD_ClearFilesStyle( // clear extentions setttings + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API void SetLocales( // set locales to use before and after display - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const int vCategory, // set local category - const char* vBeginLocale, // locale to use at begining of the dialog display - const char* vEndLocale); // locale to set at end of the dialog display +IMGUIFILEDIALOG_API void SetLocales( // set locales to use before and after display + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const int vCategory, // set local category + const char* vBeginLocale, // locale to use at begining of the dialog display + const char* vEndLocale); // locale to set at end of the dialog display #ifdef USE_EXPLORATION_BY_KEYS -IMGUIFILEDIALOG_API void IGFD_SetFlashingAttenuationInSeconds( // set the flashing time of the line in file list when use exploration keys - ImGuiFileDialog* vContext, // ImGuiFileDialog context - float vAttenValue); // set the attenuation (from flashed to not flashed) in seconds +IMGUIFILEDIALOG_API void IGFD_SetFlashingAttenuationInSeconds( // set the flashing time of the line in file list when use exploration keys + ImGuiFileDialog* vContext, // ImGuiFileDialog context + float vAttenValue); // set the attenuation (from flashed to not flashed) in seconds #endif #ifdef USE_BOOKMARK -IMGUIFILEDIALOG_API char* IGFD_SerializeBookmarks( // serialize bookmarks : return bookmark buffer to save in a file - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API char* IGFD_SerializeBookmarks( // serialize bookmarks : return bookmark buffer to save in a file + ImGuiFileDialog* vContext); // ImGuiFileDialog context -IMGUIFILEDIALOG_API void IGFD_DeserializeBookmarks( // deserialize bookmarks : load bookmar buffer to load in the dialog (saved from previous use with SerializeBookmarks()) - ImGuiFileDialog* vContext, // ImGuiFileDialog context - const char* vBookmarks); // bookmark buffer to load +IMGUIFILEDIALOG_API void IGFD_DeserializeBookmarks( // deserialize bookmarks : load bookmar buffer to load in the dialog (saved from previous use with SerializeBookmarks()) + ImGuiFileDialog* vContext, // ImGuiFileDialog context + const char* vBookmarks); // bookmark buffer to load #endif #ifdef USE_THUMBNAILS -IMGUIFILEDIALOG_API void SetCreateThumbnailCallback( // define the callback for create the thumbnails texture - ImGuiFileDialog* vContext, // ImGuiFileDialog context - IGFD_CreateThumbnailFun vCreateThumbnailFun); // the callback for create the thumbnails texture +IMGUIFILEDIALOG_API void SetCreateThumbnailCallback( // define the callback for create the thumbnails texture + ImGuiFileDialog* vContext, // ImGuiFileDialog context + IGFD_CreateThumbnailFun vCreateThumbnailFun); // the callback for create the thumbnails texture -IMGUIFILEDIALOG_API void SetDestroyThumbnailCallback( // define the callback for destroy the thumbnails texture - ImGuiFileDialog* vContext, // ImGuiFileDialog context - IGFD_DestroyThumbnailFun vDestroyThumbnailFun); // the callback for destroy the thumbnails texture +IMGUIFILEDIALOG_API void SetDestroyThumbnailCallback( // define the callback for destroy the thumbnails texture + ImGuiFileDialog* vContext, // ImGuiFileDialog context + IGFD_DestroyThumbnailFun vDestroyThumbnailFun); // the callback for destroy the thumbnails texture -IMGUIFILEDIALOG_API void ManageGPUThumbnails( // must be call in gpu zone, possibly a thread, will call the callback for create / destroy the textures - ImGuiFileDialog* vContext); // ImGuiFileDialog context +IMGUIFILEDIALOG_API void ManageGPUThumbnails( // must be call in gpu zone, possibly a thread, will call the callback for create / destroy the textures + ImGuiFileDialog* vContext); // ImGuiFileDialog context #endif // USE_THUMBNAILS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/extern/igfd/ImGuiFileDialogConfig.h b/extern/igfd/ImGuiFileDialogConfig.h index 1db638dd..4a212b60 100644 --- a/extern/igfd/ImGuiFileDialogConfig.h +++ b/extern/igfd/ImGuiFileDialogConfig.h @@ -2,9 +2,6 @@ // uncomment and modify defines under for customize ImGuiFileDialog -//this options need c++17 -//#define USE_STD_FILESYSTEM - //#define MAX_FILE_DIALOG_NAME_BUFFER 1024 //#define MAX_PATH_BUFFER_SIZE 1024 diff --git a/extern/imgui_patched/backends/imgui_impl_dx11.cpp b/extern/imgui_patched/backends/imgui_impl_dx11.cpp index fa60d9eb..86276968 100644 --- a/extern/imgui_patched/backends/imgui_impl_dx11.cpp +++ b/extern/imgui_patched/backends/imgui_impl_dx11.cpp @@ -32,16 +32,16 @@ // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2016-05-07: DirectX11: Disabling depth-write. +// DISCLAIMER: modified with d3dcompiler patch (see https://github.com/ocornut/imgui/pull/638). + #include "imgui.h" #include "imgui_impl_dx11.h" // DirectX #include #include -#include -#ifdef _MSC_VER -#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. -#endif + +typedef HRESULT (__stdcall *D3DCompile_t)(LPCVOID, SIZE_T, LPCSTR, D3D_SHADER_MACRO*, ID3DInclude*, LPCSTR, LPCSTR, UINT, UINT, ID3DBlob**, ID3DBlob*); // DirectX11 data struct ImGui_ImplDX11_Data @@ -380,11 +380,22 @@ bool ImGui_ImplDX11_CreateDeviceObjects() if (bd->pFontSampler) ImGui_ImplDX11_InvalidateDeviceObjects(); - // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) - // If you would like to use this DX11 sample code but remove this dependency you can: - // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] - // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. + // Detect which d3dcompiler_XX.dll is present in the system and grab a pointer to D3DCompile. + // Without this, you must link d3dcompiler.lib with the project. + D3DCompile_t D3DCompile = NULL; + { + char dllBuffer[20]; + for (int i = 47; i > 30 && !D3DCompile; i--) + { + sprintf(dllBuffer, "d3dcompiler_%d.dll", i); + HMODULE hDll = LoadLibraryA(dllBuffer); + if (hDll) + D3DCompile = (D3DCompile_t)GetProcAddress(hDll, "D3DCompile"); + } + if (!D3DCompile) + return false; + } // Create the vertex shader { diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 9f70aef0..5afc5407 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1444,9 +1444,6 @@ void DivEngine::initSongWithDesc(const char* description, bool inBase64, bool ol // extra attributes song.subsong[0]->hz=c.getDouble("tickRate",60.0); - if (song.subsong[0]->hz!=60.0) { - song.subsong[0]->customTempo=true; - } } void DivEngine::createNew(const char* description, String sysName, bool inBase64) { @@ -2696,16 +2693,7 @@ void DivEngine::reset() { elapsedBars=0; elapsedBeats=0; nextSpeed=speeds.val[0]; - divider=60; - if (curSubSong->customTempo) { - divider=curSubSong->hz; - } else { - if (curSubSong->pal) { - divider=60; - } else { - divider=50; - } - } + divider=curSubSong->hz; globalPitch=0; for (int i=0; ireset(); @@ -2920,14 +2908,7 @@ const DivGroovePattern& DivEngine::getSpeeds() { } float DivEngine::getHz() { - if (curSubSong->customTempo) { - return curSubSong->hz; - } else if (curSubSong->pal) { - return 60.0; - } else { - return 50.0; - } - return 60.0; + return curSubSong->hz; } float DivEngine::getCurHz() { @@ -4354,23 +4335,11 @@ void DivEngine::updateSysFlags(int system, bool restart) { BUSY_END; } -void DivEngine::setSongRate(float hz, bool pal) { +void DivEngine::setSongRate(float hz) { BUSY_BEGIN; saveLock.lock(); - curSubSong->pal=!pal; curSubSong->hz=hz; - // what? - curSubSong->customTempo=true; - divider=60; - if (curSubSong->customTempo) { - divider=curSubSong->hz; - } else { - if (curSubSong->pal) { - divider=60; - } else { - divider=50; - } - } + divider=curSubSong->hz; saveLock.unlock(); BUSY_END; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 2b9f5992..bae7daa9 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -954,7 +954,7 @@ class DivEngine { void updateSysFlags(int system, bool restart); // set Hz - void setSongRate(float hz, bool pal); + void setSongRate(float hz); // set remaining loops. -1 means loop forever. void setLoops(int loops); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index d3ae5421..5a752236 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -220,20 +220,22 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.subsong[0]->hilightB=reader.readC(); } + bool customTempo=false; + ds.subsong[0]->timeBase=reader.readC(); ds.subsong[0]->speeds.len=2; ds.subsong[0]->speeds.val[0]=reader.readC(); if (ds.version>0x07) { ds.subsong[0]->speeds.val[1]=reader.readC(); - ds.subsong[0]->pal=reader.readC(); - ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50; - ds.subsong[0]->customTempo=reader.readC(); + bool pal=reader.readC(); + ds.subsong[0]->hz=pal?60:50; + customTempo=reader.readC(); } else { ds.subsong[0]->speeds.len=1; } if (ds.version>0x0a) { String hz=reader.readString(3); - if (ds.subsong[0]->customTempo) { + if (customTempo) { try { ds.subsong[0]->hz=std::stoi(hz); } catch (std::exception& e) { @@ -304,7 +306,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.subsong[0]->hz=248; break; } - ds.subsong[0]->customTempo=true; ds.subsong[0]->timeBase=0; addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system."); } @@ -1864,8 +1865,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { subSong->speeds.val[1]=reader.readC(); subSong->arpLen=reader.readC(); subSong->hz=reader.readF(); - subSong->pal=(subSong->hz>=53); - subSong->customTempo=true; subSong->patLen=reader.readS(); subSong->ordersLen=reader.readS(); @@ -2489,8 +2488,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { subSong->speeds.val[1]=reader.readC(); subSong->arpLen=reader.readC(); subSong->hz=reader.readF(); - subSong->pal=(subSong->hz>=53); - subSong->customTempo=true; subSong->patLen=reader.readS(); subSong->ordersLen=reader.readS(); @@ -3322,9 +3319,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { ds.subsong[0]->pat[ch].effectCols=fxCols; } - ds.subsong[0]->pal=false; ds.subsong[0]->hz=50; - ds.subsong[0]->customTempo=false; ds.systemLen=(chCount+3)/4; for(int i=0; ispeeds.val[0]=(unsigned char)reader.readC(); ds.subsong[0]->hz=((double)reader.readC())/2.5; - ds.subsong[0]->customTempo=true; unsigned char masterVol=reader.readC(); @@ -3993,8 +3987,6 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ds.subsong[0]->ordersLen=seqLen; ds.subsong[0]->patLen=32; ds.subsong[0]->hz=50; - ds.subsong[0]->pal=true; - ds.subsong[0]->customTempo=true; ds.subsong[0]->pat[3].effectCols=3; ds.subsong[0]->speeds.val[0]=3; ds.subsong[0]->speeds.len=1; @@ -5819,12 +5811,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeString(song.author,true); w->writeC(curSubSong->hilightA); w->writeC(curSubSong->hilightB); + + int intHz=curSubSong->hz; w->writeC(curSubSong->timeBase); w->writeC(curSubSong->speeds.val[0]); w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]); - w->writeC(curSubSong->pal); - w->writeC(curSubSong->customTempo); + w->writeC((intHz<=53)?1:0); + w->writeC((intHz!=60 && intHz!=50)); char customHz[4]; memset(customHz,0,4); snprintf(customHz,4,"%d",(int)curSubSong->hz); diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 7c0b8c24..48128bc6 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -168,7 +168,7 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) { outL+=(output*sep2)>>7; outR+=(output*sep1)>>7; } - oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]))<<2; + oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]))<<1; } else { oscBuf[i]->data[oscBuf[i]->needle++]=0; } diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index e617fc0d..0e38bf96 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -76,7 +76,8 @@ void DivPlatformArcade::acquire_nuked(short** buf, size_t len) { } for (int i=0; i<8; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]; + int chOut=(int16_t)fm.ch_out[i]; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<1,-32768,32767); } if (o[0]<-32768) o[0]=-32768; @@ -111,7 +112,8 @@ void DivPlatformArcade::acquire_ymfm(short** buf, size_t len) { fm_ymfm->generate(&out_ymfm); for (int i=0; i<8; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1)); + int chOut=fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1); + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut,-32768,32767); } os[0]=out_ymfm.data[0]; diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 8eaea3fe..c32a4ee2 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -187,9 +187,9 @@ void DivPlatformAY8910::acquire(short** buf, size_t len) { buf[0][i]=ayBuf[0][0]; buf[1][i]=buf[0][i]; - oscBuf[0]->data[oscBuf[0]->needle++]=sunsoftVolTable[31-(ay->lastIndx&31)]<<3; - oscBuf[1]->data[oscBuf[1]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>5)&31)]<<3; - oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3; + oscBuf[0]->data[oscBuf[0]->needle++]=CLAMP(sunsoftVolTable[31-(ay->lastIndx&31)]<<3,-32768,32767); + oscBuf[1]->data[oscBuf[1]->needle++]=CLAMP(sunsoftVolTable[31-((ay->lastIndx>>5)&31)]<<3,-32768,32767); + oscBuf[2]->data[oscBuf[2]->needle++]=CLAMP(sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3,-32768,32767); } } else { for (size_t i=0; i>12; - oscBuf[j]->data[oscBuf[j]->needle++]=chanOut; + oscBuf[j]->data[oscBuf[j]->needle++]=chanOut<<1; out+=chanOut; } else { oscBuf[j]->data[oscBuf[j]->needle++]=0; diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 5f6e2829..f388e860 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -168,7 +168,7 @@ void DivPlatformES5506::acquire(short** buf, size_t len) { buf[(o<<1)|1][h]=es5506.rout(o); } for (int i=chanMax; i>=0; i--) { - oscBuf[i]->data[oscBuf[i]->needle++]=(es5506.voice_lout(i)+es5506.voice_rout(i))>>5; + oscBuf[i]->data[oscBuf[i]->needle++]=(es5506.voice_lout(i)+es5506.voice_rout(i))>>6; } } } diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index 420f3e3a..ea903ced 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -64,7 +64,7 @@ void DivPlatformFDS::acquire_puNES(short* buf, size_t len) { buf[i]=sample; if (++writeOscBuf>=32) { writeOscBuf=0; - oscBuf->data[oscBuf->needle++]=sample<<1; + oscBuf->data[oscBuf->needle++]=sample*3; } } } @@ -80,7 +80,7 @@ void DivPlatformFDS::acquire_NSFPlay(short* buf, size_t len) { buf[i]=sample; if (++writeOscBuf>=32) { writeOscBuf=0; - oscBuf->data[oscBuf->needle++]=sample<<1; + oscBuf->data[oscBuf->needle++]=sample*3; } } } diff --git a/src/engine/platform/ga20.cpp b/src/engine/platform/ga20.cpp index 7b9d86a1..7794d61a 100644 --- a/src/engine/platform/ga20.cpp +++ b/src/engine/platform/ga20.cpp @@ -71,11 +71,16 @@ void DivPlatformGA20::acquire(short** buf, size_t len) { delay=w.delay; } } - short *buffer[4] = {&ga20Buf[0][h],&ga20Buf[1][h],&ga20Buf[2][h],&ga20Buf[3][h]}; - ga20.sound_stream_update(buffer, 1); + short *buffer[4]={ + &ga20Buf[0][h], + &ga20Buf[1][h], + &ga20Buf[2][h], + &ga20Buf[3][h] + }; + ga20.sound_stream_update(buffer,1); buf[0][h]=(signed int)(ga20Buf[0][h]+ga20Buf[1][h]+ga20Buf[2][h]+ga20Buf[3][h])>>2; for (int i=0; i<4; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ga20Buf[i][h]; + oscBuf[i]->data[oscBuf[i]->needle++]=ga20Buf[i][h]>>1; } } } diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 9f905105..a4b0f7b1 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -184,16 +184,18 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) { if (i==5) { if (fm.dacen) { if (softPCM) { - oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7; - oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7; + oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<6; + oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<6; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7; + oscBuf[i]->data[oscBuf[i]->needle++]=(fm.dacdata^0x100)<<6; + oscBuf[6]->data[oscBuf[6]->needle++]=0; } } else { - oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?2:7),-32768,32767); + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?1:6),-32768,32767); + oscBuf[6]->data[oscBuf[6]->needle++]=0; } } else { - oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?2:7),-32768,32767); + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?1:6),-32768,32767); } } @@ -241,19 +243,21 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) { //OPN2_Write(&fm,0,0); for (int i=0; i<6; i++) { - int chOut=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; + int chOut=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<5; if (chOut<-32768) chOut=-32768; if (chOut>32767) chOut=32767; if (i==5) { if (fm_ymfm->debug_dac_enable()) { if (softPCM) { - oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7; - oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7; + oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<6; + oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<6; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7; + oscBuf[i]->data[oscBuf[i]->needle++]=(fm_ymfm->debug_dac_data()^0x100)<<6; + oscBuf[6]->data[oscBuf[6]->needle++]=0; } } else { oscBuf[i]->data[oscBuf[i]->needle++]=chOut; + oscBuf[6]->data[oscBuf[6]->needle++]=0; } } else { oscBuf[i]->data[oscBuf[i]->needle++]=chOut; diff --git a/src/engine/platform/k007232.cpp b/src/engine/platform/k007232.cpp index 0b11d45f..bb0bf7a9 100644 --- a/src/engine/platform/k007232.cpp +++ b/src/engine/platform/k007232.cpp @@ -79,14 +79,14 @@ void DivPlatformK007232::acquire(short** buf, size_t len) { buf[0][h]=(lout[0]+lout[1])<<4; buf[1][h]=(rout[0]+rout[1])<<4; for (int i=0; i<2; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<4; + oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<3; } } else { const unsigned char vol=regPool[0xc]; const signed int out[2]={(k007232.output(0)*(vol&0xf)),(k007232.output(1)*((vol>>4)&0xf))}; buf[0][h]=(out[0]+out[1])<<4; for (int i=0; i<2; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<5; + oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<4; } } } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 11b04e81..e9ac6be9 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -85,9 +85,9 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) { if (++writeOscBuf>=32) { writeOscBuf=0; - oscBuf[0]->data[oscBuf[0]->needle++]=isMuted[0]?0:((mmc5->S3.output*10)<<7); - oscBuf[1]->data[oscBuf[1]->needle++]=isMuted[1]?0:((mmc5->S4.output*10)<<7); - oscBuf[2]->data[oscBuf[2]->needle++]=isMuted[2]?0:((mmc5->pcm.output*2)<<6); + oscBuf[0]->data[oscBuf[0]->needle++]=isMuted[0]?0:((mmc5->S3.output)<<11); + oscBuf[1]->data[oscBuf[1]->needle++]=isMuted[1]?0:((mmc5->S4.output)<<11); + oscBuf[2]->data[oscBuf[2]->needle++]=isMuted[2]?0:((mmc5->pcm.output)<<7); } } } diff --git a/src/engine/platform/msm5232.cpp b/src/engine/platform/msm5232.cpp index eb8d5cbf..55df6128 100644 --- a/src/engine/platform/msm5232.cpp +++ b/src/engine/platform/msm5232.cpp @@ -60,7 +60,7 @@ void DivPlatformMSM5232::acquire(short** buf, size_t len) { ((regPool[12+(i>>4)]&2)?((msm->vo8[i]*partVolume[2+(i&4)])>>8):0)+ ((regPool[12+(i>>4)]&4)?((msm->vo4[i]*partVolume[1+(i&4)])>>8):0)+ ((regPool[12+(i>>4)]&8)?((msm->vo2[i]*partVolume[i&4])>>8):0) - )<<3; + )<<2; oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(o,-32768,32767); } diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 6591eda5..31002a9c 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -84,7 +84,7 @@ void DivPlatformMSM6258::acquire(short** buf, size_t len) { } else { buf[0][h]=(msmPan&2)?msmOut:0; buf[1][h]=(msmPan&1)?msmOut:0; - oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?msmOut:0; + oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?(msmOut>>1):0; } } } diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index de7fedd5..2aff0006 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -79,9 +79,8 @@ void DivPlatformMSM6295::acquire(short** buf, size_t len) { if (++updateOsc>=22) { updateOsc=0; - // TODO: per-channel osc for (int i=0; i<4; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=msm.voice_out(i)<<6; + oscBuf[i]->data[oscBuf[i]->needle++]=msm.voice_out(i)<<5; } } } diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 87721eb8..088f1e63 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -177,7 +177,7 @@ void DivPlatformNamcoWSG::acquire(short** buf, size_t len) { }; namco->sound_stream_update(bufC,1); for (int i=0; idata[oscBuf[i]->needle++]=namco->m_channel_list[i].last_out*chans; + oscBuf[i]->data[oscBuf[i]->needle++]=(namco->m_channel_list[i].last_out*chans)>>1; } } } diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index a25568d0..99131ac3 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -145,7 +145,7 @@ void DivPlatformNES::acquire_NSFPlay(short** buf, size_t len) { oscBuf[0]->data[oscBuf[0]->needle++]=nes1_NP->out[0]<<11; oscBuf[1]->data[oscBuf[1]->needle++]=nes1_NP->out[1]<<11; oscBuf[2]->data[oscBuf[2]->needle++]=nes2_NP->out[0]<<11; - oscBuf[3]->data[oscBuf[3]->needle++]=nes2_NP->out[1]<<11; + oscBuf[3]->data[oscBuf[3]->needle++]=nes2_NP->out[1]<<12; oscBuf[4]->data[oscBuf[4]->needle++]=nes2_NP->out[2]<<8; } } diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index a54667a7..d340aa31 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -211,7 +211,7 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { if (!isMuted[adpcmChan]) { os[0]-=aOut.data[0]>>3; os[1]-=aOut.data[0]>>3; - oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=aOut.data[0]; + oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=aOut.data[0]>>1; } else { oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=0; } @@ -220,47 +220,45 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { if (fm.rhy&0x20) { for (int i=0; idata[oscBuf[i]->needle]=0; if (fm.channel[i].out[0]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[0]; + chOut+=*fm.channel[ch].out[0]; } if (fm.channel[i].out[1]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; + chOut+=*fm.channel[ch].out[1]; } if (fm.channel[i].out[2]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[2]; + chOut+=*fm.channel[ch].out[2]; } if (fm.channel[i].out[3]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[3]; + chOut+=*fm.channel[ch].out[3]; } - oscBuf[i]->data[oscBuf[i]->needle]<<=1; - oscBuf[i]->needle++; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<(i==melodicChans?1:2),-32768,32767); } // special - oscBuf[melodicChans+1]->data[oscBuf[melodicChans+1]->needle++]=fm.slot[16].out*6; - oscBuf[melodicChans+2]->data[oscBuf[melodicChans+2]->needle++]=fm.slot[14].out*6; - oscBuf[melodicChans+3]->data[oscBuf[melodicChans+3]->needle++]=fm.slot[17].out*6; - oscBuf[melodicChans+4]->data[oscBuf[melodicChans+4]->needle++]=fm.slot[13].out*6; + oscBuf[melodicChans+1]->data[oscBuf[melodicChans+1]->needle++]=fm.slot[16].out*4; + oscBuf[melodicChans+2]->data[oscBuf[melodicChans+2]->needle++]=fm.slot[14].out*4; + oscBuf[melodicChans+3]->data[oscBuf[melodicChans+3]->needle++]=fm.slot[17].out*4; + oscBuf[melodicChans+4]->data[oscBuf[melodicChans+4]->needle++]=fm.slot[13].out*4; } else { for (int i=0; idata[oscBuf[i]->needle]=0; if (fm.channel[i].out[0]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[0]; + chOut+=*fm.channel[ch].out[0]; } if (fm.channel[i].out[1]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; + chOut+=*fm.channel[ch].out[1]; } if (fm.channel[i].out[2]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[2]; + chOut+=*fm.channel[ch].out[2]; } if (fm.channel[i].out[3]!=NULL) { - oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[3]; + chOut+=*fm.channel[ch].out[3]; } - oscBuf[i]->data[oscBuf[i]->needle]<<=1; - oscBuf[i]->needle++; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<2,-32768,32767); } } diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 8f30a9dd..38b892e8 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -101,8 +101,16 @@ void DivPlatformOPLL::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].vol,MIN(15,chan[i].std.vol.val),15); - if (i<9) { - rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); + + if (i>=6 && properDrums) { + drumVol[i-6]=15-chan[i].outVol; + rWrite(0x36,drumVol[0]); + rWrite(0x37,drumVol[1]|(drumVol[4]<<4)); + rWrite(0x38,drumVol[3]|(drumVol[2]<<4)); + } else if (i<6 || !drums) { + if (i<9) { + rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); + } } } diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index a920a4d0..47e5bbcd 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -101,7 +101,7 @@ void DivPlatformPCE::acquire(short** buf, size_t len) { pce->ResetTS(0); for (int i=0; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP((pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1])<<1,-32768,32767); + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1],-32768,32767); } tempL[0]=(tempL[0]>>1)+(tempL[0]>>2); diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 283b6e24..3a00e431 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -229,7 +229,7 @@ void DivPlatformPCMDAC::acquire(short** buf, size_t len) { } else { output=output*chan[0].vol*chan[0].envVol/16384; } - oscBuf->data[oscBuf->needle++]=output; + oscBuf->data[oscBuf->needle++]=output>>1; if (outStereo) { buf[0][h]=((output*chan[0].panL)>>(depthScale+8))<>(depthScale+8))<=14) { oscBufDelay=0; - oscBuf[0]->data[oscBuf[0]->needle++]=pokey.outvol_0<<11; - oscBuf[1]->data[oscBuf[1]->needle++]=pokey.outvol_1<<11; - oscBuf[2]->data[oscBuf[2]->needle++]=pokey.outvol_2<<11; - oscBuf[3]->data[oscBuf[3]->needle++]=pokey.outvol_3<<11; + oscBuf[0]->data[oscBuf[0]->needle++]=pokey.outvol_0<<10; + oscBuf[1]->data[oscBuf[1]->needle++]=pokey.outvol_1<<10; + oscBuf[2]->data[oscBuf[2]->needle++]=pokey.outvol_2<<10; + oscBuf[3]->data[oscBuf[3]->needle++]=pokey.outvol_3<<10; } } } diff --git a/src/engine/platform/pv1000.cpp b/src/engine/platform/pv1000.cpp index 4d32fc5a..bf03df40 100644 --- a/src/engine/platform/pv1000.cpp +++ b/src/engine/platform/pv1000.cpp @@ -42,7 +42,7 @@ void DivPlatformPV1000::acquire(short** buf, size_t len) { short samp=d65010g031_sound_tick(&d65010g031,1); buf[0][h]=samp; for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(d65010g031.out[i]); + oscBuf[i]->data[oscBuf[i]->needle++]=d65010g031.out[i]<<1; } } } diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index b1aeab3e..d7f908f5 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -272,7 +272,7 @@ void DivPlatformQSound::acquire(short** buf, size_t len) { buf[1][h]=chip.out[1]; for (int i=0; i<19; i++) { - int data=chip.voice_output[i]<<2; + int data=chip.voice_output[i]<<1; if (data<-32768) data=-32768; if (data>32767) data=32767; oscBuf[i]->data[oscBuf[i]->needle++]=data; diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 7be43801..84522c74 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -74,7 +74,7 @@ void DivPlatformRF5C68::acquire(short** buf, size_t len) { rf5c68.sound_stream_update(bufPtrs,chBufPtrs,blockLen); for (int i=0; i<8; i++) { for (size_t j=0; jdata[oscBuf[i]->needle++]=bufC[i*2][j]+bufC[i*2+1][j]; + oscBuf[i]->data[oscBuf[i]->needle++]=(bufC[i*2][j]+bufC[i*2+1][j])>>1; } } pos+=blockLen; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index ce24e2fb..47411496 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -49,7 +49,7 @@ void DivPlatformSegaPCM::acquire(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; i<16; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=pcm.lastOut[i][0]+pcm.lastOut[i][1]; + oscBuf[i]->data[oscBuf[i]->needle++]=(pcm.lastOut[i][0]+pcm.lastOut[i][1])>>1; } } } diff --git a/src/engine/platform/sm8521.cpp b/src/engine/platform/sm8521.cpp index e1f359c0..e72616bd 100644 --- a/src/engine/platform/sm8521.cpp +++ b/src/engine/platform/sm8521.cpp @@ -58,9 +58,9 @@ void DivPlatformSM8521::acquire(short** buf, size_t len) { sm8521_sound_tick(&sm8521,8); buf[0][h]=sm8521.out<<6; for (int i=0; i<2; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=sm8521.sg[i].base.out<<6; + oscBuf[i]->data[oscBuf[i]->needle++]=sm8521.sg[i].base.out<<7; } - oscBuf[2]->data[oscBuf[2]->needle++]=sm8521.noise.base.out<<6; + oscBuf[2]->data[oscBuf[2]->needle++]=sm8521.noise.base.out<<7; } } diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 0c9734c2..43401ebc 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -91,7 +91,7 @@ void DivPlatformSNES::acquire(short** buf, size_t len) { next=(next*254)/MAX(1,globalVolL+globalVolR); if (next<-32768) next=-32768; if (next>32767) next=32767; - oscBuf[i]->data[oscBuf[i]->needle++]=next; + oscBuf[i]->data[oscBuf[i]->needle++]=next>>1; } } } diff --git a/src/engine/platform/sound/pokey/AltASAP.cpp b/src/engine/platform/sound/pokey/AltASAP.cpp index 21bc31a2..e6675027 100644 --- a/src/engine/platform/sound/pokey/AltASAP.cpp +++ b/src/engine/platform/sound/pokey/AltASAP.cpp @@ -39,7 +39,7 @@ static constexpr int MuteInit = 2; static constexpr int MuteSerialInput = 8; //just some magick value to match the audio level of mzpokeysnd static constexpr int16_t MAGICK_VOLUME_BOOSTER = 160; -static constexpr int16_t MAGICK_OSC_VOLUME_BOOSTER = 4; +static constexpr int16_t MAGICK_OSC_VOLUME_BOOSTER = 6; struct PokeyBase { diff --git a/src/engine/platform/t6w28.cpp b/src/engine/platform/t6w28.cpp index 0d7b9223..5d21e1ad 100644 --- a/src/engine/platform/t6w28.cpp +++ b/src/engine/platform/t6w28.cpp @@ -54,7 +54,7 @@ void DivPlatformT6W28::acquire(short** buf, size_t len) { tempL=0; tempR=0; for (int i=0; i<4; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(out[i][1].curValue+out[i][2].curValue)<<6; + oscBuf[i]->data[oscBuf[i]->needle++]=(out[i][1].curValue+out[i][2].curValue)<<7; tempL+=out[i][1].curValue<<7; tempR+=out[i][2].curValue<<7; } diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 935390bc..86128340 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -78,7 +78,7 @@ void DivPlatformTX81Z::acquire(short** buf, size_t len) { fm_ymfm->generate(&out_ymfm); for (int i=0; i<8; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1),-32768,32767); } os[0]=out_ymfm.data[0]; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 57e6f29f..8357f756 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -107,9 +107,9 @@ void DivPlatformVERA::acquire(short** buf, size_t len) { pos++; for (int i=0; i<16; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=psg->channels[i].lastOut<<4; + oscBuf[i]->data[oscBuf[i]->needle++]=psg->channels[i].lastOut<<3; } - int pcmOut=whyCallItBuf[2][i]+whyCallItBuf[3][i]; + int pcmOut=(whyCallItBuf[2][i]+whyCallItBuf[3][i])>>1; if (pcmOut<-32768) pcmOut=-32768; if (pcmOut>32767) pcmOut=32767; oscBuf[16]->data[oscBuf[16]->needle++]=pcmOut; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 2aeb3897..b52bc106 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -87,7 +87,7 @@ void DivPlatformVRC6::acquire(short** buf, size_t len) { if (++writeOscBuf>=32) { writeOscBuf=0; for (int i=0; i<2; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.pulse_out(i)<<10; + oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.pulse_out(i)<<11; } oscBuf[2]->data[oscBuf[2]->needle++]=vrc6.sawtooth_out()<<10; } diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 44f94d99..29601ae9 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -222,7 +222,7 @@ void DivPlatformX1_010::acquire(short** buf, size_t len) { if (stereo) buf[1][h]=tempR; for (int i=0; i<16; i++) { - int vo=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))<<3; + int vo=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))<<2; oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(vo,-32768,32767); } } diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index cc2d1f3f..69d1ca8a 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -231,11 +231,11 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) { buf[0][h]=os; for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]; + oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]>>1; } for (int i=3; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]; + oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]>>1; } } } @@ -282,11 +282,11 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) { for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1; } for (int i=3; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]; + oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]>>1; } } } diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 7c10e76c..73280bcb 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -402,19 +402,19 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[i]; + oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]>>1; } ssge->get_last_out(ssgOut); for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; + oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1; } for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); + oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1; } - oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } @@ -471,19 +471,19 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1; } ssge->get_last_out(ssgOut); for (int i=6; i<9; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6]; + oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6]>>1; } for (int i=9; i<15; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1); + oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1))>>1; } - oscBuf[15]->data[oscBuf[15]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[15]->data[oscBuf[15]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index e9cb021d..303604d6 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -333,19 +333,19 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]]; + oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]]>>1; } ssge->get_last_out(ssgOut); for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; + oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1; } for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); + oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1; } - oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } @@ -404,19 +404,19 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1; } ssge->get_last_out(ssgOut); for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; + oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1; } for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); + oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1; } - oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 7d28a801..b4292a14 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -401,19 +401,19 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[i]; + oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]>>1; } ssge->get_last_out(ssgOut); for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; + oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1; } for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); + oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1; } - oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } @@ -471,19 +471,19 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1; } ssge->get_last_out(ssgOut); for (int i=psgChanOffs; idata[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]; + oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1; } for (int i=adpcmAChanOffs; idata[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1); + oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1; } - oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); + oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1; } } diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index a8838ae9..496f3568 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -76,7 +76,7 @@ void DivPlatformYMZ280B::acquire(short** buf, size_t len) { for (int j=0; j<8; j++) { dataL+=why[j*2][i]; dataR+=why[j*2+1][i]; - oscBuf[j]->data[oscBuf[j]->needle++]=(short)(((int)why[j*2][i]+why[j*2+1][i])/2); + oscBuf[j]->data[oscBuf[j]->needle++]=(short)(((int)why[j*2][i]+why[j*2+1][i])/4); } buf[0][pos]=(short)(dataL/8); buf[1][pos]=(short)(dataR/8); diff --git a/src/engine/song.h b/src/engine/song.h index fd2d1e07..0a6149f8 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -153,8 +153,6 @@ struct DivSubSong { unsigned char timeBase, arpLen; DivGroovePattern speeds; short virtualTempoN, virtualTempoD; - bool pal; - bool customTempo; float hz; int patLen, ordersLen; @@ -177,8 +175,6 @@ struct DivSubSong { arpLen(1), virtualTempoN(150), virtualTempoD(150), - pal(true), - customTempo(false), hz(60.0), patLen(64), ordersLen(1) { diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 449a2714..4076dbc6 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -124,6 +124,7 @@ const char* aboutLine[]={ "Ultraprogramer", "UserSniper", "Weeppiko", + "Xan", "Yuzu4K", "Zaxolotl", "ZoomTen (Zumi)", diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index d2ccfb90..e6306db2 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -22,6 +22,7 @@ #include "../ta-log.h" #include "imgui.h" #include "imgui_internal.h" +#include "misc/cpp/imgui_stdlib.h" #define FURNACE_FFT_SIZE 4096 #define FURNACE_FFT_RATE 80.0 @@ -93,7 +94,7 @@ void FurnaceGUI::calcChanOsc() { unsigned short needlePos=buf->needle; needlePos-=displaySize; for (unsigned short i=0; i<512; i++) { - float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/32768.0f; if (minLevel>y) minLevel=y; if (maxLevel oscBufs; + std::vector oscFFTs; + std::vector oscChans; + int chans=e->getTotalChannelCount(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + ImVec2 waveform[512]; - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f)); - float availY=ImGui::GetContentRegionAvail().y; - if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) { - std::vector oscBufs; - std::vector oscFFTs; - std::vector oscChans; - int chans=e->getTotalChannelCount(); - ImGuiWindow* window=ImGui::GetCurrentWindow(); - ImVec2 waveform[512]; + ImGuiStyle& style=ImGui::GetStyle(); - ImGuiStyle& style=ImGui::GetStyle(); - - for (int i=0; igetOscBuffer(i); - if (buf!=NULL && e->curSubSong->chanShow[i]) { - oscBufs.push_back(buf); - oscFFTs.push_back(&chanOscChan[i]); - oscChans.push_back(i); + for (int i=0; igetOscBuffer(i); + if (buf!=NULL && e->curSubSong->chanShow[i]) { + oscBufs.push_back(buf); + oscFFTs.push_back(&chanOscChan[i]); + oscChans.push_back(i); + } } - } - int rows=(oscBufs.size()+(chanOscCols-1))/chanOscCols; + int rows=(oscBufs.size()+(chanOscCols-1))/chanOscCols; - for (size_t i=0; ireadNeedle=buf->needle; - } + if (centerSettingReset) { + buf->readNeedle=buf->needle; + } - // check FFT status existence - if (fft->plan==NULL) { - logD("creating FFT plan for channel %d",ch); - fft->inBuf=(double*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(double)); - fft->outBuf=(fftw_complex*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(fftw_complex)); - fft->plan=fftw_plan_dft_r2c_1d(FURNACE_FFT_SIZE,fft->inBuf,fft->outBuf,FFTW_ESTIMATE); - } + // check FFT status existence + if (fft->plan==NULL) { + logD("creating FFT plan for channel %d",ch); + fft->inBuf=(double*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(double)); + fft->outBuf=(fftw_complex*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(fftw_complex)); + fft->plan=fftw_plan_dft_r2c_1d(FURNACE_FFT_SIZE,fft->inBuf,fft->outBuf,FFTW_ESTIMATE); + } - int displaySize=(float)(buf->rate)*(chanOscWindowSize/1000.0f); + int displaySize=(float)(buf->rate)*(chanOscWindowSize/1000.0f); - ImVec2 minArea=window->DC.CursorPos; - ImVec2 maxArea=ImVec2( - minArea.x+size.x, - minArea.y+size.y - ); - ImRect rect=ImRect(minArea,maxArea); - ImRect inRect=rect; - inRect.Min.x+=dpiScale; - inRect.Min.y+=dpiScale; - inRect.Max.x-=dpiScale; - inRect.Max.y-=dpiScale; - ImGui::ItemSize(size,style.FramePadding.y); - if (ImGui::ItemAdd(rect,ImGui::GetID("chOscDisplay"))) { - if (!e->isRunning()) { - for (unsigned short i=0; i<512; i++) { - float x=(float)i/512.0f; - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f)); - } - } else { - float minLevel=1.0f; - float maxLevel=-1.0f; - float dcOff=0.0f; - unsigned short needlePos=buf->needle; - for (int i=0; iinBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0; - } - fftw_execute(fft->plan); - - // find origin frequency - int point=1; - double candAmp=0.0; - for (unsigned short i=1; i<512; i++) { - fftw_complex& f=fft->outBuf[i]; - // AMPLITUDE - double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/pow((double)i,0.8); - if (amp>candAmp) { - point=i; - candAmp=amp; + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + ImRect inRect=rect; + inRect.Min.x+=dpiScale; + inRect.Min.y+=2.0*dpiScale; + inRect.Max.x-=dpiScale; + inRect.Max.y-=2.0*dpiScale; + + int precision=inRect.Max.x-inRect.Min.x; + if (precision<1) precision=1; + if (precision>512) precision=512; + + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("chOscDisplay"))) { + if (!e->isRunning()) { + for (unsigned short i=0; ineedle; + for (int i=0; iinBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0; + } + fftw_execute(fft->plan); + + // find origin frequency + int point=1; + double candAmp=0.0; + for (unsigned short i=1; i<512; i++) { + fftw_complex& f=fft->outBuf[i]; + // AMPLITUDE + double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/pow((double)i,0.8); + if (amp>candAmp) { + point=i; + candAmp=amp; + } + } + + // PHASE + fftw_complex& candPoint=fft->outBuf[point]; + double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); + + if (chanOscWaveCorr) { + needlePos-=phase; + } + chanOscPitch[ch]=(float)point/32.0f; + + /* + String cPhase=fmt::sprintf("%d cphase: %f vol: %f",point,phase,chanOscVol[ch]); + dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); + */ + + needlePos-=displaySize; + for (unsigned short i=0; idata[(unsigned short)(needlePos+(i*displaySize/precision))]/32768.0f; + if (minLevel>y) minLevel=y; + if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/precision))]/32768.0f; + y-=dcOff; + if (y<-0.5f) y=-0.5f; + if (y>0.5f) y=0.5f; + y*=chanOscAmplify; + waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); } } + ImU32 color=ImGui::GetColorU32(chanOscColor); + if (chanOscUseGrad) { + float xVal=computeGradPos(chanOscColorX,ch); + float yVal=computeGradPos(chanOscColorY,ch); - // PHASE - fftw_complex& candPoint=fft->outBuf[point]; - double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); + xVal=CLAMP(xVal,0.0f,1.0f); + yVal=CLAMP(yVal,0.0f,1.0f); - if (chanOscWaveCorr) { - needlePos-=phase; + color=chanOscGrad.get(xVal,1.0f-yVal); } - chanOscPitch[ch]=(float)point/32.0f; - - /* - String cPhase=fmt::sprintf("%d cphase: %f vol: %f",point,phase,chanOscVol[ch]); - dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); - */ + ImGui::PushClipRect(inRect.Min,inRect.Max,false); - needlePos-=displaySize; - for (unsigned short i=0; i<512; i++) { - float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - if (minLevel>y) minLevel=y; - if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; - y-=dcOff; - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); + dl->AddPolyline(waveform,precision,color,ImDrawFlags_None,dpiScale); + + if (!chanOscTextFormat.empty()) { + String text; + bool inFormat=false; + + for (char i: chanOscTextFormat) { + if (inFormat) { + switch (i) { + case 'c': + text+=e->getChannelName(ch); + break; + case 'C': + text+=e->getChannelShortName(ch); + break; + case 'd': + text+=fmt::sprintf("%d",ch); + break; + case 'D': + text+=fmt::sprintf("%d",ch+1); + break; + case 'i': { + DivChannelState* chanState=e->getChanState(ch); + if (chanState==NULL) break; + DivInstrument* ins=e->getIns(chanState->lastIns); + text+=ins->name; + break; + } + case 'I': { + DivChannelState* chanState=e->getChanState(ch); + if (chanState==NULL) break; + text+=fmt::sprintf("%d",chanState->lastIns); + break; + } + case 'x': { + DivChannelState* chanState=e->getChanState(ch); + if (chanState==NULL) break; + if (chanState->lastIns<0) { + text+="??"; + } else { + text+=fmt::sprintf("%.2X",chanState->lastIns); + } + break; + } + case 's': { + text+=e->getSystemName(e->sysOfChan[ch]); + break; + } + case 'S': { + text+=fmt::sprintf("%d",e->dispatchOfChan[ch]); + break; + } + case 'v': + break; + case 'V': + break; + case 'b': + break; + case '%': + text+='%'; + break; + default: + text+='%'; + text+=i; + break; + } + inFormat=false; + } else { + if (i=='%') { + inFormat=true; + } else { + text+=i; + } + } + } + + dl->AddText(ImLerp(inRect.Min,inRect.Max,ImVec2(0.0f,0.0f)),ImGui::GetColorU32(chanOscTextColor),text.c_str()); } + + ImGui::PopClipRect(); } - ImU32 color=ImGui::GetColorU32(chanOscColor); - if (chanOscUseGrad) { - float xVal=computeGradPos(chanOscColorX,ch); - float yVal=computeGradPos(chanOscColorY,ch); - - xVal=CLAMP(xVal,0.0f,1.0f); - yVal=CLAMP(yVal,0.0f,1.0f); - - color=chanOscGrad.get(xVal,1.0f-yVal); - } - dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale); } } - } - ImGui::EndTable(); + ImGui::EndTable(); - if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - chanOscOptions=!chanOscOptions; + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + chanOscOptions=!chanOscOptions; + } } + ImGui::PopStyleVar(); } - ImGui::PopStyleVar(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_CHAN_OSC; ImGui::End(); diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 7eb3906a..e440b589 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -380,7 +380,7 @@ void FurnaceGUI::drawDebug() { } ImGui::TreePop(); } - if (ImGui::TreeNode("Window Debug")) { + if (ImGui::TreeNodeEx("Window Debug",ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Text("Screen: %dx%d+%d+%d",scrW,scrH,scrX,scrY); ImGui::Text("Screen (Conf): %dx%d+%d+%d",scrConfW,scrConfH,scrConfX,scrConfY); ImGui::Text("Canvas: %dx%d",canvasW,canvasH); @@ -549,6 +549,7 @@ void FurnaceGUI::drawDebug() { ImGui::Text("audio: %dµs",lastProcTime); ImGui::Text("render: %.0fµs",(double)renderTimeDelta/perfFreq); + ImGui::Text("draw: %.0fµs",(double)drawTimeDelta/perfFreq); ImGui::Text("layout: %.0fµs",(double)layoutTimeDelta/perfFreq); ImGui::Text("event: %.0fµs",(double)eventTimeDelta/perfFreq); ImGui::Separator(); diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index 94ffa94e..a0a45e1e 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -1,5 +1,6 @@ #include "fileDialog.h" #include "ImGuiFileDialog.h" +#include "util.h" #include "../ta-log.h" #ifdef USE_NFD @@ -152,6 +153,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c ImGuiFileDialog::Instance()->singleClickSel=mobileUI; ImGuiFileDialog::Instance()->DpiScale=dpiScale; ImGuiFileDialog::Instance()->mobileMode=mobileUI; + ImGuiFileDialog::Instance()->homePath=getHomeDir(); ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,allowMultiple?999:1,nullptr,0,clickCallback); } opened=true; @@ -235,6 +237,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c ImGuiFileDialog::Instance()->singleClickSel=false; ImGuiFileDialog::Instance()->DpiScale=dpiScale; ImGuiFileDialog::Instance()->mobileMode=mobileUI; + ImGuiFileDialog::Instance()->homePath=getHomeDir(); ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite); } opened=true; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dd315ddf..a51f9ab8 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3420,6 +3420,7 @@ bool FurnaceGUI::loop() { logV("portrait: %d (%dx%d)",portrait,scrW,scrH); logD("window resized to %dx%d",scrW,scrH); updateWindow=true; + rend->resized(ev); break; case SDL_WINDOWEVENT_MOVED: scrX=ev.window.data1; @@ -3535,7 +3536,8 @@ bool FurnaceGUI::loop() { // update config x/y/w/h values based on scrMax state if (updateWindow) { logV("updateWindow is true"); - if (!scrMax) { + if (!scrMax && !fullScreen) { + logV("updating scrConf"); scrConfX=scrX; scrConfY=scrY; scrConfW=scrW; @@ -5809,6 +5811,7 @@ bool FurnaceGUI::loop() { renderTimeBegin=SDL_GetPerformanceCounter(); ImGui::Render(); renderTimeEnd=SDL_GetPerformanceCounter(); + drawTimeBegin=SDL_GetPerformanceCounter(); rend->renderGUI(); if (mustClear) { rend->clear(ImVec4(0,0,0,0)); @@ -5822,6 +5825,7 @@ bool FurnaceGUI::loop() { } } } + drawTimeEnd=SDL_GetPerformanceCounter(); rend->present(); if (settings.renderClearPos) { rend->clear(uiColors[GUI_COLOR_BACKGROUND]); @@ -5829,6 +5833,7 @@ bool FurnaceGUI::loop() { layoutTimeDelta=layoutTimeEnd-layoutTimeBegin; renderTimeDelta=renderTimeEnd-renderTimeBegin; + drawTimeDelta=drawTimeEnd-drawTimeBegin; eventTimeDelta=eventTimeEnd-eventTimeBegin; soloTimeout-=ImGui::GetIO().DeltaTime; @@ -5980,6 +5985,7 @@ bool FurnaceGUI::init() { pianoOptions=e->getConfBool("pianoOptions",pianoOptions); pianoSharePosition=e->getConfBool("pianoSharePosition",pianoSharePosition); pianoOptionsSet=e->getConfBool("pianoOptionsSet",pianoOptionsSet); + pianoReadonly=e->getConfBool("pianoReadonly",false); pianoOffset=e->getConfInt("pianoOffset",pianoOffset); pianoOffsetEdit=e->getConfInt("pianoOffsetEdit",pianoOffsetEdit); pianoView=e->getConfInt("pianoView",pianoView); @@ -5988,13 +5994,22 @@ bool FurnaceGUI::init() { chanOscCols=e->getConfInt("chanOscCols",3); chanOscColorX=e->getConfInt("chanOscColorX",GUI_OSCREF_CENTER); chanOscColorY=e->getConfInt("chanOscColorY",GUI_OSCREF_CENTER); + chanOscTextX=e->getConfFloat("chanOscTextX",0.0f); + chanOscTextY=e->getConfFloat("chanOscTextY",0.0f); + chanOscAmplify=e->getConfFloat("chanOscAmplify",0.95f); chanOscWindowSize=e->getConfFloat("chanOscWindowSize",20.0f); chanOscWaveCorr=e->getConfBool("chanOscWaveCorr",true); chanOscOptions=e->getConfBool("chanOscOptions",false); + chanOscNormalize=e->getConfBool("chanOscNormalize",false); + chanOscTextFormat=e->getConfString("chanOscTextFormat","%c"); chanOscColor.x=e->getConfFloat("chanOscColorR",1.0f); chanOscColor.y=e->getConfFloat("chanOscColorG",1.0f); chanOscColor.z=e->getConfFloat("chanOscColorB",1.0f); chanOscColor.w=e->getConfFloat("chanOscColorA",1.0f); + chanOscTextColor.x=e->getConfFloat("chanOscTextColorR",1.0f); + chanOscTextColor.y=e->getConfFloat("chanOscTextColorG",1.0f); + chanOscTextColor.z=e->getConfFloat("chanOscTextColorB",1.0f); + chanOscTextColor.w=e->getConfFloat("chanOscTextColorA",0.75f); chanOscUseGrad=e->getConfBool("chanOscUseGrad",false); chanOscGrad.fromString(e->getConfString("chanOscGrad","")); chanOscGrad.render(); @@ -6144,7 +6159,7 @@ bool FurnaceGUI::init() { logV("window size: %dx%d",scrW,scrH); if (!initRender()) { - if (settings.renderBackend=="OpenGL") { + if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) { settings.renderBackend=""; e->setConf("renderBackend",""); e->saveConf(); @@ -6230,11 +6245,11 @@ bool FurnaceGUI::init() { logD("starting render backend..."); if (!rend->init(sdlWin)) { - if (settings.renderBackend=="OpenGL") { + if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) { settings.renderBackend=""; - e->setConf("renderBackend",""); - e->saveConf(); - lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace."); + //e->setConf("renderBackend",""); + //e->saveConf(); + //lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace."); } else { lastError=fmt::sprintf("could not init renderer! %s",SDL_GetError()); if (!settings.renderDriver.empty()) { @@ -6257,11 +6272,17 @@ bool FurnaceGUI::init() { // special consideration for Wayland if (settings.dpiScale<0.5f) { if (strcmp(videoBackend,"wayland")==0) { - if (scrW<1) { + int realW=scrW; + int realH=scrH; + + SDL_GetWindowSize(sdlWin,&realW,&realH); + + if (realW<1) { logW("screen width is zero!\n"); dpiScale=1.0; } else { - dpiScale=(double)canvasW/(double)scrW; + dpiScale=(double)canvasW/(double)realW; + logV("we're on Wayland... scaling factor: %f",dpiScale); } } } @@ -6465,6 +6486,7 @@ void FurnaceGUI::commitState() { e->setConf("pianoOptions",pianoOptions); e->setConf("pianoSharePosition",pianoSharePosition); e->setConf("pianoOptionsSet",pianoOptionsSet); + e->setConf("pianoReadonly",pianoReadonly); e->setConf("pianoOffset",pianoOffset); e->setConf("pianoOffsetEdit",pianoOffsetEdit); e->setConf("pianoView",pianoView); @@ -6474,13 +6496,22 @@ void FurnaceGUI::commitState() { e->setConf("chanOscCols",chanOscCols); e->setConf("chanOscColorX",chanOscColorX); e->setConf("chanOscColorY",chanOscColorY); + e->setConf("chanOscTextX",chanOscTextX); + e->setConf("chanOscTextY",chanOscTextY); + e->setConf("chanOscAmplify",chanOscAmplify); e->setConf("chanOscWindowSize",chanOscWindowSize); e->setConf("chanOscWaveCorr",chanOscWaveCorr); e->setConf("chanOscOptions",chanOscOptions); + e->setConf("chanOscNormalize",chanOscNormalize); + e->setConf("chanOscTextFormat",chanOscTextFormat); e->setConf("chanOscColorR",chanOscColor.x); e->setConf("chanOscColorG",chanOscColor.y); e->setConf("chanOscColorB",chanOscColor.z); e->setConf("chanOscColorA",chanOscColor.w); + e->setConf("chanOscTextColorR",chanOscTextColor.x); + e->setConf("chanOscTextColorG",chanOscTextColor.y); + e->setConf("chanOscTextColorB",chanOscTextColor.z); + e->setConf("chanOscTextColorA",chanOscTextColor.w); e->setConf("chanOscUseGrad",chanOscUseGrad); e->setConf("chanOscGrad",chanOscGrad.toString()); @@ -6825,6 +6856,9 @@ FurnaceGUI::FurnaceGUI(): renderTimeBegin(0), renderTimeEnd(0), renderTimeDelta(0), + drawTimeBegin(0), + drawTimeEnd(0), + drawTimeDelta(0), eventTimeBegin(0), eventTimeEnd(0), eventTimeDelta(0), @@ -6899,11 +6933,17 @@ FurnaceGUI::FurnaceGUI(): chanOscColorX(GUI_OSCREF_CENTER), chanOscColorY(GUI_OSCREF_CENTER), chanOscWindowSize(20.0f), + chanOscTextX(0.0f), + chanOscTextY(0.0f), + chanOscAmplify(0.95f), chanOscWaveCorr(true), chanOscOptions(false), updateChanOscGradTex(true), chanOscUseGrad(false), + chanOscNormalize(false), + chanOscTextFormat("%c"), chanOscColor(1.0f,1.0f,1.0f,1.0f), + chanOscTextColor(1.0f,1.0f,1.0f,0.75f), chanOscGrad(64,64), chanOscGradTex(NULL), followLog(true), @@ -6913,6 +6953,7 @@ FurnaceGUI::FurnaceGUI(): pianoOptions(true), pianoSharePosition(false), pianoOptionsSet(false), + pianoReadonly(false), pianoOffset(6), pianoOffsetEdit(9), pianoView(PIANO_LAYOUT_AUTOMATIC), @@ -6922,6 +6963,7 @@ FurnaceGUI::FurnaceGUI(): pianoOctavesEdit(4), pianoOptions(false), pianoSharePosition(true), + pianoReadonly(false), pianoOffset(6), pianoOffsetEdit(6), pianoView(PIANO_LAYOUT_STANDARD), @@ -6946,6 +6988,7 @@ FurnaceGUI::FurnaceGUI(): mustClear(2), initialScreenWipe(1.0f), introSkipDo(false), + introStopped(false), curTutorial(-1), curTutorialStep(0) { // value keys diff --git a/src/gui/gui.h b/src/gui/gui.h index f5b58109..87c2a7fa 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -71,16 +71,22 @@ enum FurnaceGUIRenderBackend { GUI_BACKEND_SDL=0, - GUI_BACKEND_GL + GUI_BACKEND_GL, + GUI_BACKEND_DX11 }; #ifdef HAVE_RENDER_SDL #define GUI_BACKEND_DEFAULT GUI_BACKEND_SDL #define GUI_BACKEND_DEFAULT_NAME "SDL" #else +#ifdef HAVE_RENDER_DX11 +#define GUI_BACKEND_DEFAULT GUI_BACKEND_DX11 +#define GUI_BACKEND_DEFAULT_NAME "DirectX 11" +#else #define GUI_BACKEND_DEFAULT GUI_BACKEND_GL #define GUI_BACKEND_DEFAULT_NAME "OpenGL" #endif +#endif // TODO: // - add colors for FM envelope and waveform @@ -1242,6 +1248,7 @@ class FurnaceGUIRender { virtual bool destroyTexture(void* which); virtual void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode); virtual void setBlendMode(FurnaceGUIBlendMode mode); + virtual void resized(const SDL_Event& ev); virtual void clear(ImVec4 color); virtual bool newFrame(); virtual void createFontsTexture(); @@ -1864,6 +1871,7 @@ class FurnaceGUI { int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta; int renderTimeBegin, renderTimeEnd, renderTimeDelta; + int drawTimeBegin, drawTimeEnd, drawTimeDelta; int eventTimeBegin, eventTimeEnd, eventTimeDelta; FurnaceGUIPerfMetric perfMetrics[64]; @@ -1939,9 +1947,10 @@ class FurnaceGUI { // per-channel oscilloscope int chanOscCols, chanOscColorX, chanOscColorY; - float chanOscWindowSize; - bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex, chanOscUseGrad; - ImVec4 chanOscColor; + float chanOscWindowSize, chanOscTextX, chanOscTextY, chanOscAmplify; + bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex, chanOscUseGrad, chanOscNormalize; + String chanOscTextFormat; + ImVec4 chanOscColor, chanOscTextColor; Gradient2D chanOscGrad; void* chanOscGradTex; float chanOscLP0[DIV_MAX_CHANS]; @@ -1995,6 +2004,7 @@ class FurnaceGUI { bool pianoOptions, pianoSharePosition, pianoOptionsSet; float pianoKeyHit[180]; bool pianoKeyPressed[180]; + bool pianoReadonly; int pianoOffset, pianoOffsetEdit; int pianoView, pianoInputPadMode; @@ -2029,7 +2039,7 @@ class FurnaceGUI { double monitorPos; int mustClear; float initialScreenWipe; - bool introSkipDo; + bool introSkipDo, introStopped; ImVec2 introMin, introMax; // tutorial diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 2989ae72..9fcf78a3 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -506,7 +506,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_ABOUT", "About", 0), D("WINDOW_SETTINGS", "Settings", 0), D("WINDOW_MIXER", "Mixer", 0), - D("WINDOW_DEBUG", "Debug Menu", 0), + D("WINDOW_DEBUG", "Debug Menu", FURKMOD_CMD|FURKMOD_SHIFT|SDLK_d), D("WINDOW_OSCILLOSCOPE", "Oscilloscope (master)", 0), D("WINDOW_VOL_METER", "Volume Meter", 0), D("WINDOW_STATS", "Statistics", 0), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index e02f3969..ca254d2c 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2262,9 +2262,11 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::PushID(2+curIns); if (ImGui::InputText("##Name",&ins->name)) { MARK_MODIFIED; } + ImGui::PopID(); ImGui::TableNextRow(); ImGui::TableNextColumn(); diff --git a/src/gui/intro.cpp b/src/gui/intro.cpp index db886316..8ebbe020 100644 --- a/src/gui/intro.cpp +++ b/src/gui/intro.cpp @@ -19,6 +19,7 @@ #define _USE_MATH_DEFINES #include "gui.h" +#include "../ta-log.h" #include "imgui_internal.h" #include @@ -73,6 +74,8 @@ void FurnaceGUI::drawImage(ImDrawList* dl, FurnaceGUIImages image, const ImVec2& } void FurnaceGUI::endIntroTune() { + if (introStopped) return; + logV("ending intro"); stop(); if (curFileName.empty()) { e->createNewFromDefaults(); @@ -95,6 +98,8 @@ void FurnaceGUI::endIntroTune() { selEnd=SelectionPoint(); cursor=SelectionPoint(); updateWindowTitle(); + updateScroll(0); + introStopped=true; } void FurnaceGUI::drawIntro(double introTime, bool monitor) { @@ -290,7 +295,7 @@ void FurnaceGUI::drawIntro(double introTime, bool monitor) { if (introSkipDo) { introSkip+=ImGui::GetIO().DeltaTime; if (introSkip>=0.5) { - if (e->isPlaying()) endIntroTune(); + if (!shortIntro) endIntroTune(); introPos=0.1; if (introSkip>=0.75) introPos=12.0; } @@ -317,7 +322,7 @@ void FurnaceGUI::drawIntro(double introTime, bool monitor) { e->setRepeatPattern(false); play(); } - if (e->isPlaying() && introPos>=10.0 && !shortIntro) endIntroTune(); + if (introPos>=10.0 && !shortIntro) endIntroTune(); introPos+=ImGui::GetIO().DeltaTime; if (introPos>=(shortIntro?1.0:11.0)) { introPos=12.0; @@ -325,5 +330,7 @@ void FurnaceGUI::drawIntro(double introTime, bool monitor) { commitTutorial(); } } + } else if (!shortIntro) { + endIntroTune(); } } diff --git a/src/gui/piano.cpp b/src/gui/piano.cpp index baae316d..4842d05c 100644 --- a/src/gui/piano.cpp +++ b/src/gui/piano.cpp @@ -123,6 +123,7 @@ void FurnaceGUI::drawPiano() { pianoInputPadMode=PIANO_INPUT_PAD_SPLIT_VISIBLE; } ImGui::Checkbox("Share play/edit offset/range",&pianoSharePosition); + ImGui::Checkbox("Read-only (can't input notes)",&pianoReadonly); ImGui::EndPopup(); } @@ -223,7 +224,7 @@ void FurnaceGUI::drawPiano() { //ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) { bool canInput=false; - if (ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) { + if (!pianoReadonly && ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) { canInput=true; ImGui::InhibitInertialScroll(); } diff --git a/src/gui/render.cpp b/src/gui/render.cpp index 908fd57d..5ad753c2 100644 --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -25,12 +25,17 @@ #ifdef HAVE_RENDER_GL #include "render/renderGL.h" #endif +#ifdef HAVE_RENDER_DX11 +#include "render/renderDX11.h" +#endif bool FurnaceGUI::initRender() { if (rend!=NULL) return false; if (settings.renderBackend=="OpenGL") { renderBackend=GUI_BACKEND_GL; + } else if (settings.renderBackend=="DirectX 11") { + renderBackend=GUI_BACKEND_DX11; } else if (settings.renderBackend=="SDL") { renderBackend=GUI_BACKEND_SDL; } else { @@ -44,6 +49,12 @@ bool FurnaceGUI::initRender() { rend=new FurnaceGUIRenderGL; break; #endif +#ifdef HAVE_RENDER_DX11 + case GUI_BACKEND_DX11: + logI("render backend: DirectX 11"); + rend=new FurnaceGUIRenderDX11; + break; +#endif #ifdef HAVE_RENDER_SDL case GUI_BACKEND_SDL: logI("render backend: SDL_Renderer"); diff --git a/src/gui/render/abstract.cpp b/src/gui/render/abstract.cpp index 996cf4e8..a45c4ecd 100644 --- a/src/gui/render/abstract.cpp +++ b/src/gui/render/abstract.cpp @@ -49,6 +49,9 @@ void FurnaceGUIRender::setTextureBlendMode(void* which, FurnaceGUIBlendMode mode void FurnaceGUIRender::setBlendMode(FurnaceGUIBlendMode mode) { } +void FurnaceGUIRender::resized(const SDL_Event& ev) { +} + void FurnaceGUIRender::clear(ImVec4 color) { } @@ -97,4 +100,4 @@ void FurnaceGUIRender::quitGUI() { } FurnaceGUIRender::~FurnaceGUIRender() { -} \ No newline at end of file +} diff --git a/src/gui/render/renderDX11.cpp b/src/gui/render/renderDX11.cpp new file mode 100644 index 00000000..18cbcbae --- /dev/null +++ b/src/gui/render/renderDX11.cpp @@ -0,0 +1,571 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define INCLUDE_D3D11 +#include "renderDX11.h" +#include +#include "backends/imgui_impl_dx11.h" +#include "../../ta-log.h" + +typedef HRESULT (__stdcall *D3DCompile_t)(LPCVOID,SIZE_T,LPCSTR,D3D_SHADER_MACRO*,ID3DInclude*,LPCSTR,LPCSTR,UINT,UINT,ID3DBlob**,ID3DBlob*); + +const char* shD3D11_wipe_srcV= + "cbuffer WipeUniform: register(b0) {\n" + " float alpha;\n" + " float padding1;\n" + " float padding2;\n" + " float padding3;\n" + " float4 padding4;\n" + "};\n" + "\n" + "struct vsInput {\n" + " float4 pos: POSITION;\n" + "};\n" + "\n" + "struct fsInput {\n" + " float4 pos: SV_POSITION;\n" + " float4 color: COLOR0;\n" + "};\n" + "\n" + "fsInput main(vsInput input) {\n" + " fsInput output;\n" + " output.pos=input.pos;\n" + " output.color=float4(0.0f,0.0f,0.0f,alpha);\n" + " return output;\n" + "}"; + +const char* shD3D11_wipe_srcF= + "struct fsInput {\n" + " float4 pos: SV_POSITION;\n" + " float4 color: COLOR0;\n" + "};\n" + "\n" + "float4 main(fsInput input): SV_Target {\n" + " return input.color;\n" + "}"; + +const D3D11_INPUT_ELEMENT_DESC shD3D11_wipe_inputLayout={ + "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 +}; + +const D3D_FEATURE_LEVEL possibleFeatureLevels[2]={ + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_0 +}; + +struct FurnaceDXTexture { + ID3D11Texture2D* tex; + ID3D11ShaderResourceView* view; + int width, height; + unsigned char* lockedData; + bool dynamic; + FurnaceDXTexture(): + tex(NULL), + view(NULL), + width(0), + height(0), + lockedData(NULL), + dynamic(false) {} +}; + +bool FurnaceGUIRenderDX11::destroyRenderTarget() { + if (renderTarget!=NULL) { + renderTarget->Release(); + renderTarget=NULL; + return true; + } + return false; +} + +bool FurnaceGUIRenderDX11::createRenderTarget() { + ID3D11Texture2D* screen=NULL; + HRESULT result; + + destroyRenderTarget(); + + if (swapchain==NULL || device==NULL) { + logW("createRenderTarget: swapchain or device are NULL!"); + return false; + } + + DXGI_SWAP_CHAIN_DESC chainDesc; + memset(&chainDesc,0,sizeof(chainDesc)); + if (swapchain->GetDesc(&chainDesc)!=S_OK) { + logW("createRenderTarget: could not get swapchain desc!"); + } else { + outW=chainDesc.BufferDesc.Width; + outH=chainDesc.BufferDesc.Height; + logI("DX11: buffer desc sizes: %d, %d",chainDesc.BufferDesc.Width,chainDesc.BufferDesc.Height); + } + + result=swapchain->GetBuffer(0,IID_PPV_ARGS(&screen)); + if (result!=S_OK) { + logW("createRenderTarget: could not get buffer! %.8x",result); + return false; + } + if (screen==NULL) { + logW("createRenderTarget: screen is null!"); + return false; + } + + result=device->CreateRenderTargetView(screen,NULL,&renderTarget); + if (result!=S_OK) { + logW("createRenderTarget: could not create render target view! %.8x",result); + screen->Release(); + return false; + } + if (renderTarget==NULL) { + logW("createRenderTarget: what the hell the render target is null?"); + screen->Release(); + return false; + } + + screen->Release(); + return true; +} + +ImTextureID FurnaceGUIRenderDX11::getTextureID(void* which) { + FurnaceDXTexture* t=(FurnaceDXTexture*)which; + return (ImTextureID)t->view; +} + +bool FurnaceGUIRenderDX11::lockTexture(void* which, void** data, int* pitch) { + FurnaceDXTexture* t=(FurnaceDXTexture*)which; + if (t->lockedData!=NULL) return false; + + D3D11_MAPPED_SUBRESOURCE mappedRes; + memset(&mappedRes,0,sizeof(mappedRes)); + + HRESULT result=context->Map(t->tex,D3D11CalcSubresource(0,0,1),D3D11_MAP_WRITE_DISCARD,0,&mappedRes); + if (result!=S_OK) { + logW("could not map texture! %.8x",result); + return false; + } + t->lockedData=(unsigned char*)mappedRes.pData; + *data=mappedRes.pData; + *pitch=mappedRes.RowPitch; + + logV("texture locked... pitch: %d",mappedRes.RowPitch); + return true; +} + +bool FurnaceGUIRenderDX11::unlockTexture(void* which) { + FurnaceDXTexture* t=(FurnaceDXTexture*)which; + if (t->lockedData==NULL) return false; + context->Unmap(t->tex,D3D11CalcSubresource(0,0,1)); + t->lockedData=NULL; + return true; +} + +bool FurnaceGUIRenderDX11::updateTexture(void* which, void* data, int pitch) { + FurnaceDXTexture* t=(FurnaceDXTexture*)which; + if (t->dynamic) { + unsigned char* d=NULL; + int p=0; + if (!lockTexture(t,(void**)&d,&p)) return false; + if (p==pitch) { + memcpy(d,data,p*t->height); + } else { + unsigned char* ucData=(unsigned char*)data; + int srcPos=0; + int destPos=0; + for (int i=0; iheight; i++) { + memcpy(&d[destPos],&ucData[srcPos],pitch); + srcPos+=pitch; + destPos+=p; + } + } + unlockTexture(t); + } else { + context->UpdateSubresource(t->tex,D3D11CalcSubresource(0,0,1),NULL,data,pitch,pitch*t->height); + } + return true; +} + +void* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width, int height) { + D3D11_TEXTURE2D_DESC texDesc; + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + ID3D11Texture2D* tex=NULL; + ID3D11ShaderResourceView* view=NULL; + HRESULT result; + + memset(&texDesc,0,sizeof(texDesc)); + memset(&viewDesc,0,sizeof(viewDesc)); + + texDesc.Width=width; + texDesc.Height=height; + texDesc.MipLevels=1; + texDesc.ArraySize=1; + texDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; // ??? + texDesc.SampleDesc.Count=1; + texDesc.SampleDesc.Quality=0; + texDesc.Usage=dynamic?D3D11_USAGE_DYNAMIC:D3D11_USAGE_DEFAULT; + texDesc.BindFlags=D3D11_BIND_SHADER_RESOURCE; + texDesc.CPUAccessFlags=dynamic?D3D11_CPU_ACCESS_WRITE:0; + texDesc.MiscFlags=0; + + result=device->CreateTexture2D(&texDesc,NULL,&tex); + if (result!=S_OK) { + logW("could not create texture! %.8x",result); + return NULL; + } + + viewDesc.Format=texDesc.Format=texDesc.Format; + viewDesc.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MostDetailedMip=0; + viewDesc.Texture2D.MipLevels=texDesc.MipLevels; + + result=device->CreateShaderResourceView(tex,&viewDesc,&view); + if (result!=S_OK) { + logW("could not create texture view! %.8x",result); + tex->Release(); + return NULL; + } + + FurnaceDXTexture* ret=new FurnaceDXTexture; + ret->width=width; + ret->height=height; + ret->tex=tex; + ret->view=view; + ret->dynamic=dynamic; + textures.push_back(ret); + return ret; +} + +bool FurnaceGUIRenderDX11::destroyTexture(void* which) { + FurnaceDXTexture* t=(FurnaceDXTexture*)which; + t->view->Release(); + t->tex->Release(); + delete t; + + for (size_t i=0; iResizeBuffers(0,(unsigned int)ev.window.data1,(unsigned int)ev.window.data2,DXGI_FORMAT_UNKNOWN,DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH); + if (result!=S_OK) { + logW("error while resizing swapchain buffers! %.8x",result); + } + createRenderTarget(); +} + +void FurnaceGUIRenderDX11::clear(ImVec4 color) { + float floatColor[4]={ + color.x*color.w, + color.y*color.w, + color.z*color.w, + color.w, + }; + + context->OMSetRenderTargets(1,&renderTarget,NULL); + context->ClearRenderTargetView(renderTarget,floatColor); +} + +bool FurnaceGUIRenderDX11::newFrame() { + ImGui_ImplDX11_NewFrame(); + return true; +} + +void FurnaceGUIRenderDX11::createFontsTexture() { + ImGui_ImplDX11_CreateDeviceObjects(); +} + +void FurnaceGUIRenderDX11::destroyFontsTexture() { + ImGui_ImplDX11_InvalidateDeviceObjects(); +} + +void FurnaceGUIRenderDX11::renderGUI() { + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); +} + +const float blendFactor[4]={ + 1.0f, 1.0f, 1.0f, 1.0f +}; + +void FurnaceGUIRenderDX11::wipe(float alpha) { + D3D11_VIEWPORT viewPort; + unsigned int strides=4*sizeof(float); + unsigned int offsets=0; + + memset(&viewPort,0,sizeof(viewPort)); + viewPort.TopLeftX=0.0f; + viewPort.TopLeftY=0.0f; + viewPort.Width=outW; + viewPort.Height=outH; + viewPort.MinDepth=0.0f; + viewPort.MaxDepth=1.0f; + + D3D11_MAPPED_SUBRESOURCE mappedUniform; + if (context->Map(sh_wipe_uniform,0,D3D11_MAP_WRITE_DISCARD,0,&mappedUniform)!=S_OK) { + logW("could not map constant"); + } + WipeUniform* sh_wipe_uniformState=(WipeUniform*)mappedUniform.pData; + sh_wipe_uniformState->alpha=alpha; + context->Unmap(sh_wipe_uniform,0); + + context->RSSetViewports(1,&viewPort); + context->RSSetState(rsState); + + context->OMSetBlendState(omBlendState,blendFactor,0xffffffff); + context->IASetInputLayout(sh_wipe_inputLayout); + context->IASetVertexBuffers(0,1,&quadVertex,&strides,&offsets); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context->VSSetShader(sh_wipe_vertex,NULL,0); + context->VSSetConstantBuffers(0,1,&sh_wipe_uniform); + context->PSSetShader(sh_wipe_fragment,NULL,0); + + context->Draw(4,0); +} + +void FurnaceGUIRenderDX11::present() { + swapchain->Present(1,0); +} + +bool FurnaceGUIRenderDX11::getOutputSize(int& w, int& h) { + w=outW; + h=outH; + return true; +} + +int FurnaceGUIRenderDX11::getWindowFlags() { + return 0; +} + +void FurnaceGUIRenderDX11::preInit() { +} + +const float wipeVertices[4][4]={ + -1.0, -1.0, 0.0, 1.0, + 1.0, -1.0, 0.0, 1.0, + -1.0, 1.0, 0.0, 1.0, + 1.0, 1.0, 0.0, 1.0 +}; + +bool FurnaceGUIRenderDX11::init(SDL_Window* win) { + SDL_SysWMinfo sysWindow; + D3D_FEATURE_LEVEL featureLevel; + + SDL_VERSION(&sysWindow.version); + if (SDL_GetWindowWMInfo(win,&sysWindow)==SDL_FALSE) { + logE("could not get window WM info! %s",SDL_GetError()); + return false; + } + HWND window=(HWND)sysWindow.info.win.window; + + DXGI_SWAP_CHAIN_DESC chainDesc; + memset(&chainDesc,0,sizeof(chainDesc)); + chainDesc.BufferDesc.Width=0; + chainDesc.BufferDesc.Height=0; + chainDesc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; + chainDesc.BufferDesc.RefreshRate.Numerator=60; + chainDesc.BufferDesc.RefreshRate.Denominator=1; + chainDesc.SampleDesc.Count=1; + chainDesc.SampleDesc.Quality=0; + chainDesc.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT; + chainDesc.BufferCount=2; + chainDesc.OutputWindow=window; + chainDesc.Windowed=TRUE; // TODO: what if we're in full screen mode? + chainDesc.SwapEffect=DXGI_SWAP_EFFECT_DISCARD; + chainDesc.Flags=DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + HRESULT result=D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,0,possibleFeatureLevels,2,D3D11_SDK_VERSION,&chainDesc,&swapchain,&device,&featureLevel,&context); + if (result!=S_OK) { + logE("could not create device and/or swap chain! %.8x",result); + return false; + } + + // https://github.com/ocornut/imgui/pull/638 + D3DCompile_t D3DCompile=NULL; + char dllBuffer[20]; + for (int i=47; (i>30 && !D3DCompile); i--) { + snprintf(dllBuffer,20,"d3dcompiler_%d.dll",i); + HMODULE hDll=LoadLibraryA(dllBuffer); + if (hDll) { + D3DCompile=(D3DCompile_t)GetProcAddress(hDll,"D3DCompile"); + } + } + if (!D3DCompile) { + logE("could not find D3DCompile!"); + return false; + } + + // create wipe shader + ID3DBlob* wipeBlobV=NULL; + ID3DBlob* wipeBlobF=NULL; + D3D11_BUFFER_DESC wipeConstantDesc; + + result=D3DCompile(shD3D11_wipe_srcV,strlen(shD3D11_wipe_srcV),NULL,NULL,NULL,"main","vs_4_0",0,0,&wipeBlobV,NULL); + if (result!=S_OK) { + logE("could not compile vertex shader! %.8x",result); + return false; + } + result=D3DCompile(shD3D11_wipe_srcF,strlen(shD3D11_wipe_srcF),NULL,NULL,NULL,"main","ps_4_0",0,0,&wipeBlobF,NULL); + if (result!=S_OK) { + logE("could not compile pixel shader! %.8x",result); + return false; + } + + result=device->CreateVertexShader(wipeBlobV->GetBufferPointer(),wipeBlobV->GetBufferSize(),NULL,&sh_wipe_vertex); + if (result!=S_OK) { + logE("could not create vertex shader! %.8x",result); + return false; + } + result=device->CreatePixelShader(wipeBlobF->GetBufferPointer(),wipeBlobF->GetBufferSize(),NULL,&sh_wipe_fragment); + if (result!=S_OK) { + logE("could not create pixel shader! %.8x",result); + return false; + } + + result=device->CreateInputLayout(&shD3D11_wipe_inputLayout,1,wipeBlobV->GetBufferPointer(),wipeBlobV->GetBufferSize(),&sh_wipe_inputLayout); + if (result!=S_OK) { + logE("could not create input layout! %.8x",result); + return false; + } + + memset(&wipeConstantDesc,0,sizeof(wipeConstantDesc)); + wipeConstantDesc.ByteWidth=sizeof(WipeUniform); + wipeConstantDesc.Usage=D3D11_USAGE_DYNAMIC; + wipeConstantDesc.BindFlags=D3D11_BIND_CONSTANT_BUFFER; + wipeConstantDesc.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE; + wipeConstantDesc.MiscFlags=0; + wipeConstantDesc.StructureByteStride=0; + + result=device->CreateBuffer(&wipeConstantDesc,NULL,&sh_wipe_uniform); + if (result!=S_OK) { + logE("could not create constant buffer! %.8x",result); + return false; + } + + // create wipe vertices + D3D11_BUFFER_DESC vertexDesc; + D3D11_SUBRESOURCE_DATA vertexRes; + + memset(&vertexDesc,0,sizeof(vertexDesc)); + memset(&vertexRes,0,sizeof(vertexRes)); + + vertexDesc.ByteWidth=4*4*sizeof(float); + vertexDesc.Usage=D3D11_USAGE_DEFAULT; + vertexDesc.BindFlags=D3D11_BIND_VERTEX_BUFFER; + vertexDesc.CPUAccessFlags=0; + vertexDesc.MiscFlags=0; + vertexDesc.StructureByteStride=0; + + vertexRes.pSysMem=wipeVertices; + vertexRes.SysMemPitch=0; + vertexRes.SysMemSlicePitch=0; + + result=device->CreateBuffer(&vertexDesc,&vertexRes,&quadVertex); + if (result!=S_OK) { + logE("could not create vertex buffer! %.8x",result); + return false; + } + + // initialize the rest + D3D11_RASTERIZER_DESC rasterDesc; + D3D11_BLEND_DESC blendDesc; + + memset(&rasterDesc,0,sizeof(rasterDesc)); + memset(&blendDesc,0,sizeof(blendDesc)); + + rasterDesc.FillMode=D3D11_FILL_SOLID; + rasterDesc.CullMode=D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise=false; + rasterDesc.DepthBias=0; + rasterDesc.DepthBiasClamp=0.0f; + rasterDesc.SlopeScaledDepthBias=0.0f; + rasterDesc.DepthClipEnable=false; + rasterDesc.ScissorEnable=false; + rasterDesc.MultisampleEnable=false; + rasterDesc.AntialiasedLineEnable=false; + result=device->CreateRasterizerState(&rasterDesc,&rsState); + if (result!=S_OK) { + logE("could not create rasterizer state! %.8x",result); + return false; + } + + blendDesc.AlphaToCoverageEnable=false; + blendDesc.IndependentBlendEnable=false; + blendDesc.RenderTarget[0].BlendEnable=true; + blendDesc.RenderTarget[0].SrcBlend=D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[0].DestBlend=D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOp=D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlendAlpha=D3D11_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha=D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOpAlpha=D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].RenderTargetWriteMask=D3D11_COLOR_WRITE_ENABLE_ALL; + result=device->CreateBlendState(&blendDesc,&omBlendState); + if (result!=S_OK) { + logE("could not create blend state! %.8x",result); + return false; + } + + createRenderTarget(); + return true; +} + +void FurnaceGUIRenderDX11::initGUI(SDL_Window* win) { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + ImGui_ImplSDL2_InitForD3D(win); + ImGui_ImplDX11_Init(device,context); +} + +bool FurnaceGUIRenderDX11::quit() { + destroyRenderTarget(); + + for (FurnaceDXTexture* i: textures) { + i->view->Release(); + i->tex->Release(); + delete i; + } + textures.clear(); + + if (swapchain!=NULL) { + swapchain->Release(); + swapchain=NULL; + } + if (context!=NULL) { + context->Release(); + context=NULL; + } + if (device!=NULL) { + device->Release(); + device=NULL; + } + return true; +} + +void FurnaceGUIRenderDX11::quitGUI() { + ImGui_ImplDX11_Shutdown(); +} diff --git a/src/gui/render/renderDX11.h b/src/gui/render/renderDX11.h new file mode 100644 index 00000000..18d8673d --- /dev/null +++ b/src/gui/render/renderDX11.h @@ -0,0 +1,103 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "../gui.h" +#ifdef INCLUDE_D3D11 +#include +#else +typedef void ID3D11DeviceContext; +typedef void ID3D11RenderTargetView; +typedef void ID3D11Buffer; +typedef void ID3D11RasterizerState; +typedef void ID3D11BlendState; +typedef void ID3D11VertexShader; +typedef void ID3D11PixelShader; +typedef void ID3D11InputLayout; +typedef void IDXGISwapChain; +#endif + +struct FurnaceDXTexture; + +class FurnaceGUIRenderDX11: public FurnaceGUIRender { + ID3D11Device* device; + ID3D11DeviceContext* context; + ID3D11RenderTargetView* renderTarget; + IDXGISwapChain* swapchain; + ID3D11RasterizerState* rsState; + ID3D11BlendState* omBlendState; + + ID3D11Buffer* quadVertex; + int outW, outH; + + // SHADERS // + // -> wipe + ID3D11VertexShader* sh_wipe_vertex; + ID3D11PixelShader* sh_wipe_fragment; + ID3D11InputLayout* sh_wipe_inputLayout; + ID3D11Buffer* sh_wipe_uniform; + struct WipeUniform { + float alpha; + float padding[7]; + }; + + bool destroyRenderTarget(); + bool createRenderTarget(); + + std::vector textures; + + public: + ImTextureID getTextureID(void* which); + bool lockTexture(void* which, void** data, int* pitch); + bool unlockTexture(void* which); + bool updateTexture(void* which, void* data, int pitch); + void* createTexture(bool dynamic, int width, int height); + bool destroyTexture(void* which); + void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode); + void setBlendMode(FurnaceGUIBlendMode mode); + void resized(const SDL_Event& ev); + void clear(ImVec4 color); + bool newFrame(); + void createFontsTexture(); + void destroyFontsTexture(); + void renderGUI(); + void wipe(float alpha); + void present(); + bool getOutputSize(int& w, int& h); + int getWindowFlags(); + void preInit(); + bool init(SDL_Window* win); + void initGUI(SDL_Window* win); + void quitGUI(); + bool quit(); + FurnaceGUIRenderDX11(): + device(NULL), + context(NULL), + renderTarget(NULL), + swapchain(NULL), + rsState(NULL), + omBlendState(NULL), + quadVertex(NULL), + outW(0), + outH(0), + sh_wipe_vertex(NULL), + sh_wipe_fragment(NULL), + sh_wipe_inputLayout(NULL), + sh_wipe_uniform(NULL) { + } +}; diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 238f37e8..5d2e1d9f 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -158,9 +158,11 @@ void FurnaceGUI::drawSampleEdit() { ImGui::Text("Name"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::PushID(2+curSample); if (ImGui::InputText("##SampleName",&sample->name)) { MARK_MODIFIED; } + ImGui::PopID(); ImGui::Separator(); @@ -1229,7 +1231,17 @@ void FurnaceGUI::drawSampleEdit() { } } - memcpy(dataT,data,sampleTexW*sampleTexH*sizeof(unsigned int)); + if ((pitch>>2)==sampleTexW) { + memcpy(dataT,data,sampleTexW*sampleTexH*sizeof(unsigned int)); + } else { + int srcY=0; + int destY=0; + for (int i=0; i>2; + } + } rend->unlockTexture(sampleTex); delete[] data; } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 9648de12..5e57640d 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1303,6 +1303,11 @@ void FurnaceGUI::drawSettings() { settings.renderBackend="SDL"; } #endif +#ifdef HAVE_RENDER_DX11 + if (ImGui::Selectable("DirectX 11",curRenderBackend=="DirectX 11")) { + settings.renderBackend="DirectX 11"; + } +#endif #ifdef HAVE_RENDER_GL if (ImGui::Selectable("OpenGL",curRenderBackend=="OpenGL")) { settings.renderBackend="OpenGL"; diff --git a/src/gui/speed.cpp b/src/gui/speed.cpp index 9cb5c72d..5557c663 100644 --- a/src/gui/speed.cpp +++ b/src/gui/speed.cpp @@ -56,7 +56,7 @@ void FurnaceGUI::drawSpeed(bool asChild) { if (tempoView) setHz/=2.5; if (setHz<1) setHz=1; if (setHz>999) setHz=999; - e->setSongRate(setHz,setHz<52); + e->setSongRate(setHz); } if (tempoView) { ImGui::SameLine();