Skip to content

Commit c407250

Browse files
committed
can explore by keys / up / down / enter / backspace
can explore by input char also better fps by display only pre filtered file list (search tag) use now virtual list mode also for big file list keep cycles to the minimum needed update readme with a gif for explain the new features
1 parent 8a2f2eb commit c407250

File tree

8 files changed

+138
-58
lines changed

8 files changed

+138
-58
lines changed

3rdparty/imgui

Submodule imgui updated 47 files

CustomImGuiFileDialogConfig.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44

55
//#define USE_IMGUI_TABLES
66

7+
#define USE_EXPLORATION_BY_KEYS
78
#include <GLFW/glfw3.h>
9+
// Up key for explore to the top
810
#define IGFD_KEY_UP GLFW_KEY_UP
11+
// Down key for explore to the bottom
912
#define IGFD_KEY_DOWN GLFW_KEY_DOWN
13+
// Enter key for open directory
1014
#define IGFD_KEY_ENTER GLFW_KEY_ENTER
15+
// BackSpace for comming back to the last directory
1116
#define IGFD_KEY_BACKSPACE GLFW_KEY_BACKSPACE
1217

1318
// widget

ImGuiFileDialog/ImGuiFileDialog.cpp

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ namespace igfd
341341
//////////////////////////////////////////////////////////////////////////////////////////////////
342342
///// CUSTOM SELECTABLE (Flashing Support) ///////////////////////////////////////////////////////
343343
//////////////////////////////////////////////////////////////////////////////////////////////////
344-
344+
#ifdef USE_EXPLORATION_BY_KEYS
345345
bool ImGuiFileDialog::FlashableSelectable(const char* label, bool selected,
346346
ImGuiSelectableFlags flags, bool vFlashing, const ImVec2& size_arg)
347347
{
@@ -466,6 +466,7 @@ namespace igfd
466466
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
467467
return pressed;
468468
}
469+
#endif
469470

470471
//////////////////////////////////////////////////////////////////////////////////////////////////
471472
///// STANDARD DIALOG ////////////////////////////////////////////////////////////////////////////
@@ -882,8 +883,8 @@ namespace igfd
882883
#endif
883884
#endif
884885
size_t countRows = m_FilteredFileList.size();
885-
ImGuiListClipper clipper(countRows, ImGui::GetFrameHeight());
886-
for(int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
886+
ImGuiListClipper clipper(countRows, ImGui::GetTextLineHeightWithSpacing());
887+
for(int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
887888
{
888889
const FileInfoStruct& infos = m_FilteredFileList[i];
889890

@@ -915,12 +916,16 @@ namespace igfd
915916
#ifdef USE_IMGUI_TABLES
916917
selectableFlags |= ImGuiSelectableFlags_SpanAllColumns;
917918
#endif
919+
bool _selectablePressed = false;
920+
#ifdef USE_EXPLORATION_BY_KEYS
918921
LocateByInputKey();
919-
bool _selectablePressed = false;
920-
bool flashed = BeginFlashItem(i);
921-
_selectablePressed = FlashableSelectable(str.c_str(), selected, selectableFlags, flashed);
922+
bool flashed = BeginFlashItem(i);
923+
_selectablePressed = FlashableSelectable(str.c_str(), selected, selectableFlags, flashed);
922924
if (flashed)
923925
EndFlashItem();
926+
#else
927+
_selectablePressed = ImGui::Selectable(str.c_str(), selected, selectableFlags);
928+
#endif
924929
if (_selectablePressed)
925930
{
926931
if (infos.type == 'd')
@@ -968,9 +973,9 @@ namespace igfd
968973
}
969974
ImGui::EndTable();
970975
#endif
971-
976+
#ifdef USE_EXPLORATION_BY_KEYS
972977
ExploreWithkeys(); // outside of file list loop
973-
978+
#endif
974979
// changement de repertoire
975980
if (pathClick)
976981
{
@@ -1665,9 +1670,10 @@ namespace igfd
16651670
}
16661671
free(files);
16671672
}
1673+
1674+
SortFields(m_SortingField);
1675+
ApplyFilteringOnFileList();
16681676
}
1669-
SortFields(m_SortingField);
1670-
ApplyFilteringOnFileList();
16711677
}
16721678

16731679
void ImGuiFileDialog::SetCurrentDir(const std::string& vPath)
@@ -1939,57 +1945,75 @@ namespace igfd
19391945
////////////////////////////////////////////////////////////////////////////////////////////////
19401946

19411947
static size_t locateFileByInputChar_lastFileIdx = 0;
1948+
static char locateFileByInputChar_lastChar = 0;
1949+
static int locateFileByInputChar_InputQueueCharactersSize = 0;
1950+
static bool locateFileByInputChar_lastFound = false;
1951+
1952+
bool ImGuiFileDialog::LocateItem_Loop(char vC)
1953+
{
1954+
bool found = false;
1955+
1956+
for (size_t i = locateFileByInputChar_lastFileIdx; i < m_FilteredFileList.size(); i++)
1957+
{
1958+
if (m_FilteredFileList[i].fileName_optimized[0] == vC || // lower case search
1959+
m_FilteredFileList[i].fileName[0] == vC) // maybe upper case search
1960+
{
1961+
float p = (float)((double)i / (double)m_FilteredFileList.size()) * ImGui::GetScrollMaxY();
1962+
ImGui::SetScrollY(p);
1963+
found = true;
1964+
locateFileByInputChar_lastFound = true;
1965+
locateFileByInputChar_lastFileIdx = i;
1966+
StartFlashItem(locateFileByInputChar_lastFileIdx);
1967+
1968+
auto infos = &m_FilteredFileList[locateFileByInputChar_lastFileIdx];
1969+
1970+
if (infos->type == 'd')
1971+
{
1972+
if (!dlg_filters) // directory chooser
1973+
{
1974+
SelectFileName(*infos);
1975+
}
1976+
}
1977+
else
1978+
{
1979+
SelectFileName(*infos);
1980+
}
19421981

1982+
found = true;
1983+
1984+
break;
1985+
}
1986+
}
1987+
1988+
return found;
1989+
}
1990+
1991+
#ifdef USE_EXPLORATION_BY_KEYS
19431992
void ImGuiFileDialog::LocateByInputKey()
19441993
{
19451994
ImGuiContext& g = *GImGui;
1946-
if (!g.ActiveId && !m_FileList.empty())
1995+
if (!g.ActiveId && !m_FilteredFileList.empty())
19471996
{
19481997
// point by char
1949-
static char locateFileByInputChar_lastChar = 0;
1950-
static int locateFileByInputChar_InputQueueCharactersSize = 0;
19511998
if (!ImGui::GetIO().InputQueueCharacters.empty())
19521999
{
19532000
char c = ImGui::GetIO().InputQueueCharacters.back();
1954-
if (locateFileByInputChar_InputQueueCharactersSize != ImGui::GetIO().InputQueueCharacters.size())
2001+
if (locateFileByInputChar_InputQueueCharactersSize !=
2002+
ImGui::GetIO().InputQueueCharacters.size())
19552003
{
19562004
if (c == locateFileByInputChar_lastChar) // next file starting with same char until
19572005
{
1958-
if (locateFileByInputChar_lastFileIdx < m_FileList.size() - 1)
2006+
if (locateFileByInputChar_lastFileIdx < m_FilteredFileList.size() - 1)
19592007
locateFileByInputChar_lastFileIdx++;
19602008
else
19612009
locateFileByInputChar_lastFileIdx = 0;
19622010
}
1963-
else // new char
1964-
{
1965-
locateFileByInputChar_lastFileIdx = 0;
1966-
}
19672011

1968-
static bool locateFileByInputChar_lastFound = false;
1969-
bool found = false;
1970-
for (size_t i = locateFileByInputChar_lastFileIdx; i < m_FileList.size(); i++)
2012+
if (!LocateItem_Loop(c))
19712013
{
1972-
if (m_FileList[i].fileName_optimized[0] == c || // lower case search
1973-
m_FileList[i].fileName[0] == c) // maybe upper case search
1974-
{
1975-
float p = (float)((double)i / (double)m_FileList.size()) * ImGui::GetScrollMaxY();
1976-
ImGui::SetScrollY(p);
1977-
found = true;
1978-
locateFileByInputChar_lastFound = true;
1979-
locateFileByInputChar_lastFileIdx = i;
1980-
StartFlashItem(locateFileByInputChar_lastFileIdx);
1981-
break;
1982-
}
1983-
1984-
if (c == locateFileByInputChar_lastChar &&
1985-
locateFileByInputChar_lastFound &&
1986-
!found &&
1987-
i == m_FileList.size() - 1) //last item and not found => new loop
1988-
{
1989-
locateFileByInputChar_lastFileIdx = 0; // cyclic next file starting with same char until
1990-
i = 0;
1991-
locateFileByInputChar_lastFound = false;
1992-
}
2014+
// not found, loop again from 0 this time
2015+
locateFileByInputChar_lastFileIdx = 0;
2016+
LocateItem_Loop(c);
19932017
}
19942018

19952019
locateFileByInputChar_lastChar = c;
@@ -2002,24 +2026,24 @@ namespace igfd
20022026
void ImGuiFileDialog::ExploreWithkeys()
20032027
{
20042028
ImGuiContext& g = *GImGui;
2005-
if (!g.ActiveId && !m_FileList.empty())
2029+
if (!g.ActiveId && !m_FilteredFileList.empty())
20062030
{
20072031
// explore
20082032
bool exploreByKey = false;
20092033
bool enterInDirectory = false;
20102034
bool exitDirectory = false;
2011-
if (ImGui::IsKeyReleased(IGFD_KEY_UP))
2035+
if (ImGui::IsKeyPressed(IGFD_KEY_UP))
20122036
{
20132037
exploreByKey = true;
20142038
if (locateFileByInputChar_lastFileIdx > 0)
20152039
{
20162040
locateFileByInputChar_lastFileIdx--;
20172041
}
20182042
}
2019-
else if (ImGui::IsKeyReleased(IGFD_KEY_DOWN))
2043+
else if (ImGui::IsKeyPressed(IGFD_KEY_DOWN))
20202044
{
20212045
exploreByKey = true;
2022-
if (locateFileByInputChar_lastFileIdx < m_FileList.size() - 1)
2046+
if (locateFileByInputChar_lastFileIdx < m_FilteredFileList.size() - 1)
20232047
{
20242048
locateFileByInputChar_lastFileIdx++;
20252049
}
@@ -2037,11 +2061,11 @@ namespace igfd
20372061

20382062
if (exploreByKey)
20392063
{
2040-
float p = (float)((double)locateFileByInputChar_lastFileIdx / (double)m_FileList.size()) * ImGui::GetScrollMaxY();
2064+
float p = (float)((double)locateFileByInputChar_lastFileIdx / (double)m_FilteredFileList.size()) * ImGui::GetScrollMaxY();
20412065
ImGui::SetScrollY(p);
20422066
StartFlashItem(locateFileByInputChar_lastFileIdx);
20432067

2044-
auto infos = &m_FileList[locateFileByInputChar_lastFileIdx];
2068+
auto infos = &m_FilteredFileList[locateFileByInputChar_lastFileIdx];
20452069

20462070
if (infos->type == 'd')
20472071
{
@@ -2079,7 +2103,7 @@ namespace igfd
20792103
{
20802104
// changement de repertoire
20812105
SetPath(m_CurrentPath);
2082-
if (locateFileByInputChar_lastFileIdx > m_FileList.size() - 1)
2106+
if (locateFileByInputChar_lastFileIdx > m_FilteredFileList.size() - 1)
20832107
{
20842108
locateFileByInputChar_lastFileIdx = 0;
20852109
}
@@ -2111,7 +2135,7 @@ namespace igfd
21112135
if (m_FlashedItem == vIdx &&
21122136
std::abs(m_FlashAlpha - 0.0f) > 0.00001f)
21132137
{
2114-
m_FlashAlpha -= m_FlashAlphaStep;
2138+
m_FlashAlpha -= m_FlashAlphaAttenInSecs * ImGui::GetIO().DeltaTime;
21152139
if (m_FlashAlpha < 0.0f) m_FlashAlpha = 0.0f;
21162140

21172141
ImVec4 hov = ImGui::GetStyleColorVec4(ImGuiCol_HeaderHovered);
@@ -2127,5 +2151,11 @@ namespace igfd
21272151
{
21282152
ImGui::PopStyleColor();
21292153
}
2154+
2155+
void ImGuiFileDialog::SetFlashingAttenuationInSeconds(float vAttenValue)
2156+
{
2157+
m_FlashAlphaAttenInSecs = 1.0f / max(vAttenValue,0.01f);
2158+
}
2159+
#endif
21302160
}
21312161

ImGuiFileDialog/ImGuiFileDialog.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ SOFTWARE.
2424

2525
#pragma once
2626

27-
#define IMGUIFILEDIALOG_VERSION "v0.2"
27+
#define IMGUIFILEDIALOG_VERSION "v0.3"
2828

2929
#include <imgui.h>
3030

@@ -64,15 +64,13 @@ namespace igfd
6464
size_t fileSize = 0; // for sorting operations
6565
std::string formatedFileSize;
6666
std::string fileModifDate;
67-
6867
};
6968

7069
// old FilterInfosStruct
7170
struct FileExtentionInfosStruct
7271
{
7372
std::string icon;
7473
ImVec4 color = ImVec4(0, 0, 0, 0);
75-
7674
FileExtentionInfosStruct() { color = ImVec4(0, 0, 0, 0); }
7775
FileExtentionInfosStruct(const ImVec4& vColor, const std::string& vIcon = std::string())
7876
{
@@ -109,7 +107,7 @@ namespace igfd
109107

110108
enum SortingFieldEnum
111109
{
112-
FIELD_NONE=0,
110+
FIELD_NONE = 0,
113111
FIELD_FILENAME,
114112
FIELD_SIZE,
115113
FIELD_DATE
@@ -134,7 +132,7 @@ namespace igfd
134132
private: // flash when select by char
135133
size_t m_FlashedItem = 0;
136134
float m_FlashAlpha = 0.0f;
137-
float m_FlashAlphaStep = 0.01f; // fps display dependant
135+
float m_FlashAlphaAttenInSecs = 1.0f; // fps display dependant
138136

139137
public:
140138
static char FileNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER];
@@ -210,6 +208,7 @@ namespace igfd
210208
const std::string& vFilePathName, const int& vCountSelectionMax = 1,
211209
UserDatas vUserDatas = 0);
212210

211+
public: // core
213212
bool FileDialog(const std::string& vKey, ImGuiWindowFlags vFlags = ImGuiWindowFlags_NoCollapse,
214213
ImVec2 vMinSize = ImVec2(0, 0), ImVec2 vMaxSize = ImVec2(FLT_MAX, FLT_MAX));
215214
void CloseDialog(const std::string& vKey);
@@ -246,13 +245,18 @@ namespace igfd
246245
private:
247246
void ApplyFilteringOnFileList();
248247

248+
#ifdef USE_EXPLORATION_BY_KEYS
249249
private: // file localization by input chat // widget flashing
250250
void LocateByInputKey();
251+
bool LocateItem_Loop(char vC);
251252
void ExploreWithkeys();
252253
static bool FlashableSelectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0,
253254
bool vFlashing = false, const ImVec2& size = ImVec2(0, 0));
254255
void StartFlashItem(size_t vIdx);
255256
bool BeginFlashItem(size_t vIdx);
256257
void EndFlashItem();
258+
public:
259+
void SetFlashingAttenuationInSeconds(float vAttenValue);
260+
#endif
257261
};
258262
}

ImGuiFileDialog/ImGuiFileDialogConfig.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44

55
//#define USE_IMGUI_TABLES
66

7-
//#include <GLFW/glfw3.h>
7+
//#define USE_EXPLORATION_BY_KEYS
8+
// this mapping by default is for GLFW but you can use another
9+
//#include <GLFW/glfw3.h>
10+
// Up key for explore to the top
811
//#define IGFD_KEY_UP GLFW_KEY_UP
12+
// Down key for explore to the bottom
913
//#define IGFD_KEY_DOWN GLFW_KEY_DOWN
14+
// Enter key for open directory
1015
//#define IGFD_KEY_ENTER GLFW_KEY_ENTER
16+
// BackSpace for comming back to the last directory
1117
//#define IGFD_KEY_BACKSPACE GLFW_KEY_BACKSPACE
1218

1319
// widget

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ An example of the File Dialog integrated within the ImGui Demo App
1818
- Support of Modal/Standard dialog type
1919
- Support both Mode : File Chooser or Directory Chooser
2020
- Support filter collection / Custom filter name
21+
- Support files Exploring with keys : Up / Down / Enter (open dir) / Backspace (come back)
22+
- Support files Exploring by input char (case insensitive)
2123

2224
Use the Namespace igfd (for avoid conflict with variables, struct and class names)
2325

@@ -186,6 +188,25 @@ You can have tables display like that.
186188
187189
![alt text](doc/imgui_tables_branch.gif)
188190
191+
## Exploring by keys
192+
193+
you can activate this feature by uncomment "#define USE_EXPLORATION_BY_KEYS" in you custom config file (CustomImGuiFileDialogConfig.h in this example)
194+
you can also uncomment the next lines for define your keys :
195+
*IGFD_KEY_UP => Up key for explore to the top
196+
*IGFD_KEY_DOWN => Down key for explore to the bottom
197+
*IGFD_KEY_ENTER => Enter key for open directory
198+
*IGFD_KEY_BACKSPACE => BackSpace for comming back to the last directory
199+
200+
you can also explore a file list by use the current key char.
201+
202+
![alt text](doc/explore_ny_keys.gif)
203+
204+
as you see the current item is flashed (by default for 1 sec)
205+
you can define the flashing life time by yourself with the function
206+
```cpp
207+
igfd::ImGuiFileDialog::Instance()->SetFlashingAttenuationInSeconds(1.0f);
208+
```
209+
189210
## How to Integrate ImGuiFileDialog in your porject
190211

191212
### ImGuiFileDialog require :

doc/explore_ny_keys.gif

1.94 MB
Loading

0 commit comments

Comments
 (0)