OXYGENHUB
◆ main openmsx / src / 3rdparty / ImGuiFileDialog / ImGuiFileDialog.h
106.7 KiB · Objective-C · last changed chore(): initial commit 1 month ago source blame history raw
1
#pragma once
2
3
#if defined(__clang__)
4
#pragma clang diagnostic ignored "-Wunknown-pragmas"
5
#elif defined(__GNUC__)
6
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
7
#endif
8
9
#ifdef _MSC_VER
10
#pragma warning(disable : 4251)
11
#endif
12
13
#pragma region IGFD LICENSE
14
15
/*
16
MIT License
17
18
Copyright (c) 2018-2023 Stephane Cuillerdier (aka aiekick)
19
20
Permission is hereby granted, free of charge, to any person obtaining a copy
21
of this software and associated documentation files (the "Software"), to deal
22
in the Software without restriction, including without limitation the rights
23
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
copies of the Software, and to permit persons to whom the Software is
25
furnished to do so, subject to the following conditions:
26
27
The above copyright notice and this permission notice shall be included in all
28
copies or substantial portions of the Software.
29
30
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
SOFTWARE.
37
*/
38
39
#pragma endregion
40
41
#pragma region IGFD DOCUMENTATION
42
43
/*
44
// generated with "Text to ASCII Art Generator (TAAG)"
45
// https://patorjk.com/software/taag/#p=display&h=1&v=0&f=Big&t=ImGuiFileDialog%0Av0.6.7
46
  _____              _____         _  ______  _  _        _____   _         _
47
 |_   _|            / ____|       (_)|  ____|(_)| |      |  __ \ (_)       | |
48
   | |   _ __ ___  | |  __  _   _  _ | |__    _ | |  ___ | |  | | _   __ _ | |  ___    __ _
49
   | |  | '_ ` _ \ | | |_ || | | || ||  __|  | || | / _ \| |  | || | / _` || | / _ \  / _` |
50
  _| |_ | | | | | || |__| || |_| || || |     | || ||  __/| |__| || || (_| || || (_) || (_| |
51
 |_____||_| |_| |_| \_____| \__,_||_||_|     |_||_| \___||_____/ |_| \__,_||_| \___/  \__, |
52
                                                                                       __/ |
53
                                                                                      |___/
54
                                  ___      __    ______
55
                                 / _ \    / /   |____  |
56
                         __   __| | | |  / /_       / /
57
                         \ \ / /| | | | | '_ \     / /
58
                          \ V / | |_| |_| (_) |_  / /
59
                           \_/   \___/(_)\___/(_)/_/
60
61
github repo : https://github.com/aiekick/ImGuiFileDialog
62
this section is the content of the ReadMe.md file
63
64
# ImGuiFileDialog
65
66
## Purpose
67
68
ImGuiFileDialog is a file selection dialog built for (and using only) [Dear ImGui](https://github.com/ocornut/imgui).
69
70
My primary goal was to have a custom pane with widgets according to file extension. This was not possible using other
71
solutions.
72
73
## ImGui Supported Version
74
75
ImGuiFileDialog follow the master and docking branch of ImGui . currently ImGui 1.90.1 WIP
76
77
## Structure
78
79
* The library is in [Lib_Only branch](https://github.com/aiekick/ImGuiFileDialog/tree/Lib_Only)
80
* A demo app can be found the [master branch](https://github.com/aiekick/ImGuiFileDialog/tree/master)
81
82
This library is designed to be dropped into your source code rather than compiled separately.
83
84
From your project directory:
85
86
```
87
mkdir lib    <or 3rdparty, or externals, etc.>
88
cd lib
89
git clone https://github.com/aiekick/ImGuiFileDialog.git
90
git checkout Lib_Only
91
```
92
93
These commands create a `lib` directory where you can store any third-party dependencies used in your project, downloads
94
the ImGuiFileDialog git repository and checks out the Lib_Only branch where the actual library code is located.
95
96
Add `lib/ImGuiFileDialog/ImGuiFileDialog.cpp` to your build system and include
97
`lib/ImGuiFileDialog/ImGuiFileDialog.h` in your source code. ImGuiFileLib will compile with and be included directly in
98
your executable file.
99
100
If, for example, your project uses cmake, look for a line like `add_executable(my_project_name main.cpp)`
101
and change it to `add_executable(my_project_name lib/ImGuiFileDialog/ImGuiFileDialog.cpp main.cpp)`. This tells the
102
compiler where to find the source code declared in `ImGuiFileDialog.h` which you included in your own source code.
103
104
## Requirements:
105
106
You must also, of course, have added [Dear ImGui](https://github.com/ocornut/imgui) to your project for this to work at
107
all.
108
109
[dirent v1.23](https://github.com/tronkko/dirent/tree/v1.23) is required to use ImGuiFileDialog under Windows. It is
110
included in the Lib_Only branch for your convenience.
111
112
################################################################
113
## Features
114
################################################################
115
116
- C Api (succesfully tested with CimGui)
117
- Separate system for call and display
118
    - Can have many function calls with different parameters for one display function, for example
119
- Can create a custom pane with any widgets via function binding
120
    - This pane can block the validation of the dialog
121
    - Can also display different things according to current filter and UserDatas
122
- Advanced file style for file/dir/link coloring / icons / font
123
    - predefined form or user custom form by lambda function (the lambda mode is not available for the C API)
124
- Multi-selection (ctrl/shift + click) :
125
    - 0 => Infinite
126
    - 1 => One file (default)
127
    - n => n files
128
- Compatible with MacOs, Linux, Windows
129
    - Windows version can list drives
130
- Supports modal or standard dialog types
131
- Select files or directories
132
- Filter groups and custom filter names
133
- can ignore filter Case for file searching
134
- Keyboard navigation (arrows, backspace, enter)
135
- Exploring by entering characters (case insensitive)
136
- Directory bookmarks
137
- Directory manual entry (right click on any path element)
138
- Optional 'Confirm to Overwrite" dialog if file exists
139
- Thumbnails Display (agnostic way for compatibility with any backend, sucessfully tested with OpenGl and Vulkan)
140
- The dialog can be embedded in another user frame than the standard or modal dialog
141
- Can tune validation buttons (placements, widths, inversion)
142
- Can quick select a parrallel directory of a path, in the path composer (when you clikc on a / you have a popup)
143
- regex support for filters, collection of filters and filestyle (the regex is recognized when between (( and )) in a
144
filter)
145
- multi layer extentions like : .a.b.c .json.cpp .vcxproj.filters etc..
146
- advanced behavior regarding asterisk based filter. like : .* .*.* .vcx.* .*.filters .vcs*.filt.* etc.. (internally
147
regex is used)
148
- result modes GetFilePathName, GetFileName and GetSelection (overwrite file ext, keep file, add ext if no user ext
149
exist)
150
151
################################################################
152
## Filter format
153
################################################################
154
155
A filter is recognized only if he respects theses rules :
156
157
0) a filter must have 2 chars mini and the first must be a .
158
1) a regex must be in (( and ))
159
2) a , will separate filters except if between a ( and )
160
3) name{filter1, filter2} is a special form for collection filters
161
   - the name can be composed of what you want except { and }
162
   - a filter can be a regex
163
4) the filters cannot integrate these chars '(' ')' '{' '}' ' ' except for a regex with respect to rule 1)
164
5) the filters cannot integrate a ','
165
166
################################################################
167
## Singleton Pattern vs. Multiple Instances
168
################################################################
169
170
### Single Dialog :
171
172
If you only need to display one file dialog at a time, use ImGuiFileDialog's singleton pattern to avoid explicitly
173
declaring an object:
174
175
```cpp
176
ImGuiFileDialog::Instance()->method_of_your_choice();
177
```
178
179
### Multiple Dialogs :
180
181
If you need to have multiple file dialogs open at once, declare each dialog explicity:
182
183
```cpp
184
ImGuiFileDialog instance_a;
185
instance_a.method_of_your_choice();
186
ImGuiFileDialog instance_b;
187
instance_b.method_of_your_choice();
188
```
189
190
################################################################
191
## Simple Dialog :
192
################################################################
193
194
```cpp
195
void drawGui()
196
{
197
  // open Dialog Simple
198
  if (ImGui::Button("Open File Dialog"))
199
    IGFD::FileDialogConfig config;
200
    config.path = ".";
201
    ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config);
202
203
  // display
204
  if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey"))
205
  {
206
    // action if OK
207
    if (ImGuiFileDialog::Instance()->IsOk())
208
    {
209
      std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
210
      std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
211
      // action
212
    }
213
214
    // close
215
    ImGuiFileDialog::Instance()->Close();
216
  }
217
}
218
```
219
220
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/dlg_simple.gif)
221
222
################################################################
223
## Modal dialog :
224
################################################################
225
226
you have now a flag for open modal dialog :
227
228
```cpp
229
ImGuiFileDialogFlags_Modal
230
```
231
232
you can use it like that :
233
234
```cpp
235
IGFD::FileDialogConfig config;
236
config.path = ".";
237
config.countSelectionMax = 1;
238
config.flags = ImGuiFileDialogFlags_Modal;
239
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config);
240
```
241
242
################################################################
243
## Directory Chooser :
244
################################################################
245
246
To have a directory chooser, set the file extension filter to nullptr:
247
248
```cpp
249
IGFD::FileDialogConfig config;
250
config.path = ".";
251
ImGuiFileDialog::Instance()->OpenDialog("ChooseDirDlgKey", "Choose a Directory", nullptr, config);
252
```
253
254
In this mode you can select any directory with one click and open a directory with a double-click.
255
256
![directoryChooser](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/directoryChooser.gif)
257
258
################################################################
259
## Dialog with Custom Pane :
260
################################################################
261
262
The signature of the custom pane callback is:
263
264
### for C++ :
265
266
```cpp
267
void(const char *vFilter, IGFDUserDatas vUserDatas, bool *vCantContinue)
268
```
269
270
### for C :
271
272
```c
273
void(const char *vFilter, void* vUserDatas, bool *vCantContinue)
274
```
275
276
### Example :
277
278
```cpp
279
static bool canValidateDialog = false;
280
inline void InfosPane(cosnt char *vFilter, IGFDUserDatas vUserDatas, bool *vCantContinue) // if vCantContinue is false,
281
the user cant validate the dialog
282
{
283
    ImGui::TextColored(ImVec4(0, 1, 1, 1), "Infos Pane");
284
    ImGui::Text("Selected Filter : %s", vFilter.c_str());
285
    if (vUserDatas)
286
        ImGui::Text("UserDatas : %s", vUserDatas);
287
    ImGui::Checkbox("if not checked you cant validate the dialog", &canValidateDialog);
288
    if (vCantContinue)
289
        *vCantContinue = canValidateDialog;
290
}
291
292
void drawGui()
293
{
294
  // open Dialog with Pane
295
  if (ImGui::Button("Open File Dialog with a custom pane")) {
296
	IGFD::FileDialogConfig config;
297
	config.path = ".";
298
	config.countSelectionMax = 1;
299
	config.sidePane = std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
300
	config.sidePaneWidth = 350.0f;
301
	config.useDatas = UserDatas("InfosPane");
302
	config.flags = ImGuiFileDialogFlags_Modal;
303
    ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config);
304
  }
305
306
  // display and action if ok
307
  if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey"))
308
  {
309
    if (ImGuiFileDialog::Instance()->IsOk())
310
    {
311
        std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
312
        std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
313
        std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter();
314
        // here convert from string because a string was passed as a userDatas, but it can be what you want
315
        std::string userDatas;
316
        if (ImGuiFileDialog::Instance()->GetUserDatas())
317
            userDatas = std::string((const char*)ImGuiFileDialog::Instance()->GetUserDatas());
318
        auto selection = ImGuiFileDialog::Instance()->GetSelection(); // multiselection
319
320
        // action
321
    }
322
    // close
323
    ImGuiFileDialog::Instance()->Close();
324
  }
325
}
326
```
327
328
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/doc/dlg_with_pane.gif)
329
330
################################################################
331
## File Style : Custom icons and colors by extension
332
################################################################
333
334
You can define style for files/dirs/links in many ways :
335
336
the style can be colors, icons and fonts
337
338
the general form is :
339
```cpp
340
ImGuiFileDialog::Instance()->SetFileStyle(styleType, criteria, color, icon, font);
341
```
342
343
### Predefined Form :
344
345
styleType can be thoses :
346
347
```cpp
348
IGFD_FileStyleByTypeFile				// define style for all files
349
IGFD_FileStyleByTypeDir					// define style for all dir
350
IGFD_FileStyleByTypeLink				// define style for all link
351
IGFD_FileStyleByExtention				// define style by extention, for files or links
352
IGFD_FileStyleByFullName				// define style for particular file/dir/link full name (filename + extention)
353
IGFD_FileStyleByContainedInFullName		// define style for file/dir/link when criteria is contained in full name
354
```
355
356
### Lambda Function Form :
357
358
You can define easily your own style include your own detection by using lambda function :
359
360
** To note, this mode is not available with the C API **
361
362
this lamba will treat a file and return a shared pointer of your files style
363
364
see in action a styling of all files and dir starting by a dot
365
366
this lambda input a FileInfos and output a FileStyle
367
return true if a FileStyle was defined
368
369
```cpp
370
ImGuiFileDialog::Instance()->SetFileStyle([](const IGFD::FileInfos& vFile, IGFD::FileStyle &vOutStyle) -> bool {
371
    if (!vFile.fileNameExt.empty() && vFile.fileNameExt[0] == '.') {
372
        vOutStyle = IGFD::FileStyle(ImVec4(0.0f, 0.9f, 0.9f, 1.0f), ICON_IGFD_REMOVE);
373
        return true;
374
    }
375
    return false;
376
});
377
```
378
379
see sample app for the code in action
380
381
### Samples :
382
383
ImGuiFileDialog accepts icon font macros as well as text tags for file types.
384
385
[ImGuIFontStudio](https://github.com/aiekick/ImGuiFontStudio) is useful here. I wrote it to make it easy to create
386
custom icon sets for use with Dear ImGui.
387
388
It is inspired by [IconFontCppHeaders](https://github.com/juliettef/IconFontCppHeaders), which can also be used with
389
ImGuiFileDialog.
390
391
samples :
392
393
```cpp
394
// define style by file extention and Add an icon for .png files
395
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".png", ImVec4(0.0f, 1.0f, 1.0f, 0.9f),,ICON_IGFD_FILE_PIC, font1); 
396
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".gif", ImVec4(0.0f, 1.0f, 0.5f, 0.9f), "[GIF]");
397
398
// define style for all directories
399
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FOLDER);
400
// can be for a specific directory
401
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, ".git", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FOLDER);
402
403
// define style for all files
404
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FILE);
405
// can be for a specific file
406
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, ".git", ImVec4(0.5f, 1.0f, 0.9f, 0.9f),
407
ICON_IGFD_FILE);
408
409
// define style for all links
410
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeLink, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f));
411
// can be for a specific link
412
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeLink, "Readme.md", ImVec4(0.5f, 1.0f, 0.9f, 0.9f));
413
414
// define style for any files/dirs/links by fullname
415
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByFullName, "doc", ImVec4(0.9f, 0.2f, 0.0f, 0.9f),
416
ICON_IGFD_FILE_PIC);
417
418
// define style by file who are containing this string
419
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByContainedInFullName, ".git", ImVec4(0.9f, 0.2f, 0.0f, 0.9f),
420
ICON_IGFD_BOOKMARK);
421
422
all of theses can be miwed with IGFD_FileStyleByTypeDir / IGFD_FileStyleByTypeFile / IGFD_FileStyleByTypeLink
423
like theses by ex :
424
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir | IGFD_FileStyleByContainedInFullName, ".git",
425
ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_BOOKMARK); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile
426
| IGFD_FileStyleByFullName, "cmake", ImVec4(0.5f, 0.8f, 0.5f, 0.9f), ICON_IGFD_SAVE);
427
428
// for all these,s you can use a regex
429
// ex for color files like Custom*.h
430
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByFullName, "((Custom.+[.]h))", ImVec4(0.0f, 1.0f, 1.0f, 0.9f),
431
ICON_IGFD_FILE_PIC, font1);
432
433
// lambda function
434
// set file style with a lambda function
435
// return true is a file style was defined
436
ImGuiFileDialog::Instance()->SetFileStyle([](const IGFD::FileInfos& vFile, IGFD::FileStyle &vOutStyle) -> bool {
437
    if (!vFile.fileNameExt.empty() && vFile.fileNameExt[0] == '.') {
438
        vOutStyle = IGFD::FileStyle(ImVec4(0.0f, 0.9f, 0.9f, 1.0f), ICON_IGFD_REMOVE);
439
        return true;
440
    }
441
    return false;
442
});
443
```
444
445
this sample code of [master/main.cpp](https://github.com/aiekick/ImGuiFileDialog/blob/master/main.cpp) produce the
446
picture above :
447
448
```cpp
449
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".cpp", ImVec4(1.0f, 1.0f, 0.0f, 0.9f));
450
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".h", ImVec4(0.0f, 1.0f, 0.0f, 0.9f));
451
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".hpp", ImVec4(0.0f, 0.0f, 1.0f, 0.9f));
452
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".md", ImVec4(1.0f, 0.0f, 1.0f, 0.9f));
453
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".png", ImVec4(0.0f, 1.0f, 1.0f, 0.9f),
454
ICON_IGFD_FILE_PIC); // add an icon for the filter type
455
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".gif", ImVec4(0.0f, 1.0f, 0.5f, 0.9f), "[GIF]");
456
// add an text for a filter type ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, nullptr,
457
ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FOLDER); // for all dirs
458
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, "CMakeLists.txt", ImVec4(0.1f, 0.5f, 0.5f, 0.9f),
459
ICON_IGFD_ADD); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByFullName, "doc", ImVec4(0.9f, 0.2f, 0.0f,
460
0.9f), ICON_IGFD_FILE_PIC); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir |
461
IGFD_FileStyleByContainedInFullName, ".git", ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_BOOKMARK);
462
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile | IGFD_FileStyleByContainedInFullName, ".git",
463
ImVec4(0.5f, 0.8f, 0.5f, 0.9f), ICON_IGFD_SAVE);
464
```
465
466
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/color_filter.png)
467
468
469
################################################################
470
## Filter Collections
471
################################################################
472
473
You can define a custom filter name that corresponds to a group of filters using this syntax:
474
475
```custom_name1{filter1,filter2,filter3},custom_name2{filter1,filter2},filter1```
476
477
When you select custom_name1, filters 1 to 3 will be applied. The characters `{` and `}` are reserved. Don't use them
478
for filter names.
479
480
this code :
481
482
```cpp
483
const char *filters = "Source files (*.cpp *.h *.hpp){.cpp,.h,.hpp},Image files (*.png *.gif *.jpg *.jpeg){.png,.gif,.jpg,.jpeg},.md";
484
IGFD::FileDialogConfig config;
485
config.path = ".";
486
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", ICON_IMFDLG_FOLDER_OPEN " Choose a File", filters, config);
487
```
488
489
490
will produce :
491
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/filters.gif)
492
493
################################################################
494
## Multi Selection
495
################################################################
496
497
You can define in OpenDialog call the count file you want to select :
498
499
- 0 => infinite
500
- 1 => one file only (default)
501
- n => n files only
502
503
See the define at the end of these funcs after path.
504
505
```cpp
506
IGFD::FileDialogConfig config; config.path = ".";
507
508
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".*,.cpp,.h,.hpp", config);
509
510
config.countSelectionMax = 1;
511
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose 1 File", ".*,.cpp,.h,.hpp", config);
512
513
config.countSelectionMax = 5;
514
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose 5 File", ".*,.cpp,.h,.hpp", config);
515
516
config.countSelectionMax = 0;
517
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose many File", ".*,.cpp,.h,.hpp", config);
518
519
config.countSelectionMax = 1;
520
config.sidePane = std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
521
config.sidePaneWidth = 350.0f;
522
config.useDatas = UserDatas("SaveFile");
523
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".png,.jpg", config); // 1 file
524
```
525
526
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/multiSelection.gif)
527
528
################################################################
529
## File Dialog Constraints
530
################################################################
531
532
You can set the minimum and/or maximum size of the dialog:
533
534
```cpp
535
ImVec2 maxSize = ImVec2((float)display_w, (float)display_h);  // The full display area
536
ImVec2 minSize = maxSize * 0.5f;  // Half the display area
537
ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey", ImGuiWindowFlags_NoCollapse, minSize, maxSize);
538
```
539
540
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/dialog_constraints.gif)
541
542
################################################################
543
## Exploring by keys
544
################################################################
545
546
You can activate this feature by uncommenting `#define USE_EXPLORATION_BY_KEYS`
547
in your custom config file (CustomImGuiFileDialogConfig.h)
548
549
You can also uncomment the next lines to define navigation keys:
550
551
* IGFD_KEY_UP => Up key for explore to the top
552
* IGFD_KEY_DOWN => Down key for explore to the bottom
553
* IGFD_KEY_ENTER => Enter key for open directory
554
* IGFD_KEY_BACKSPACE => BackSpace for comming back to the last directory
555
556
You can also jump to a point in the file list by pressing the corresponding key of the first filename character.
557
558
![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/explore_ny_keys.gif)
559
560
As you see the current item is flashed by default for 1 second. You can define the flashing lifetime with the function
561
562
```cpp
563
ImGuiFileDialog::Instance()->SetFlashingAttenuationInSeconds(1.0f);
564
```
565
566
################################################################
567
## Bookmarks
568
################################################################
569
570
You can create/edit/call path bookmarks and load/save them.
571
572
Activate this feature by uncommenting: `#define USE_BOOKMARK` in your custom config file (CustomImGuiFileDialogConfig.h)
573
574
More customization options:
575
576
```cpp
577
#define bookmarkPaneWith 150.0f => width of the bookmark pane
578
#define IMGUI_TOGGLE_BUTTON ToggleButton => customize the Toggled button (button stamp must be : (const char* label,
579
bool *toggle) #define bookmarksButtonString "Bookmark" => the text in the toggle button #define
580
bookmarksButtonHelpString "Bookmark" => the helper text when mouse over the button #define addBookmarkButtonString "+"
581
=> the button for add a bookmark #define removeBookmarkButtonString "-" => the button for remove the selected bookmark
582
```
583
584
* You can select each bookmark to edit the displayed name corresponding to a path
585
* Double-click on the label to apply the bookmark
586
587
![bookmarks.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/bookmarks.gif)
588
589
You can also serialize/deserialize bookmarks (for example to load/save from/to a file):
590
```cpp
591
Load => ImGuiFileDialog::Instance()->DeserializeBookmarks(bookmarString);
592
Save => std::string bookmarkString = ImGuiFileDialog::Instance()->SerializeBookmarks();
593
```
594
(please see example code for details)
595
596
you can also add/remove bookmark by code :
597
and in this case, you can also avoid serialization of code based bookmark
598
599
```cpp
600
Add => ImGuiFileDialog::Instance()->AddBookmark(bookmark_name, bookmark_path);
601
Remove => ImGuiFileDialog::Instance()->RemoveBookmark(bookmark_name);
602
Save => std::string bookmarkString = ImGuiFileDialog::Instance()->SerializeBookmarks(true); // true for prevent
603
serialization of code based bookmarks
604
```
605
606
################################################################
607
## Path Edition :
608
################################################################
609
610
Right clicking on any path element button allows the user to manually edit the path from that portion of the tree.
611
Pressing the completion key (GLFW uses `enter` by default) validates the new path. Pressing the cancel key (GLFW
612
uses`escape` by default) cancels the manual entry and restores the original path.
613
614
Here's the manual entry operation in action:
615
![inputPathEdition.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/inputPathEdition.gif)
616
617
################################################################
618
## Confirm Overwrite Dialog :
619
################################################################
620
621
If you want avoid overwriting files after selection, ImGuiFileDialog can show a dialog to confirm or cancel the
622
operation.
623
624
To do so, define the flag ImGuiFileDialogFlags_ConfirmOverwrite in your call to OpenDialog.
625
626
By default this flag is not set since there is no pre-defined way to define if a dialog will be for Open or Save
627
behavior. (by design! :) )
628
629
Example code For Standard Dialog :
630
631
```cpp
632
IGFD::FileDialogConfig config;
633
config.path = ".";
634
config.flags = ImGuiFileDialogFlags_ConfirmOverwrite;
635
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey",
636
    ICON_IGFD_SAVE " Choose a File", filters, config);
637
```
638
639
Example code For Modal Dialog :
640
641
```cpp
642
IGFD::FileDialogConfig config;
643
config.path = ".";
644
config.flags = ImGuiFileDialogFlags_Modal | ImGuiFileDialogFlags_ConfirmOverwrite;
645
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", ICON_IGFD_SAVE " Choose a File", filters, config);
646
```
647
648
This dialog will only verify the file in the file field, not with `GetSelection()`.
649
650
The confirmation dialog will be a non-movable modal (input blocking) dialog displayed in the middle of the current
651
ImGuiFileDialog window.
652
653
As usual, you can customize the dialog in your custom config file (CustomImGuiFileDialogConfig.h in this example)
654
655
Uncomment these line for customization options:
656
657
```cpp
658
//#define OverWriteDialogTitleString "The file Already Exist !"
659
//#define OverWriteDialogMessageString "Would you like to OverWrite it ?"
660
//#define OverWriteDialogConfirmButtonString "Confirm"
661
//#define OverWriteDialogCancelButtonString "Cancel"
662
```
663
664
See the result :
665
666
![ConfirmToOverWrite.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/ConfirmToOverWrite.gif)
667
668
################################################################
669
## Open / Save dialog Behavior :
670
################################################################
671
672
ImGuiFileDialog uses the same code internally for Open and Save dialogs. To distinguish between them access the various
673
data return functions depending on what the dialog is doing.
674
675
When selecting an existing file (for example, a Load or Open dialog), use
676
677
```cpp
678
std::map<std::string, std::string> GetSelection(); // Returns selection via a map<FileName, FilePathName>
679
UserDatas GetUserDatas();                          // Get user data provided by the Open dialog
680
```
681
682
To selecting a new file (for example, a Save As... dialog), use:
683
684
```cpp
685
std::string GetFilePathName();                     // Returns the content of the selection field with current file
686
extension and current path std::string GetCurrentFileName();                  // Returns the content of the selection
687
field with current file extension but no path std::string GetCurrentPath();                      // Returns current path
688
only std::string GetCurrentFilter();                    // The file extension
689
```
690
691
################################################################
692
## Thumbnails Display
693
################################################################
694
695
You can now, display thumbnails of pictures.
696
697
![thumbnails.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/thumbnails.gif)
698
699
The file resize use stb/image so the following files extentions are supported :
700
 * .png (tested sucessfully)
701
 * .bmp (tested sucessfully)
702
 * .tga (tested sucessfully)
703
 * .jpg (tested sucessfully)
704
 * .jpeg (tested sucessfully)
705
 * .gif (tested sucessfully_ but not animation just first frame)
706
 * .psd (not tested)
707
 * .pic (not tested)
708
 * .ppm (not tested)
709
 * .pgm (not tested)
710
711
Corresponding to your backend (ex : OpenGl) you need to define two callbacks :
712
* the first is a callback who will be called by ImGuiFileDialog for create the backend texture
713
* the second is a callback who will be called by ImGuiFileDialog for destroy the backend texture
714
715
After that you need to call the function who is responsible to create / destroy the textures.
716
this function must be called in your GPU Rendering zone for avoid destroying of used texture.
717
if you do that at the same place of your imgui code, some backend can crash your app, by ex with vulkan.
718
719
To Clarify :
720
721
This feature is spliited in two zones :
722
 - CPU Zone : for load/destroy picture file
723
 - GPU Zone : for load/destroy gpu textures.
724
This modern behavior for avoid destroying of used texture,
725
was needed for vulkan.
726
727
This feature was Successfully tested on my side with Opengl and Vulkan.
728
But im sure is perfectly compatible with other modern apis like DirectX and Metal
729
730
ex, for opengl :
731
732
```cpp
733
// Create thumbnails texture
734
ImGuiFileDialog::Instance()->SetCreateThumbnailCallback([](IGFD_Thumbnail_Info *vThumbnail_Info) -> void
735
{
736
    if (vThumbnail_Info &&
737
        vThumbnail_Info->isReadyToUpload &&
738
        vThumbnail_Info->textureFileDatas)
739
    {
740
        GLuint textureId = 0;
741
        glGenTextures(1, &textureId);
742
        vThumbnail_Info->textureID = (void*)textureId;
743
744
        glBindTexture(GL_TEXTURE_2D, textureId);
745
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
746
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
747
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
748
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
749
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
750
            (GLsizei)vThumbnail_Info->textureWidth, (GLsizei)vThumbnail_Info->textureHeight,
751
            0, GL_RGBA, GL_UNSIGNED_BYTE, vThumbnail_Info->textureFileDatas);
752
        glFinish();
753
        glBindTexture(GL_TEXTURE_2D, 0);
754
755
        delete[] vThumbnail_Info->textureFileDatas;
756
        vThumbnail_Info->textureFileDatas = nullptr;
757
758
        vThumbnail_Info->isReadyToUpload = false;
759
        vThumbnail_Info->isReadyToDisplay = true;
760
    }
761
});
762
```
763
764
```cpp
765
// Destroy thumbnails texture
766
ImGuiFileDialog::Instance()->SetDestroyThumbnailCallback([](IGFD_Thumbnail_Info* vThumbnail_Info)
767
{
768
    if (vThumbnail_Info)
769
    {
770
        GLuint texID = (GLuint)vThumbnail_Info->textureID;
771
        glDeleteTextures(1, &texID);
772
        glFinish();
773
    }
774
});
775
```
776
777
```cpp
778
// GPU Rendering Zone // To call for Create/ Destroy Textures
779
ImGuiFileDialog::Instance()->ManageGPUThumbnails();
780
```
781
782
################################################################
783
## Embedded in other frames :
784
################################################################
785
786
The dialog can be embedded in another user frame than the standard or modal dialog
787
788
You have to create a variable of type ImGuiFileDialog. (if you are using the singleton, you will not have the
789
possibility to open other dialog)
790
791
ex :
792
793
```cpp
794
ImGuiFileDialog fileDialog;
795
796
// open dialog; in this case, Bookmark, directory creation are disabled with, and also the file input field is readonly.
797
// btw you can od what you want
798
IGFD::FileDialogConfig config;
799
config.path = ".";
800
config.countSelectionMax = -1;
801
config.flags = ImGuiFileDialogFlags_NoDialog |
802
    ImGuiFileDialogFlags_DisableBookmarkMode |
803
    ImGuiFileDialogFlags_DisableCreateDirectoryButton |
804
    ImGuiFileDialogFlags_ReadOnlyFileNameField);
805
fileDialog.OpenDialog("embedded", "Select File", ".*", config);
806
// then display, here
807
// to note, when embedded the ImVec2(0,0) (MinSize) do nothing, only the ImVec2(0,350) (MaxSize) can size the dialog frame
808
fileDialog.Display("embedded", ImGuiWindowFlags_NoCollapse, ImVec2(0,0), ImVec2(0,350)))
809
```
810
the result :
811
812
![Embedded.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/Embedded.gif)
813
814
################################################################
815
## Quick Parallel Path Selection in Path Composer
816
################################################################
817
818
you have a separator between two directories in the path composer
819
when you click on it you can explore a list of parrallels directories of this point
820
821
this feature is enabled by default
822
you can disable it with the flag : ImGuiFileDialogFlags_DisableQuickPathSelection
823
824
you can also customize the spacing between path button's with and without this mode
825
you can do that by define the compiler flag : #define CUSTOM_PATH_SPACING 2
826
if undefined the spacing is defined by the imgui theme
827
828
![quick_composer_path_select.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/quick_composer_path_select.gif)
829
830
################################################################
831
## Case Insensitive Filtering
832
################################################################
833
834
you can use this flag 'ImGuiFileDialogFlags_CaseInsensitiveExtention' when you call the display function
835
836
```
837
by ex :
838
if the flag ImGuiFileDialogFlags_CaseInsensitiveExtention is used
839
with filters like .jpg or .Jpg or .JPG
840
all files with extentions by ex : .jpg and .JPG will be displayed
841
```
842
843
################################################################
844
## Tune the validations button group
845
################################################################
846
847
You can specify :
848
- the width of "ok" and "cancel" buttons, by the set the defines "okButtonWidth" and "cancelButtonWidth"
849
- the alignement of the button group (left, right, middle, etc..) by set the define "okCancelButtonAlignement"
850
- if you want to have the ok button on the left and cancel button on the right or inverted by set the define
851
"invertOkAndCancelButtons"
852
853
just see theses defines in the config file
854
```cpp
855
//Validation buttons
856
//#define okButtonString " OK"
857
//#define okButtonWidth 0.0f
858
//#define cancelButtonString " Cancel"
859
//#define cancelButtonWidth 0.0f
860
//alignement [0:1], 0.0 is left, 0.5 middle, 1.0 right, and other ratios
861
//#define okCancelButtonAlignement 0.0f
862
//#define invertOkAndCancelButtons false
863
```
864
with Alignement 0.0 => left
865
866
![alignement_0.0.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/alignement_0.0.png)
867
868
with Alignement 1.0 => right
869
870
![alignement_1.0.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/alignement_1.0.png)
871
872
with Alignement 0.5 => middle
873
874
![alignement_0.5.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/alignement_0.5.png)
875
876
ok and cancel buttons inverted (cancel on the left and ok on the right)
877
878
![validation_buttons_inverted.gif](https://github.com/aiekick/ImGuiFileDialog/blob/master/doc/validation_buttons_inverted.png)
879
880
################################################################
881
## Regex support for Filtering and File Styling
882
################################################################
883
884
you can use a regex for filtering and file Styling
885
886
for have a filter recognized as a regex, you must have it between a (( and a ))
887
888
this one will filter files who start by the word "Common" and finish by ".h"
889
```cpp
890
ex : "((Custom.+[.]h))"
891
```
892
893
use cases :
894
895
* Simple filter :
896
```cpp
897
OpenDialog("toto", "Choose File", "((Custom.+[.]h))");
898
```
899
900
* Collections filter :
901
for this one the filter is between "{" and "}", so you can use the "(" and ")" outside
902
903
```cpp
904
OpenDialog("toto", "Choose File", "Source files (*.cpp *.h *.hpp){((Custom.+[.]h)),.h,.hpp}");
905
```
906
907
* file coloring :
908
this one will colorized all files who start by the word "Common" and finish by ".h"
909
```cpp
910
SetFileStyle(IGFD_FileStyleByFullName, "((Custom.+[.]h))", ImVec4(1.0f, 1.0f, 0.0f, 0.9f));
911
```
912
913
* with this feature you can by ex filter and colorize render frame pictures who have ext like .000, .001, .002, etc..
914
```cpp
915
OpenDialog("toto", "Choose File", "(([.][0-9]{3}))");
916
SetFileStyle(IGFD_FileStyleByFullName, "(([.][0-9]{3}))", ImVec4(1.0f, 1.0f, 0.0f, 0.9f));
917
```
918
919
################################################################
920
## Multi Layer / asterisk based filter
921
################################################################
922
923
you can add filter in the form : .a.b.c .json.cpp .vcxproj.filters
924
925
you can also add filter in the form : .* .*.* .vcx.* .*.filters .vcx*.filt.* etc..
926
all the * based filter are internally using regex's
927
928
################################################################
929
## Result Modes for GetFilePathName, getFileName and GetSelection
930
################################################################
931
932
you can add have various behavior when you get the file results at dialog end
933
934
you can specify a result mode to thoses function :
935
936
```cpp
937
GetFilePathName(IGFD_ResultMode = IGFD_ResultMode_AddIfNoFileExt)
938
GetFileName(IGFD_ResultMode = IGFD_ResultMode_AddIfNoFileExt)
939
GetFileSelection(IGFD_ResultMode = IGFD_ResultMode_KeepInputFile)
940
```
941
You can see these function who their default modes.
942
but you can modify them.
943
944
There is 3 Modes :
945
```cpp
946
IGFD_ResultMode_AddIfNoFileExt [DEFAULT]
947
This mode add the filter ext only if there is no file ext. (compatible multi layer)
948
ex :
949
   filter {.cpp,.h} with file :
950
     toto.h => toto.h
951
     toto.a.h => toto.a.h
952
     toto.a. => toto.a.cpp
953
     toto. => toto.cpp
954
     toto => toto.cpp
955
   filter {.z,.a.b} with file :
956
     toto.a.h => toto.a.h
957
     toto. => toto.z
958
     toto => toto.z
959
   filter {.g.z,.a} with file :
960
     toto.a.h => toto.a.h
961
     toto. => toto.g.z
962
     toto => toto.g.z
963
964
IGFD_ResultMode_OverwriteFileExt
965
This mode Overwrite the file extention by the current filter
966
This mode is the old behavior for imGuiFileDialog pre v0.6.6
967
ex :
968
   filter {.cpp,.h} with file :
969
     toto.h => toto.cpp
970
     toto.a.h => toto.a.cpp
971
     toto.a. => toto.a.cpp
972
     toto.a.h.t => toto.a.h.cpp
973
     toto. => toto.cpp
974
     toto => toto.cpp
975
   filter {.z,.a.b} with file :
976
     toto.a.h => toto.z
977
     toto.a.h.t => toto.a.z
978
     toto. => toto.z
979
     toto => toto.z
980
   filter {.g.z,.a} with file :
981
     toto.a.h => toto.g.z
982
     toto.a.h.y => toto.a.g.z
983
     toto.a. => toto.g.z
984
     toto. => toto.g.z
985
     toto => toto.g.z
986
987
IGFD_ResultMode_KeepInputFile
988
This mode keep the input file. no modification
989
es :
990
   filter {.cpp,.h} with file :
991
      toto.h => toto.h
992
      toto. => toto.
993
      toto => toto
994
   filter {.z,.a.b} with file :
995
      toto.a.h => toto.a.h
996
      toto. => toto.
997
      toto => toto
998
   filter {.g.z,.a} with file :
999
      toto.a.h => toto.a.h
1000
      toto. => toto.
1001
      toto => toto
1002
```
1003
1004
to note :
1005
  - in case of a collection of filter. the default filter will be the first.
1006
    so in collection {.cpp,((.vcxproj.*)), .ft.*}, the default filter used for renaming will be .cpp
1007
  - when you have multilayer filter in collection.
1008
    we consider a filter to be replaced according to the max dot of filters for a whole collection
1009
    a collection {.a, .b.z} is a two dots filter, so a file toto.g.z will be replaced by toto.a
1010
    a collection {.z; .b} is a one dot filter, so a file toto.g.z will be replaced by toto.g.a
1011
1012
################################################################
1013
## Custom FileSystem
1014
################################################################
1015
1016
you can use your custom file system interface.
1017
1018
by default IGFD come with the File System Interfaces for Dirent or std::filesystem
1019
but you have now a FileSystem interface called IFileSystem who can be overrided with your needs
1020
by ex for android, emscripten, or boost
1021
1022
2 steps :
1023
1024
1) create a include file who must contain :
1025
   - your override of IGFD::IFileSystem
1026
   - a define of your class name in FILE_SYSTEM_OVERRIDE (ex : #define FILE_SYSTEM_OVERRIDE FileSystemBoost)
1027
1028
2) define your file system include file path in the preprocessor var "CUSTOM_FILESYSTEM_INCLUDE"
1029
   ex : #define CUSTOM_FILESYSTEM_INCLUDE "src/FileSystemBoost.hpp"
1030
1031
you can check the DemoApp who is using an override for the Boost::filesystem
1032
1033
################################################################
1034
## Modify file infos during scan by a callback
1035
################################################################
1036
1037
in some case, it can be unsefull for modify file infos
1038
so you can define your callback and attached it in the FileDialogConfig struct in the field userFileAttributes
1039
1040
the callback stamp is :
1041
```cpp
1042
bool (IGFD::FileInfos* vFileInfosPtr, IGFD::UserDatas vUserDatas)
1043
```
1044
if the callback is returning false, the file is ignored, so not displayed by the dailog
1045
1046
example in the gltf separated files : (see the branch DemoApp for example use)
1047
1048
A gltf file can have data description and datas files separated.
1049
in this case only the file with description will be shown in the dialog, so with not the full size of all attached datas
1050
1051
With the file format .gltf who is containing datas in a separate .bin
1052
1053
syntax :
1054
```cpp
1055
config.userFileAttributes = [](IGFD::FileInfos* vFileInfosPtr, IGFD::UserDatas vUserDatas) -> bool {
1056
    if (vFileInfosPtr != nullptr) {
1057
        // this demo not take into account .gltf who have data insise. besauce keepd easy just for demo
1058
        if (vFileInfosPtr->SearchForExt(".gltf", true)) {
1059
            auto bin_file_path_name = vFileInfosPtr->filePath + IGFD::Utils::GetPathSeparator() + vFileInfosPtr->fileNameLevels[0] + ".bin";
1060
            struct stat statInfos   = {};
1061
            char timebuf[100];
1062
            int result = stat(bin_file_path_name.c_str(), &statInfos);
1063
            if (!result) {
1064
                vFileInfosPtr->fileSize = (size_t)statInfos.st_size;
1065
            } else {
1066
                // no bin, so escaped.
1067
                // normally we must parse the file and check the uri for get the buffer file
1068
                // but here we keep the example as easy for demo.
1069
                return false;
1070
            }
1071
        }
1072
    }
1073
    return true;
1074
};
1075
```
1076
1077
you can also display a tootlip for a file displayed when the mouse is over a dedicated column
1078
1079
you juste need to set your message for the FileDialogConfig.tooltipMessage
1080
and specify the column in FileDialogConfig.tooltipColumn
1081
1082
ex code from the DemoApp branch for display the decomposition of gltf total size
1083
1084
syntax :
1085
```cpp
1086
vFileInfosPtr->tooltipMessage = toStr("%s : %s\n%s : %s",             //
1087
    (vFileInfosPtr->fileNameLevels[0] + ".gltf").c_str(),             //
1088
    IGFD::Utils::FormatFileSize(vFileInfosPtr->fileSize).c_str(),     //
1089
    (vFileInfosPtr->fileNameLevels[0] + ".bin").c_str(),              //
1090
    IGFD::Utils::FormatFileSize((size_t)statInfos.st_size).c_str());  //
1091
vFileInfosPtr->tooltipColumn  = 1;
1092
```
1093
1094
################################################################
1095
## How to Integrate ImGuiFileDialog in your project
1096
################################################################
1097
1098
### Customize ImGuiFileDialog :
1099
1100
You can customize many aspects of ImGuiFileDialog by overriding `ImGuiFileDialogConfig.h`.
1101
1102
To enable your customizations, define the preprocessor directive CUSTOM_IMGUIFILEDIALOG_CONFIG with the path of your
1103
custom config file. This path must be relative to the directory where you put the ImGuiFileDialog module.
1104
1105
This operation is demonstrated in `CustomImGuiFileDialog.h` in the example project to:
1106
1107
* Have a custom icon font instead of labels for buttons or message titles
1108
* Customize the button text (the button call signature must be the same, by the way! :)
1109
1110
The custom icon font used in the example code ([CustomFont.cpp](CustomFont.cpp) and [CustomFont.h](CustomFont.h)) was
1111
made with [ImGuiFontStudio](https://github.com/aiekick/ImGuiFontStudio), which I wrote. :)
1112
1113
ImGuiFontStudio uses ImGuiFileDialog! Check it out.
1114
1115
################################################################
1116
## Api's C/C++ :
1117
################################################################
1118
1119
### the C Api
1120
1121
this api was sucessfully tested with CImGui
1122
1123
A C API is available let you include ImGuiFileDialog in your C project.
1124
btw, ImGuiFileDialog depend of ImGui and dirent (for windows)
1125
1126
Sample code with cimgui :
1127
1128
```cpp
1129
// create ImGuiFileDialog
1130
ImGuiFileDialog *cfileDialog = IGFD_Create();
1131
1132
// open dialog
1133
if (igButton("Open File", buttonSize)) {
1134
    IGFD_FileDialog_Config config = IGFD_FileDialog_Config_Get();
1135
    config.path = ".";
1136
    config.flags = ImGuiFileDialogFlags_ConfirmOverwrite; // ImGuiFileDialogFlags
1137
    IGFD_OpenDialog(cfiledialog,
1138
        "filedlg",                              // dialog key (make it possible to have different treatment reagrding the dialog key
1139
        "Open a File",                          // dialog title
1140
        "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..
1141
        config); 								// the file dialog config
1142
}
1143
1144
ImGuiIO* ioptr = igGetIO();
1145
ImVec2 maxSize;
1146
maxSize.x = ioptr->DisplaySize.x * 0.8f;
1147
maxSize.y = ioptr->DisplaySize.y * 0.8f;
1148
ImVec2 minSize;
1149
minSize.x = maxSize.x * 0.25f;
1150
minSize.y = maxSize.y * 0.25f;
1151
1152
// display dialog
1153
if (IGFD_DisplayDialog(cfiledialog, "filedlg", ImGuiWindowFlags_NoCollapse, minSize, maxSize))
1154
{
1155
    if (IGFD_IsOk(cfiledialog)) // result ok
1156
    {
1157
        char* cfilePathName = IGFD_GetFilePathName(cfiledialog);
1158
        printf("GetFilePathName : %s\n", cfilePathName);
1159
        char* cfilePath = IGFD_GetCurrentPath(cfiledialog);
1160
        printf("GetCurrentPath : %s\n", cfilePath);
1161
        char* cfilter = IGFD_GetCurrentFilter(cfiledialog);
1162
        printf("GetCurrentFilter : %s\n", cfilter);
1163
        // here convert from string because a string was passed as a userDatas, but it can be what you want
1164
        void* cdatas = IGFD_GetUserDatas(cfiledialog);
1165
        if (cdatas)
1166
            printf("GetUserDatas : %s\n", (const char*)cdatas);
1167
        struct IGFD_Selection csel = IGFD_GetSelection(cfiledialog); // multi selection
1168
        printf("Selection :\n");
1169
        for (int i = 0; i < (int)csel.count; i++)
1170
        {
1171
            printf("(%i) FileName %s => path %s\n", i, csel.table[i].fileName, csel.table[i].filePathName);
1172
        }
1173
        // action
1174
1175
        // destroy
1176
        if (cfilePathName) free(cfilePathName);
1177
        if (cfilePath) free(cfilePath);
1178
        if (cfilter) free(cfilter);
1179
1180
        IGFD_Selection_DestroyContent(&csel);
1181
    }
1182
    IGFD_CloseDialog(cfiledialog);
1183
}
1184
1185
// destroy ImGuiFileDialog
1186
IGFD_Destroy(cfiledialog);
1187
```
1188
################################################################
1189
################################################################
1190
1191
Thats all.
1192
1193
You can check by example in this repo with the file CustomImGuiFileDialogConfig.h :
1194
- this trick was used for have custom icon font instead of labels for buttons or messages titles
1195
- you can also use your custom imgui button, the button call stamp must be same by the way :)
1196
1197
The Custom Icon Font (in CustomFont.cpp and CustomFont.h) was made with ImGuiFontStudio
1198
(https://github.com/aiekick/ImGuiFontStudio) i wrote for that :) ImGuiFontStudio is using also ImGuiFileDialog.
1199
1200
################################################################
1201
################################################################
1202
*/
1203
1204
#pragma endregion
1205
1206
#pragma region IGFD VERSION
1207
1208
// compatible with 1.90.1 WIP
1209
#define IMGUIFILEDIALOG_VERSION "v0.6.6.1"
1210
1211
#pragma endregion
1212
1213
#pragma region CONFIG FILE INCLUSION
1214
1215
#ifndef CUSTOM_IMGUIFILEDIALOG_CONFIG
1216
#include "ImGuiFileDialogConfig.h"
1217
#else  // CUSTOM_IMGUIFILEDIALOG_CONFIG
1218
#include CUSTOM_IMGUIFILEDIALOG_CONFIG
1219
#endif  // CUSTOM_IMGUIFILEDIALOG_CONFIG
1220
1221
#pragma endregion
1222
1223
#pragma region FLAGS : FileStyleFlags
1224
1225
// file style enum for file display (color, icon, font)
1226
typedef int IGFD_FileStyleFlags;  // -> enum IGFD_FileStyleFlags_
1227
enum IGFD_FileStyleFlags_         // by evaluation / priority order
1228
{
1229
    IGFD_FileStyle_None = 0,                         // define none style
1230
    IGFD_FileStyleByTypeFile = (1 << 0),             // define style for all files
1231
    IGFD_FileStyleByTypeDir = (1 << 1),              // define style for all dir
1232
    IGFD_FileStyleByTypeLink = (1 << 2),             // define style for all link
1233
    IGFD_FileStyleByExtention = (1 << 3),            // define style by extention, for files or links
1234
    IGFD_FileStyleByFullName = (1 << 4),             // define style for particular file/dir/link full name (filename + extention)
1235
    IGFD_FileStyleByContainedInFullName = (1 << 5),  // define style for file/dir/link when criteria is contained in full name
1236
};
1237
1238
#pragma endregion
1239
1240
#pragma region FLAGS : ImGuiFileDialogFlags
1241
1242
typedef int ImGuiFileDialogFlags;  // -> enum ImGuiFileDialogFlags_
1243
enum ImGuiFileDialogFlags_ {
1244
    ImGuiFileDialogFlags_None = 0,                                 // define none default flag
1245
    ImGuiFileDialogFlags_ConfirmOverwrite = (1 << 0),              // show confirm to overwrite dialog
1246
    ImGuiFileDialogFlags_DontShowHiddenFiles = (1 << 1),           // dont show hidden file (file starting with a .)
1247
    ImGuiFileDialogFlags_DisableCreateDirectoryButton = (1 << 2),  // disable the create directory button
1248
    ImGuiFileDialogFlags_HideColumnType = (1 << 3),                // hide column file type
1249
    ImGuiFileDialogFlags_HideColumnSize = (1 << 4),                // hide column file size
1250
    ImGuiFileDialogFlags_HideColumnDate = (1 << 5),                // hide column file date
1251
    ImGuiFileDialogFlags_NoDialog = (1 << 6),                      // let the dialog embedded in your own imgui begin / end scope
1252
    ImGuiFileDialogFlags_ReadOnlyFileNameField = (1 << 7),         // don't let user type in filename field for file open style dialogs
1253
    ImGuiFileDialogFlags_CaseInsensitiveExtention = (1 << 8),      // the file extentions treatments will not take into account the case
1254
    ImGuiFileDialogFlags_Modal = (1 << 9),                         // modal
1255
    ImGuiFileDialogFlags_DisableThumbnailMode = (1 << 10),         // disable the thumbnail mode
1256
    ImGuiFileDialogFlags_DisableBookmarkMode = (1 << 11),          // disable the bookmark mode
1257
    ImGuiFileDialogFlags_DisableQuickPathSelection = (1 << 12),    // disable the quick path selection
1258
1259
    // default behavior when no flags is defined. seems to be the more common cases
1260
    ImGuiFileDialogFlags_Default = ImGuiFileDialogFlags_ConfirmOverwrite |  //
1261
                                   ImGuiFileDialogFlags_Modal |             //
1262
                                   ImGuiFileDialogFlags_HideColumnType
1263
};
1264
1265
// flags used for GetFilePathName(flag) or GetSelection(flag)
1266
typedef int IGFD_ResultMode;  // -> enum IGFD_ResultMode_
1267
enum IGFD_ResultMode_ {
1268
    // IGFD_ResultMode_AddIfNoFileExt
1269
    // add the file ext only if there is no file ext
1270
    //   filter {.cpp,.h} with file :
1271
    //     toto.h => toto.h
1272
    //     toto.a.h => toto.a.h
1273
    //     toto.a. => toto.a.cpp
1274
    //     toto. => toto.cpp
1275
    //     toto => toto.cpp
1276
    //   filter {.z,.a.b} with file :
1277
    //     toto.a.h => toto.a.h
1278
    //     toto. => toto.z
1279
    //     toto => toto.z
1280
    //   filter {.g.z,.a} with file :
1281
    //     toto.a.h => toto.a.h
1282
    //     toto. => toto.g.z
1283
    //     toto => toto.g.z
1284
    IGFD_ResultMode_AddIfNoFileExt = 0,
1285
1286
    // IGFD_ResultMode_OverwriteFileExt
1287
    // Overwrite the file extention by the current filter :
1288
    //   filter {.cpp,.h} with file :
1289
    //     toto.h => toto.cpp
1290
    //     toto.a.h => toto.a.cpp
1291
    //     toto.a. => toto.a.cpp
1292
    //     toto.a.h.t => toto.a.h.cpp
1293
    //     toto. => toto.cpp
1294
    //     toto => toto.cpp
1295
    //   filter {.z,.a.b} with file :
1296
    //     toto.a.h => toto.z
1297
    //     toto.a.h.t => toto.a.z
1298
    //     toto. => toto.z
1299
    //     toto => toto.z
1300
    //   filter {.g.z,.a} with file :
1301
    //     toto.a.h => toto.g.z
1302
    //     toto.a.h.y => toto.a.g.z
1303
    //     toto.a. => toto.g.z
1304
    //     toto. => toto.g.z
1305
    //     toto => toto.g.z
1306
    IGFD_ResultMode_OverwriteFileExt = 1,  // behavior pre IGFD v0.6.6
1307
1308
    // IGFD_ResultMode_KeepInputFile
1309
    // keep the input file => no modification :
1310
    //   filter {.cpp,.h} with file :
1311
    //      toto.h => toto.h
1312
    //      toto. => toto.
1313
    //      toto => toto
1314
    //   filter {.z,.a.b} with file :
1315
    //      toto.a.h => toto.a.h
1316
    //      toto. => toto.
1317
    //      toto => toto
1318
    //   filter {.g.z,.a} with file :
1319
    //      toto.a.h => toto.a.h
1320
    //      toto. => toto.
1321
    //      toto => toto
1322
    IGFD_ResultMode_KeepInputFile = 2
1323
};
1324
1325
#pragma endregion
1326
1327
#pragma region Common Cpp& C Structures
1328
1329
#ifdef USE_THUMBNAILS
1330
struct IGFD_Thumbnail_Info {
1331
    int isReadyToDisplay = 0;             // ready to be rendered, so texture created
1332
    int isReadyToUpload = 0;              // ready to upload to gpu
1333
    int isLoadingOrLoaded = 0;            // was sent to laoding or loaded
1334
    int textureWidth = 0;                 // width of the texture to upload
1335
    int textureHeight = 0;                // height of the texture to upload
1336
    int textureChannels = 0;              // count channels of the texture to upload
1337
    unsigned char* textureFileDatas = 0;  // file texture datas, will be rested to null after gpu upload
1338
    void* textureID = 0;                  // 2d texture id (void* is like ImtextureID type) (GL, DX, VK, Etc..)
1339
    void* userDatas = 0;                  // user datas
1340
};
1341
#endif  // USE_THUMBNAILS
1342
1343
#pragma endregion
1344
1345
#ifdef __cplusplus
1346
1347
#pragma region Includes
1348
1349
#ifndef IMGUI_DEFINE_MATH_OPERATORS
1350
#define IMGUI_DEFINE_MATH_OPERATORS
1351
#endif  // IMGUI_DEFINE_MATH_OPERATORS
1352
1353
#ifdef IMGUI_INCLUDE
1354
#include IMGUI_INCLUDE
1355
#else  // IMGUI_INCLUDE
1356
#include <imgui.h>
1357
#endif  // IMGUI_INCLUDE
1358
1359
#include <set>
1360
#include <map>
1361
#include <list>
1362
#include <regex>
1363
#include <array>
1364
#include <mutex>
1365
#include <condition_variable>
1366
#include <thread>
1367
#include <cfloat>
1368
#include <memory>
1369
#include <string>
1370
#include <vector>
1371
#include <utility>
1372
#include <fstream>
1373
#include <functional>
1374
#include <unordered_map>
1375
1376
#pragma endregion
1377
1378
#pragma region IGFD API
1379
1380
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
1381
// Using ImGuiFileDialog via a shared library is not recommended, because we don't guarantee
1382
// backward nor forward ABI compatibility and also function call overhead. If you
1383
// do use ImGuiFileDialog as a DLL, be sure to call SetImGuiContext (see Miscellanous section).
1384
1385
#ifndef IGFD_API
1386
#define IGFD_API
1387
#endif  // IGFD_API
1388
1389
#pragma endregion
1390
1391
#pragma region Defines
1392
1393
#ifndef defaultSortField
1394
#define defaultSortField FIELD_FILENAME
1395
#endif  // defaultSortField
1396
1397
#ifndef defaultSortOrderFilename
1398
#define defaultSortOrderFilename true
1399
#endif  // defaultSortOrderFilename
1400
#ifndef defaultSortOrderType
1401
#define defaultSortOrderType true
1402
#endif  // defaultSortOrderType
1403
#ifndef defaultSortOrderSize
1404
#define defaultSortOrderSize true
1405
#endif  // defaultSortOrderSize
1406
#ifndef defaultSortOrderDate
1407
#define defaultSortOrderDate true
1408
#endif  // defaultSortOrderDate
1409
#ifndef defaultSortOrderThumbnails
1410
#define defaultSortOrderThumbnails true
1411
#endif  // defaultSortOrderThumbnails
1412
1413
#ifndef MAX_FILE_DIALOG_NAME_BUFFER
1414
#define MAX_FILE_DIALOG_NAME_BUFFER 1024
1415
#endif  // MAX_FILE_DIALOG_NAME_BUFFER
1416
1417
#ifndef MAX_PATH_BUFFER_SIZE
1418
#define MAX_PATH_BUFFER_SIZE 1024
1419
#endif  // MAX_PATH_BUFFER_SIZE
1420
1421
#ifndef EXT_MAX_LEVEL
1422
#define EXT_MAX_LEVEL 10U
1423
#endif  // EXT_MAX_LEVEL
1424
1425
#pragma endregion
1426
1427
#pragma region IGFD NAMESPACE
1428
1429
namespace IGFD {
1430
1431
#pragma region INTERNAL
1432
1433
#pragma region SEARCHABLE VECTOR
1434
1435
template <typename T>
1436
class SearchableVector {
1437
private:
1438
    std::unordered_map<T, size_t> m_Dico;
1439
    std::vector<T> m_Array;
1440
1441
public:
1442
    void clear() {
1443
        m_Dico.clear();
1444
        m_Array.clear();
1445
    }
1446
1447
    bool empty() const {
1448
        return m_Array.empty();
1449
    }
1450
    size_t size() const {
1451
        return m_Array.size();
1452
    }
1453
    T& operator[](const size_t& vIdx) {
1454
        return m_Array[vIdx];
1455
    }
1456
    T& at(const size_t& vIdx) {
1457
        return m_Array.at(vIdx);
1458
    }
1459
    typename std::vector<T>::iterator begin() {
1460
        return m_Array.begin();
1461
    }
1462
    typename std::vector<T>::const_iterator begin() const {
1463
        return m_Array.begin();
1464
    }
1465
    typename std::vector<T>::iterator end() {
1466
        return m_Array.end();
1467
    }
1468
    typename std::vector<T>::const_iterator end() const {
1469
        return m_Array.end();
1470
    }
1471
1472
    bool try_add(T vKey) {
1473
        if (!exist(vKey)) {
1474
            m_Dico[vKey] = m_Array.size();
1475
            m_Array.push_back(vKey);
1476
            return true;
1477
        }
1478
        return false;
1479
    }
1480
1481
    bool try_set_existing(T vKey) {
1482
        if (exist(vKey)) {
1483
            auto row = m_Dico.at(vKey);
1484
            m_Array[row] = vKey;
1485
            return true;
1486
        }
1487
        return false;
1488
    }
1489
1490
    bool exist(const std::string& vKey) const {
1491
        return (m_Dico.find(vKey) != m_Dico.end());
1492
    }
1493
};
1494
1495
#pragma endregion
1496
1497
#pragma region Utils
1498
1499
class IGFD_API Utils {
1500
public:
1501
    struct PathStruct {
1502
        std::string path;
1503
        std::string name;
1504
        std::string ext;
1505
        bool isOk = false;
1506
    };
1507
1508
public:
1509
    static bool ImSplitter(
1510
        bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f);
1511
    static bool ReplaceString(std::string& str, const std::string& oldStr, const std::string& newStr, const size_t& vMaxRecursion = 10U);
1512
    static void AppendToBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr);
1513
    static void ResetBuffer(char* vBuffer);
1514
    static void SetBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr);
1515
    static std::string UTF8Encode(const std::wstring& wstr);
1516
    static std::wstring UTF8Decode(const std::string& str);
1517
    static std::vector<std::string> SplitStringToVector(const std::string& vText, const char& vDelimiter, const bool& vPushEmpty);
1518
    static std::string LowerCaseString(const std::string& vString);  // turn all text in lower case for search facilitie
1519
    static size_t GetCharCountInString(const std::string& vString, const char& vChar);
1520
    static size_t GetLastCharPosWithMinCharCount(const std::string& vString, const char& vChar, const size_t& vMinCharCount);
1521
    static std::string GetPathSeparator(); // return the slash for any OS ( \\ win, / unix)
1522
    static std::string RoundNumber(double vvalue, int n);  // custom rounding number
1523
    static std::pair<std::string, std::string> FormatFileSize(size_t vByteSize);   // format file size field
1524
};
1525
1526
#pragma endregion
1527
1528
#pragma region FileStyle
1529
1530
class IGFD_API FileInfos;
1531
class IGFD_API FileStyle {
1532
public:
1533
    typedef std::function<bool(const FileInfos&, FileStyle&)> FileStyleFunctor;
1534
1535
public:
1536
    ImVec4 color = ImVec4(0, 0, 0, 0);
1537
    std::string icon;
1538
    ImFont* font = nullptr;
1539
    IGFD_FileStyleFlags flags = 0;
1540
1541
public:
1542
    FileStyle();
1543
    FileStyle(const FileStyle& vStyle);
1544
    FileStyle(const ImVec4& vColor, const std::string& vIcon = "", ImFont* vFont = nullptr);
1545
};
1546
1547
#pragma endregion
1548
1549
#pragma region SearchManager
1550
1551
class IGFD_API FileDialogInternal;
1552
class IGFD_API SearchManager {
1553
public:
1554
    std::string searchTag;
1555
    char searchBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = "";
1556
    bool searchInputIsActive = false;
1557
1558
public:
1559
    void Clear();                                                 // clear datas
1560
    void DrawSearchBar(FileDialogInternal& vFileDialogInternal);  // draw the search bar
1561
};
1562
1563
#pragma endregion
1564
1565
#pragma region FilterInfos
1566
1567
class IGFD_API FilterInfos {
1568
private:
1569
    // just for return a default const std::string& in getFirstFilter.
1570
    // cannot be const, because FilterInfos must be affected to an another FilterInfos
1571
    // must stay empty alla time
1572
    std::string empty_string;
1573
1574
public:
1575
    std::string title;                                // displayed filter.can be different than rela filter
1576
    SearchableVector<std::string> filters;            // filters
1577
    SearchableVector<std::string> filters_optimized;  // optimized filters for case insensitive search
1578
    std::vector<std::regex> filters_regex;            // collection of regex filter type
1579
    size_t count_dots = 0U;                           // the max count dot the max per filter of all filters
1580
1581
public:
1582
    void clear();                                                                 // clear the datas
1583
    bool empty() const;                                                           // is filter empty
1584
    const std::string& getFirstFilter() const;                                    // get the first filter
1585
    bool regexExist(const std::string& vFilter) const;                            // is regex filter exist
1586
    bool exist(const FileInfos& vFileInfos, bool vIsCaseInsensitive) const;       // is filter exist
1587
    void setCollectionTitle(const std::string& vTitle);                           // set the collection title
1588
    void addFilter(const std::string& vFilter, const bool& vIsRegex);             // add a filter
1589
    void addCollectionFilter(const std::string& vFilter, const bool& vIsRegex);   // add a filter in collection
1590
    std::string transformAsteriskBasedFilterToRegex(const std::string& vFilter);  // will transform a filter who contain * to a regex
1591
};
1592
1593
#pragma endregion
1594
1595
#pragma region FilterManager
1596
1597
class IGFD_API FileInfos;
1598
class IGFD_API FilterManager {
1599
#ifdef NEED_TO_BE_PUBLIC_FOR_TESTS
1600
public:
1601
#else
1602
private:
1603
#endif
1604
    std::vector<FilterInfos> m_ParsedFilters;
1605
    std::unordered_map<IGFD_FileStyleFlags, std::unordered_map<std::string, std::shared_ptr<FileStyle>>> m_FilesStyle;  // file infos for file
1606
                                                                                                                        // extention only
1607
    std::vector<FileStyle::FileStyleFunctor> m_FilesStyleFunctors;  // file style via lambda function
1608
    FilterInfos m_SelectedFilter;
1609
1610
public:
1611
    std::string dLGFilters;
1612
    std::string dLGdefaultExt;
1613
1614
public:
1615
    const FilterInfos& GetSelectedFilter() const;
1616
    void ParseFilters(const char* vFilters);                            // Parse filter syntax, detect and parse filter collection
1617
    void SetSelectedFilterWithExt(const std::string& vFilter);          // Select filter
1618
    bool m_FillFileStyle(std::shared_ptr<FileInfos> vFileInfos) const;  // fill with the good style
1619
    void SetFileStyle(const IGFD_FileStyleFlags& vFlags, const char* vCriteria, const FileStyle& vInfos);  // Set FileStyle
1620
    void SetFileStyle(const IGFD_FileStyleFlags& vFlags,
1621
        const char* vCriteria,
1622
        const ImVec4& vColor,
1623
        const std::string& vIcon,
1624
        ImFont* vFont);                                       // link file style to Color and Icon and Font
1625
    void SetFileStyle(FileStyle::FileStyleFunctor vFunctor);  // lambda functor for set file style.
1626
    bool GetFileStyle(const IGFD_FileStyleFlags& vFlags,
1627
        const std::string& vCriteria,
1628
        ImVec4* vOutColor,
1629
        std::string* vOutIcon,
1630
        ImFont** vOutFont);  // Get Color and Icon for Filter
1631
    void ClearFilesStyle();  // clear m_FileStyle
1632
    bool IsCoveredByFilters(const FileInfos& vFileInfos,
1633
        bool vIsCaseInsensitive) const;    // check if current file extention (vExt) is covered by current filter, or by regex (vNameExt)
1634
    float GetFilterComboBoxWidth() const;  // will return the current combo box widget width
1635
    bool DrawFilterComboBox(FileDialogInternal& vFileDialogInternal);  // draw the filter combobox 	// get the current selected filter
1636
    std::string ReplaceExtentionWithCurrentFilterIfNeeded(const std::string& vFileName,
1637
        IGFD_ResultMode vFlag) const;     // replace the extention of the current file by the selected filter
1638
    void SetDefaultFilterIfNotDefined();  // define the first filter if no filter is selected
1639
};
1640
1641
#pragma endregion
1642
1643
#pragma region FileType
1644
1645
class IGFD_API FileType {
1646
public:
1647
    enum class ContentType {
1648
        // The ordering will be used during sort.
1649
        Invalid = -1,
1650
        Directory = 0,
1651
        File = 1,
1652
        LinkToUnknown = 2,  // link to something that is not a regular file or directory.
1653
    };
1654
1655
private:
1656
    ContentType m_Content = ContentType::Invalid;
1657
    bool m_Symlink = false;
1658
1659
public:
1660
    FileType();
1661
    FileType(const ContentType& vContentType, const bool& vIsSymlink);
1662
1663
    void SetContent(const ContentType& vContentType);
1664
    void SetSymLink(const bool& vIsSymlink);
1665
1666
    bool isValid() const;
1667
    bool isDir() const;
1668
    bool isFile() const;
1669
    bool isLinkToUnknown() const;
1670
    bool isSymLink() const;
1671
1672
    // Comparisons only care about the content type, ignoring whether it's a symlink or not.
1673
    bool operator==(const FileType& rhs) const;
1674
    bool operator!=(const FileType& rhs) const;
1675
    bool operator<(const FileType& rhs) const;
1676
    bool operator>(const FileType& rhs) const;
1677
};
1678
1679
#pragma endregion
1680
1681
#pragma region FileInfos
1682
1683
class IGFD_API FileInfos {
1684
public:
1685
    // extention of the file, the array is the levels of ext, by ex : .a.b.c, will be save in {.a.b.c, .b.c, .c}
1686
    // 10 level max are sufficient i guess. the others levels will be checked if countExtDot > 1
1687
    std::array<std::string, EXT_MAX_LEVEL> fileExtLevels;
1688
    std::array<std::string, EXT_MAX_LEVEL> fileExtLevels_optimized;  // optimized for search => insensitivecase
1689
    // same for file name, can be sued in userFileAttributesFun
1690
    std::array<std::string, EXT_MAX_LEVEL> fileNameLevels;
1691
    std::array<std::string, EXT_MAX_LEVEL> fileNameLevels_optimized;  // optimized for search => insensitivecase
1692
    size_t countExtDot = 0U;                                         // count dots in file extention. this count will give the levels in fileExtLevels
1693
    FileType fileType;                                               // fileType
1694
    std::string filePath;                                            // path of the file
1695
    std::string fileName;                                            // file name only
1696
    std::string fileNameExt;                                         // filename of the file (file name + extention) (but no path)
1697
    std::string fileNameExt_optimized;                               // optimized for search => insensitivecase
1698
    std::string tooltipMessage;                                      // message to display on the tooltip, is not empty
1699
    int32_t tooltipColumn = -1;                                      // the tooltip will appears only when the mouse is over the tooltipColumn if > -1
1700
    size_t fileSize = 0U;                                            // for sorting operations
1701
    std::pair<std::string, std::string> formatedFileSize;            // file size formated with number in first and unit in second (10 o, 10 ko, 10 mo, 10 go)
1702
    std::string fileModifDate;                                       // file user defined format of the date (data + time by default)
1703
    std::shared_ptr<FileStyle> fileStyle = nullptr;                  // style of the file
1704
#ifdef USE_THUMBNAILS
1705
    IGFD_Thumbnail_Info thumbnailInfo;  // structre for the display for image file tetxure
1706
#endif                                  // USE_THUMBNAILS
1707
1708
public:
1709
    bool SearchForTag(const std::string& vTag) const;  // will search a tag in fileNameExt and fileNameExt_optimized
1710
    bool SearchForExt(const std::string& vExt,
1711
        const bool& vIsCaseInsensitive,
1712
        const size_t& vMaxLevel = EXT_MAX_LEVEL) const;  // will check the fileExtLevels levels for vExt, until vMaxLevel
1713
    bool SearchForExts(const std::string& vComaSepExts,
1714
        const bool& vIsCaseInsensitive,
1715
        const size_t& vMaxLevel = EXT_MAX_LEVEL) const;  // will check the fileExtLevels levels for vExts (ext are coma separated), until vMaxLevel
1716
    bool FinalizeFileTypeParsing(const size_t& vMaxDotToExtract);  // finalize the parsing the file (only a file or link to file. no dir)
1717
};
1718
1719
#pragma endregion
1720
1721
#pragma region FILE SYSTEM INTERFACE
1722
1723
class IFileSystem {
1724
public:
1725
    virtual ~IFileSystem() = default;
1726
    // say if a directory can be openened or for any reason locked
1727
    virtual bool IsDirectoryCanBeOpened(const std::string& vName) = 0;
1728
    // say if a directory exist
1729
    virtual bool IsDirectoryExist(const std::string& vName) = 0;
1730
    // say if a file exist
1731
    virtual bool IsFileExist(const std::string& vName) = 0;
1732
    // say if a directory was created, return false if vName is invalid or alreayd exist
1733
    virtual bool CreateDirectoryIfNotExist(const std::string& vName) = 0;
1734
    // extract the component of a file apth name, like path, name, ext
1735
    virtual IGFD::Utils::PathStruct ParsePathFileName(const std::string& vPathFileName) = 0;
1736
    // will return a list of files inside a path
1737
    virtual std::vector<IGFD::FileInfos> ScanDirectory(const std::string& vPath) = 0;
1738
    // say if the path is well a directory
1739
    virtual bool IsDirectory(const std::string& vFilePathName) = 0;
1740
    // return a drive list on windows, bu can be used on android or linux for give to the suer a list of root dir
1741
    virtual std::vector<std::string> GetDrivesList() = 0;
1742
};
1743
1744
#pragma endregion
1745
1746
#pragma region FileManager
1747
1748
class IGFD_API FileManager {
1749
public:                            // types
1750
    enum SortingFieldEnum {        // sorting for filetering of the file lsit
1751
        FIELD_FILENAME,            // sorted by filename
1752
        FIELD_TYPE,                // sorted by filetype
1753
        FIELD_SIZE,                // sorted by filesize (formated file size)
1754
        FIELD_DATE,                // sorted by filedate
1755
#ifdef USE_THUMBNAILS
1756
        FIELD_THUMBNAILS,          // sorted by thumbnails (comparaison by width then by height)
1757
#endif
1758
        NUM_FIELDS,
1759
    };
1760
1761
#ifdef NEED_TO_BE_PUBLIC_FOR_TESTS
1762
public:
1763
#else
1764
private:
1765
#endif
1766
    std::string m_CurrentPath;                                   // current path (to be decomposed in m_CurrentPathDecomposition
1767
    std::vector<std::string> m_CurrentPathDecomposition;         // part words
1768
    std::vector<std::shared_ptr<FileInfos>> m_FileList;          // base container
1769
    std::vector<std::shared_ptr<FileInfos>> m_FilteredFileList;  // filtered container (search, sorting, etc..)
1770
    std::vector<std::shared_ptr<FileInfos>> m_PathList;          // base container for path selection
1771
    std::vector<std::shared_ptr<FileInfos>> m_FilteredPathList;  // filtered container for path selection (search, sorting, etc..)
1772
    std::vector<std::string>::iterator m_PopupComposedPath;      // iterator on m_CurrentPathDecomposition for Current Path popup
1773
    std::string m_LastSelectedFileName;                          // for shift multi selection
1774
    std::set<std::string> m_SelectedFileNames;                   // the user selection of FilePathNames
1775
    bool m_CreateDirectoryMode = false;                          // for create directory widget
1776
    std::string m_FileSystemName;
1777
    std::unique_ptr<IFileSystem> m_FileSystemPtr = nullptr;
1778
1779
public:
1780
    bool inputPathActivated = false;                             // show input for path edition
1781
    bool drivesClicked = false;                                  // event when a drive button is clicked
1782
    bool puPathClicked = false;                                  // event when a path button was clicked
1783
    char inputPathBuffer[MAX_PATH_BUFFER_SIZE] = "";             // input path buffer for imgui widget input text (displayed in palce of composer)
1784
    char variadicBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = "";       // called by m_SelectableItem
1785
    char fileNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = "";       // file name buffer in footer for imgui widget input text
1786
    char directoryNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = "";  // directory name buffer (when in directory mode)
1787
    std::string header[SortingFieldEnum::NUM_FIELDS];            // detail view name of column
1788
    bool sortingDirection[SortingFieldEnum::NUM_FIELDS] = {      // true => Ascending, false => Descending
1789
        defaultSortOrderFilename, defaultSortOrderType, defaultSortOrderSize, defaultSortOrderDate,
1790
#ifdef USE_THUMBNAILS
1791
        defaultSortOrderThumbnails,
1792
#endif
1793
    };
1794
    SortingFieldEnum sortingField = SortingFieldEnum::FIELD_FILENAME;  // detail view sorting column
1795
    bool showDrives = false;                                           // drives are shown (only on os windows)
1796
1797
    std::string dLGpath;               // base path set by user when OpenDialog was called
1798
    std::string dLGDefaultFileName;    // base default file path name set by user when OpenDialog was called
1799
    size_t dLGcountSelectionMax = 1U;  // 0 for infinite				// base max selection count set by user when OpenDialog was called
1800
    bool dLGDirectoryMode = false;     // is directory mode (defiend like : dLGDirectoryMode = (filters.empty()))
1801
1802
    std::string fsRoot;
1803
1804
#ifdef NEED_TO_BE_PUBLIC_FOR_TESTS
1805
public:
1806
#else
1807
private:
1808
#endif
1809
    static void m_CompleteFileInfos(const std::shared_ptr<FileInfos>& vInfos);     // set time and date infos of a file (detail view mode)
1810
    void m_RemoveFileNameInSelection(const std::string& vFileName);                // selection : remove a file name
1811
    void m_m_AddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName);  // selection : add a file name
1812
    void m_AddFile(const FileDialogInternal& vFileDialogInternal,
1813
        const std::string& vPath,
1814
        const std::string& vFileName,
1815
        const FileType& vFileType);  // add file called by scandir
1816
    void m_AddPath(const FileDialogInternal& vFileDialogInternal,
1817
        const std::string& vPath,
1818
        const std::string& vFileName,
1819
        const FileType& vFileType);  // add file called by scandir
1820
    void m_ScanDirForPathSelection(const FileDialogInternal& vFileDialogInternal,
1821
        const std::string& vPath);  // scan the directory for retrieve the path list
1822
    void m_OpenPathPopup(const FileDialogInternal& vFileDialogInternal,
1823
        std::vector<std::string>::iterator vPathIter);  // open the popup list of paths
1824
    void m_SetCurrentPath(std::vector<std::string>::iterator vPathIter);  // set the current path, update the path bar
1825
    void m_ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal,
1826
        std::vector<std::shared_ptr<FileInfos>>& vFileInfosList,
1827
        std::vector<std::shared_ptr<FileInfos>>& vFileInfosFilteredList);
1828
    void m_SortFields(const FileDialogInternal& vFileDialogInternal,
1829
        std::vector<std::shared_ptr<FileInfos>>& vFileInfosList,
1830
        std::vector<std::shared_ptr<FileInfos>>& vFileInfosFilteredList);  // will sort a column
1831
    bool m_CompleteFileInfosWithUserFileAttirbutes(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr<FileInfos>& vInfos);
1832
1833
public:
1834
    FileManager();
1835
    bool IsComposerEmpty();
1836
    size_t GetComposerSize();
1837
    bool IsFileListEmpty();
1838
    bool IsPathListEmpty();
1839
    bool IsFilteredListEmpty();
1840
    bool IsPathFilteredListEmpty();
1841
    size_t GetFullFileListSize();
1842
    std::shared_ptr<FileInfos> GetFullFileAt(size_t vIdx);
1843
    size_t GetFilteredListSize();
1844
    size_t GetPathFilteredListSize();
1845
    std::shared_ptr<FileInfos> GetFilteredFileAt(size_t vIdx);
1846
    std::shared_ptr<FileInfos> GetFilteredPathAt(size_t vIdx);
1847
    std::vector<std::string>::iterator GetCurrentPopupComposedPath();
1848
    bool IsFileNameSelected(const std::string& vFileName);
1849
    std::string GetBack();
1850
    void ClearComposer();
1851
    void ClearFileLists();  // clear file list, will destroy thumbnail textures
1852
    void ClearPathLists();  // clear path list, will destroy thumbnail textures
1853
    void ClearAll();
1854
    void ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal);
1855
    void SortFields(const FileDialogInternal& vFileDialogInternal);        // will sort a column
1856
    void OpenCurrentPath(const FileDialogInternal& vFileDialogInternal);   // set the path of the dialog, will launch the
1857
                                                                           // scandir for populate the file listview
1858
    bool GetDrives();                                                      // list drives on windows platform
1859
    bool CreateDir(const std::string& vPath);                              // create a directory on the file system
1860
    std::string ComposeNewPath(std::vector<std::string>::iterator vIter);  // compose a path from the compose path widget
1861
    bool SetPathOnParentDirectoryIfAny();                                  // compose paht on parent directory
1862
    std::string GetCurrentPath();                                          // get the current path
1863
    void SetCurrentPath(const std::string& vCurrentPath);                  // set the current path
1864
    void SetDefaultFileName(const std::string& vFileName);
1865
    bool SelectDirectory(const std::shared_ptr<FileInfos>& vInfos);  // enter directory
1866
    void SelectFileName(const FileDialogInternal& vFileDialogInternal,
1867
        const std::shared_ptr<FileInfos>& vInfos);  // select filename
1868
    void SetCurrentDir(const std::string& vPath);   // define current directory for scan
1869
    void ScanDir(const FileDialogInternal& vFileDialogInternal,
1870
        const std::string& vPath);  // scan the directory for retrieve the file list
1871
1872
    std::string GetResultingPath();
1873
    std::string GetResultingFileName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag);
1874
    std::string GetResultingFilePathName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag);
1875
    std::map<std::string, std::string> GetResultingSelection(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag);
1876
1877
    void DrawDirectoryCreation(const FileDialogInternal& vFileDialogInternal);  // draw directory creation widget
1878
    void DrawPathComposer(const FileDialogInternal& vFileDialogInternal); 
1879
1880
    IFileSystem* GetFileSystemInstance() {
1881
        return m_FileSystemPtr.get();
1882
    }
1883
    const std::string& GetFileSystemName() {
1884
        return m_FileSystemName;
1885
    }
1886
};
1887
1888
#pragma endregion
1889
1890
#pragma region FileDialogInternal
1891
1892
typedef void* UserDatas;
1893
typedef std::function<void(const char*, UserDatas, bool*)> PaneFun;  // side pane function binding
1894
typedef std::function<bool(FileInfos*, UserDatas)> UserFileAttributesFun;  // custom file Attributes call back, reject file if false
1895
1896
struct IGFD_API FileDialogConfig {
1897
    std::string path;                                        // path
1898
    std::string fileName;                                    // defaut file name
1899
    std::string filePathName;                                // if not empty, the filename and the path will be obtained from filePathName
1900
    int32_t countSelectionMax  = 1;                          // count selection max
1901
    UserDatas userDatas        = nullptr;                    // user datas (can be retrieved in pane)
1902
    ImGuiFileDialogFlags flags = ImGuiFileDialogFlags_None;  // ImGuiFileDialogFlags
1903
    PaneFun sidePane;                                        // side pane callback
1904
    float sidePaneWidth = 250.0f;                            // side pane width
1905
    UserFileAttributesFun userFileAttributes;                // user file Attibutes callback
1906
};
1907
1908
class IGFD_API FileDialogInternal {
1909
public:
1910
    FileManager fileManager;      // the file manager
1911
    FilterManager filterManager;  // the filter manager
1912
    SearchManager searchManager;  // the search manager
1913
1914
public:
1915
    std::string name;                                           // the internal dialog name (title + ##word)
1916
    bool showDialog = false;                                    // the dialog is shown
1917
    ImVec2 dialogCenterPos = ImVec2(0, 0);                      // center pos for display the confirm overwrite dialog
1918
    int lastImGuiFrameCount = 0;                                // to be sure than only one dialog displayed per frame
1919
    float footerHeight = 0.0f;                                  // footer height
1920
    bool canWeContinue = true;                                  // events
1921
    bool okResultToConfirm = false;                             // to confim if ok for OverWrite
1922
    bool isOk = false;                                          // is dialog ok button click
1923
    bool fileInputIsActive = false;                             // when input text for file or directory is active
1924
    bool fileListViewIsActive = false;                          // when list view is active
1925
    std::string dLGkey;                                         // the dialog key
1926
    std::string dLGtitle;                                       // the dialog title
1927
    bool needToExitDialog = false;                              // we need to exit the dialog
1928
    bool puUseCustomLocale = false;                             // custom user locale
1929
    int localeCategory = LC_ALL;                                // locale category to use
1930
    std::string localeBegin;                                    // the locale who will be applied at start of the display dialog
1931
    std::string localeEnd;                                      // the locale who will be applaied at end of the display dialog
1932
1933
private:
1934
    FileDialogConfig m_DialogConfig;
1935
1936
public:
1937
    void NewFrame();           // new frame, so maybe neded to do somethings, like reset events
1938
    void EndFrame();           // end frame, so maybe neded to do somethings fater all
1939
    void ResetForNewDialog();  // reset what is needed to reset for the openging of a new dialog
1940
1941
    void configureDialog(                  // open simple dialog
1942
        const std::string& vKey,           // key dialog
1943
        const std::string& vTitle,         // title
1944
        const char* vFilters,              // filters, if null, will display only directories
1945
        const FileDialogConfig& vConfig);  // FileDialogConfig
1946
    const FileDialogConfig& getDialogConfig() const;
1947
    FileDialogConfig& getDialogConfigRef();
1948
};
1949
1950
#pragma endregion
1951
1952
#pragma endregion
1953
1954
#pragma region Optional Features
1955
1956
#pragma region ThumbnailFeature
1957
1958
#ifdef USE_THUMBNAILS
1959
typedef std::function<void(IGFD_Thumbnail_Info*)> CreateThumbnailFun;   // texture 2d creation function binding
1960
typedef std::function<void(IGFD_Thumbnail_Info*)> DestroyThumbnailFun;  // texture 2d destroy function binding
1961
#endif
1962
class IGFD_API ThumbnailFeature {
1963
protected:
1964
    ThumbnailFeature();
1965
    ~ThumbnailFeature();
1966
1967
    void m_NewThumbnailFrame(FileDialogInternal& vFileDialogInternal);
1968
    void m_EndThumbnailFrame(FileDialogInternal& vFileDialogInternal);
1969
    void m_QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal);
1970
1971
#ifdef USE_THUMBNAILS
1972
protected:
1973
    enum class DisplayModeEnum { FILE_LIST = 0, THUMBNAILS_LIST, THUMBNAILS_GRID };
1974
1975
private:
1976
    uint32_t m_CountFiles = 0U;
1977
    bool m_IsWorking = false;
1978
    std::shared_ptr<std::thread> m_ThumbnailGenerationThread = nullptr;
1979
    std::list<std::shared_ptr<FileInfos>> m_ThumbnailFileDatasToGet;  // base container
1980
    std::mutex m_ThumbnailFileDatasToGetMutex;
1981
    std::condition_variable m_ThumbnailFileDatasToGetCv;
1982
    std::list<std::shared_ptr<FileInfos>> m_ThumbnailToCreate;  // base container
1983
    std::mutex m_ThumbnailToCreateMutex;
1984
    std::list<IGFD_Thumbnail_Info> m_ThumbnailToDestroy;  // base container
1985
    std::mutex m_ThumbnailToDestroyMutex;
1986
1987
    CreateThumbnailFun m_CreateThumbnailFun = nullptr;
1988
    DestroyThumbnailFun m_DestroyThumbnailFun = nullptr;
1989
1990
protected:
1991
    DisplayModeEnum m_DisplayMode = DisplayModeEnum::FILE_LIST;
1992
1993
private:
1994
    void m_VariadicProgressBar(float fraction, const ImVec2& size_arg, const char* fmt, ...);
1995
1996
protected:
1997
    // will be call in cpu zone (imgui computations, will call a texture file retrieval thread)
1998
    void m_StartThumbnailFileDatasExtraction();                               // start the thread who will get byte buffer from image files
1999
    bool m_StopThumbnailFileDatasExtraction();                                // stop the thread who will get byte buffer from image files
2000
    void m_ThreadThumbnailFileDatasExtractionFunc();                          // the thread who will get byte buffer from image files
2001
    void m_DrawThumbnailGenerationProgress();                                 // a little progressbar who will display the texture gen status
2002
    void m_AddThumbnailToLoad(const std::shared_ptr<FileInfos>& vFileInfos);  // add texture to load in the thread
2003
    void m_AddThumbnailToCreate(const std::shared_ptr<FileInfos>& vFileInfos);
2004
    void m_AddThumbnailToDestroy(const IGFD_Thumbnail_Info& vIGFD_Thumbnail_Info);
2005
    void m_DrawDisplayModeToolBar();  // draw display mode toolbar (file list, thumbnails list, small thumbnails grid, big thumbnails grid)
2006
    void m_ClearThumbnails(FileDialogInternal& vFileDialogInternal);
2007
2008
public:
2009
    void SetCreateThumbnailCallback(const CreateThumbnailFun& vCreateThumbnailFun);
2010
    void SetDestroyThumbnailCallback(const DestroyThumbnailFun& vCreateThumbnailFun);
2011
2012
    // must be call in gpu zone (rendering, possibly one rendering thread)
2013
    void ManageGPUThumbnails();  // in gpu rendering zone, whill create or destroy texture
2014
#endif
2015
};
2016
2017
#pragma endregion
2018
2019
#pragma region BookMarkFeature
2020
2021
class IGFD_API BookMarkFeature {
2022
protected:
2023
    BookMarkFeature();
2024
2025
#ifdef USE_BOOKMARK
2026
private:
2027
    struct BookmarkStruct {
2028
        std::string name;  // name of the bookmark
2029
2030
        // todo: the path could be relative, better if the app is movedn but bookmarked path can be outside of the app
2031
        std::string path;  // absolute path of the bookmarked directory
2032
2033
        bool defined_by_code = false;  // defined by code, can be used for rpevent serialization / deserialization
2034
    };
2035
2036
private:
2037
    ImGuiListClipper m_BookmarkClipper;
2038
    std::vector<BookmarkStruct> m_Bookmarks;
2039
    char m_BookmarkEditBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = "";
2040
2041
protected:
2042
    float m_BookmarkWidth = 200.0f;
2043
    bool m_BookmarkPaneShown = false;
2044
2045
protected:
2046
    void m_DrawBookmarkButton();                                                            // draw bookmark button
2047
    bool m_DrawBookmarkPane(FileDialogInternal& vFileDialogInternal, const ImVec2& vSize);  // draw bookmark Pane
2048
2049
public:
2050
    std::string SerializeBookmarks(                            // serialize bookmarks : return bookmark buffer to save in a file
2051
        const bool& vDontSerializeCodeBasedBookmarks = true);  // for avoid serialization of bookmarks added by code
2052
    void DeserializeBookmarks(                                 // deserialize bookmarks : load bookmark buffer to load in the dialog (saved from
2053
        const std::string& vBookmarks);                        // previous use with SerializeBookmarks()) bookmark buffer to load
2054
    void AddBookmark(                                          // add a bookmark by code
2055
        const std::string& vBookMarkName,                      // bookmark name
2056
        const std::string& vBookMarkPath);                     // bookmark path
2057
    bool RemoveBookmark(                                       // remove a bookmark by code, return true if succeed
2058
        const std::string& vBookMarkName);                     // bookmark name to remove
2059
2060
#endif  // USE_BOOKMARK
2061
};
2062
2063
#pragma endregion
2064
2065
#pragma region KeyExplorerFeature
2066
2067
// file localization by input chat // widget flashing
2068
class IGFD_API KeyExplorerFeature {
2069
protected:
2070
    KeyExplorerFeature();
2071
2072
#ifdef USE_EXPLORATION_BY_KEYS
2073
private:
2074
    bool m_LocateFileByInputChar_lastFound = false;
2075
    ImWchar m_LocateFileByInputChar_lastChar = 0;
2076
    float m_FlashAlpha = 0.0f;             // flash when select by char
2077
    float m_FlashAlphaAttenInSecs = 1.0f;  // fps display dependant
2078
    int m_LocateFileByInputChar_InputQueueCharactersSize = 0;
2079
    size_t m_FlashedItem = 0;  // flash when select by char
2080
    size_t m_LocateFileByInputChar_lastFileIdx = 0;
2081
2082
protected:
2083
    void m_LocateByInputKey(FileDialogInternal& vFileDialogInternal);  // select a file line in listview according to char key
2084
    bool m_LocateItem_Loop(FileDialogInternal& vFileDialogInternal,
2085
        ImWchar vC);  // restrat for start of list view if not found a corresponding file
2086
    void m_ExploreWithkeys(FileDialogInternal& vFileDialogInternal,
2087
        ImGuiID vListViewID);            // select file/directory line in listview accroding to up/down enter/backspace keys
2088
    void m_StartFlashItem(size_t vIdx);  // define than an item must be flashed
2089
    bool m_BeginFlashItem(size_t vIdx);  // start the flashing of a line in lsit view
2090
    static void m_EndFlashItem();        // end the fleshing accrdoin to var m_FlashAlphaAttenInSecs
2091
    static bool m_FlashableSelectable(const char* label,
2092
        bool selected = false,
2093
        ImGuiSelectableFlags flags = 0,
2094
        bool vFlashing = false,
2095
        const ImVec2& size = ImVec2(0, 0));  // custom flashing selectable widgets, for flash the selected line in a short time
2096
2097
public:
2098
    void SetFlashingAttenuationInSeconds(  // set the flashing time of the line in file list when use exploration keys
2099
        float vAttenValue);                // set the attenuation (from flashed to not flashed) in seconds
2100
#endif                                     // USE_EXPLORATION_BY_KEYS
2101
};
2102
2103
#pragma endregion
2104
2105
#pragma endregion
2106
2107
#pragma region FileDialog
2108
2109
class IGFD_API FileDialog : public BookMarkFeature, public KeyExplorerFeature, public ThumbnailFeature {
2110
protected:
2111
    FileDialogInternal m_FileDialogInternal;
2112
    ImGuiListClipper m_FileListClipper;
2113
    ImGuiListClipper m_PathListClipper;
2114
    float prOkCancelButtonWidth = 0.0f;
2115
2116
public:
2117
    // Singleton for easier accces form anywhere but only one dialog at a time
2118
    // vCopy or vForce can be used for share a memory pointer in a new memory space like a dll module
2119
    static FileDialog* Instance(FileDialog* vCopy = nullptr, bool vForce = false) {
2120
        static FileDialog _instance;
2121
        static FileDialog* _instance_copy = nullptr;
2122
        if (vCopy || vForce) {
2123
            _instance_copy = vCopy;
2124
        }
2125
        if (_instance_copy) {
2126
            return _instance_copy;
2127
        }
2128
        return &_instance;
2129
    }
2130
2131
public:
2132
    FileDialog();           // ImGuiFileDialog Constructor. can be used for have many dialog at same time (not possible with singleton)
2133
    virtual ~FileDialog();  // ImGuiFileDialog Destructor
2134
2135
    //  standard dialog
2136
    virtual void OpenDialog(                    // open simple dialog
2137
        const std::string& vKey,                // key dialog
2138
        const std::string& vTitle,              // title
2139
        const char* vFilters,                   // filters, if null, will display only directories
2140
        const FileDialogConfig& vConfig = {});  // FileDialogConfig
2141
2142
    // Display / Close dialog form
2143
    bool Display(                                               // Display the dialog. return true if a result was obtained (Ok or not)
2144
        const std::string& vKey,                                // key dialog to display (if not the same key as defined by OpenDialog => no opening)
2145
        ImGuiWindowFlags vFlags = ImGuiWindowFlags_NoCollapse,  // ImGuiWindowFlags
2146
        ImVec2 vMinSize = ImVec2(0, 0),                         // mininmal size contraint for the ImGuiWindow
2147
        ImVec2 vMaxSize = ImVec2(FLT_MAX, FLT_MAX));            // maximal size contraint for the ImGuiWindow
2148
    void Close();                                               // close dialog
2149
2150
    // queries
2151
    bool WasOpenedThisFrame(const std::string& vKey) const;  // say if the dialog key was already opened this frame
2152
    bool WasOpenedThisFrame() const;                         // say if the dialog was already opened this frame
2153
    bool IsOpened(const std::string& vKey) const;            // say if the key is opened
2154
    bool IsOpened() const;                                   // say if the dialog is opened somewhere
2155
    std::string GetOpenedKey() const;                        // return the dialog key who is opened, return nothing if not opened
2156
2157
    // get result
2158
    bool IsOk() const;  // true => Dialog Closed with Ok result / false : Dialog closed with cancel result
2159
    std::map<std::string, std::string> GetSelection(
2160
        IGFD_ResultMode vFlag = IGFD_ResultMode_KeepInputFile);  // Open File behavior : will return selection via a
2161
                                                                 // map<FileName, FilePathName>
2162
    std::string GetFilePathName(
2163
        IGFD_ResultMode vFlag = IGFD_ResultMode_AddIfNoFileExt);  // Save File behavior : will return the current file path name
2164
    std::string GetCurrentFileName(IGFD_ResultMode vFlag = IGFD_ResultMode_AddIfNoFileExt);  // Save File behavior : will return the content file name
2165
    std::string GetCurrentPath();                                                            // will return current file path
2166
    std::string GetCurrentFilter();                                                          // will return current filter
2167
    UserDatas GetUserDatas() const;                                                          // will return user datas send with Open Dialog
2168
2169
    // file style by extentions
2170
    void SetFileStyle(                                        // SetExtention datas for have custom display of particular file type
2171
        const IGFD_FileStyleFlags& vFlags,                    // file style
2172
        const char* vCriteria,                                // extention filter to tune
2173
        const FileStyle& vInfos);                             // Filter Extention Struct who contain Color and Icon/Text for the display of the
2174
                                                              // file with extention filter
2175
    void SetFileStyle(                                        // SetExtention datas for have custom display of particular file type
2176
        const IGFD_FileStyleFlags& vFlags,                    // file style
2177
        const char* vCriteria,                                // extention filter to tune
2178
        const ImVec4& vColor,                                 // wanted color for the display of the file with extention filter
2179
        const std::string& vIcon = "",                        // wanted text or icon of the file with extention filter
2180
        ImFont* vFont = nullptr);                             // wanted font
2181
    void SetFileStyle(FileStyle::FileStyleFunctor vFunctor);  // set file style via lambda function
2182
    bool GetFileStyle(                                        // GetExtention datas. return true is extention exist
2183
        const IGFD_FileStyleFlags& vFlags,                    // file style
2184
        const std::string& vCriteria,                         // extention filter (same as used in SetExtentionInfos)
2185
        ImVec4* vOutColor,                                    // color to retrieve
2186
        std::string* vOutIcon = nullptr,                      // icon or text to retrieve
2187
        ImFont** vOutFont = nullptr);                         // font to retreive
2188
    void ClearFilesStyle();                                   // clear extentions setttings
2189
2190
    void SetLocales(                      // set locales to use before and after the dialog display
2191
        const int& vLocaleCategory,       // set local category
2192
        const std::string& vLocaleBegin,  // locale to use at begining of the dialog display
2193
        const std::string& vLocaleEnd);   // locale to use at the end of the dialog display
2194
2195
protected:
2196
    void m_NewFrame();   // new frame just at begining of display
2197
    void m_EndFrame();   // end frame just at end of display
2198
    void m_QuitFrame();  // quit frame when qui quit the dialog
2199
2200
    // others
2201
    bool m_Confirm_Or_OpenOverWriteFileDialog_IfNeeded(
2202
        bool vLastAction, ImGuiWindowFlags vFlags);  // treatment of the result, start the confirm to overwrite dialog
2203
                                                     // if needed (if defined with flag)
2204
2205
    // dialog parts
2206
    virtual void m_DrawHeader();   // draw header part of the dialog (bookmark btn, dir creation, path composer, search
2207
                                   // bar)
2208
    virtual void m_DrawContent();  // draw content part of the dialog (bookmark pane, file list, side pane)
2209
    virtual bool m_DrawFooter();   // draw footer part of the dialog (file field, fitler combobox, ok/cancel btn's)
2210
2211
    // widgets components
2212
    virtual void m_DisplayPathPopup(ImVec2 vSize);  // draw path popup when click on a \ or /
2213
    virtual bool m_DrawValidationButtons();         // draw validations btns, ok, cancel buttons
2214
    virtual bool m_DrawOkButton();                  // draw ok button
2215
    virtual bool m_DrawCancelButton();              // draw cancel button
2216
    virtual void m_DrawSidePane(float vHeight);     // draw side pane
2217
    virtual void m_SelectableItem(int vidx,
2218
        std::shared_ptr<FileInfos> vInfos,
2219
        bool vSelected,
2220
        const char* vFmt,
2221
        ...);                                       // draw a custom selectable behavior item
2222
    virtual void m_DrawFileListView(ImVec2 vSize);  // draw file list view (default mode)
2223
2224
#ifdef USE_THUMBNAILS
2225
    virtual void m_DrawThumbnailsListView(ImVec2 vSize);  // draw file list view with small thumbnails on the same line
2226
    virtual void m_DrawThumbnailsGridView(ImVec2 vSize);  // draw a grid of small thumbnails
2227
#endif
2228
2229
    // to be called only by these function and theirs overrides
2230
    // - m_DrawFileListView
2231
    // - m_DrawThumbnailsListView
2232
    // - m_DrawThumbnailsGridView
2233
    void m_BeginFileColorIconStyle(std::shared_ptr<FileInfos> vFileInfos,
2234
        bool& vOutShowColor,
2235
        std::string& vOutStr,
2236
        ImFont** vOutFont);                                               // begin style apply of filter with color an icon if any
2237
    void m_EndFileColorIconStyle(const bool& vShowColor, ImFont* vFont);  // end style apply of filter
2238
2239
    void m_DisplayFileInfosTooltip(const int32_t& vRowIdx, const int32_t& vColumnIdx, std::shared_ptr<FileInfos> vFileInfos);
2240
};
2241
2242
#pragma endregion
2243
2244
}  // namespace IGFD
2245
2246
#pragma endregion
2247
2248
#endif  // __cplusplus
2249
2250
#pragma region IGFD_C_API
2251
2252
#include <stdint.h>
2253
2254
#if defined _WIN32 || defined __CYGWIN__
2255
#ifdef IMGUIFILEDIALOG_NO_EXPORT
2256
#define API
2257
#else  // IMGUIFILEDIALOG_NO_EXPORT
2258
#define API __declspec(dllexport)
2259
#endif  // IMGUIFILEDIALOG_NO_EXPORT
2260
#else   // defined _WIN32 || defined __CYGWIN__
2261
#ifdef __GNUC__
2262
#define API __attribute__((__visibility__("default")))
2263
#else  // __GNUC__
2264
#define API
2265
#endif  // __GNUC__
2266
#endif  // defined _WIN32 || defined __CYGWIN__
2267
2268
#ifdef __cplusplus
2269
#define IGFD_C_API extern "C" API
2270
typedef IGFD::UserDatas IGFDUserDatas;
2271
typedef IGFD::PaneFun IGFDPaneFun;
2272
typedef IGFD::FileDialog ImGuiFileDialog;
2273
#else  // __cplusplus
2274
#define IGFD_C_API
2275
typedef struct ImGuiFileDialog ImGuiFileDialog;
2276
typedef struct IGFD_Selection_Pair IGFD_Selection_Pair;
2277
typedef struct IGFD_Selection IGFD_Selection;
2278
#endif  // __cplusplus
2279
2280
typedef void (*IGFD_PaneFun)(const char*, void*, bool*);  // callback fucntion for display the pane
2281
2282
struct IGFD_FileDialog_Config {
2283
    const char* path;              // path
2284
    const char* fileName;          // defaut file name
2285
    const char* filePathName;      // if not empty, the filename and the path will be obtained from filePathName
2286
    int32_t countSelectionMax;     // count selection max
2287
    void* userDatas;               // user datas (can be retrieved in pane)
2288
    IGFD_PaneFun sidePane;         // side pane callback
2289
    float sidePaneWidth;  // side pane width};
2290
    ImGuiFileDialogFlags flags;    // ImGuiFileDialogFlags
2291
};
2292
IGFD_C_API IGFD_FileDialog_Config IGFD_FileDialog_Config_Get();  // return an initialized IGFD_FileDialog_Config
2293
2294
struct IGFD_Selection_Pair {
2295
    char* fileName;
2296
    char* filePathName;
2297
};
2298
2299
IGFD_C_API IGFD_Selection_Pair IGFD_Selection_Pair_Get();                                  // return an initialized IGFD_Selection_Pair
2300
IGFD_C_API void IGFD_Selection_Pair_DestroyContent(IGFD_Selection_Pair* vSelection_Pair);  // destroy the content of a IGFD_Selection_Pair
2301
2302
struct IGFD_Selection {
2303
    IGFD_Selection_Pair* table;  // 0
2304
    size_t count;                // 0U
2305
};
2306
2307
IGFD_C_API IGFD_Selection IGFD_Selection_Get();                             // return an initialized IGFD_Selection
2308
IGFD_C_API void IGFD_Selection_DestroyContent(IGFD_Selection* vSelection);  // destroy the content of a IGFD_Selection
2309
2310
// constructor / destructor
2311
IGFD_C_API ImGuiFileDialog* IGFD_Create(void);               // create the filedialog context
2312
IGFD_C_API void IGFD_Destroy(ImGuiFileDialog* vContextPtr);  // destroy the filedialog context
2313
2314
#ifdef USE_THUMBNAILS
2315
typedef void (*IGFD_CreateThumbnailFun)(IGFD_Thumbnail_Info*);   // callback function for create thumbnail texture
2316
typedef void (*IGFD_DestroyThumbnailFun)(IGFD_Thumbnail_Info*);  // callback fucntion for destroy thumbnail texture
2317
#endif                                                           // USE_THUMBNAILS
2318
2319
IGFD_C_API void IGFD_OpenDialog(            // open a standard dialog
2320
    ImGuiFileDialog* vContextPtr,           // ImGuiFileDialog context
2321
    const char* vKey,                       // key dialog
2322
    const char* vTitle,                     // title
2323
    const char* vFilters,                   // filters/filter collections. set it to null for directory mode
2324
    const IGFD_FileDialog_Config vConfig);  // config
2325
2326
IGFD_C_API bool IGFD_DisplayDialog(  // Display the dialog
2327
    ImGuiFileDialog* vContextPtr,    // ImGuiFileDialog context
2328
    const char* vKey,                // key dialog to display (if not the same key as defined by OpenDialog => no opening)
2329
    ImGuiWindowFlags vFlags,         // ImGuiWindowFlags
2330
    ImVec2 vMinSize,                 // mininmal size contraint for the ImGuiWindow
2331
    ImVec2 vMaxSize);                // maximal size contraint for the ImGuiWindow
2332
2333
IGFD_C_API void IGFD_CloseDialog(   // Close the dialog
2334
    ImGuiFileDialog* vContextPtr);  // ImGuiFileDialog context
2335
2336
IGFD_C_API bool IGFD_IsOk(          // true => Dialog Closed with Ok result / false : Dialog closed with cancel result
2337
    ImGuiFileDialog* vContextPtr);  // ImGuiFileDialog context
2338
2339
IGFD_C_API bool IGFD_WasKeyOpenedThisFrame(  // say if the dialog key was already opened this frame
2340
    ImGuiFileDialog* vContextPtr,            // ImGuiFileDialog context
2341
    const char* vKey);
2342
2343
IGFD_C_API bool IGFD_WasOpenedThisFrame(  // say if the dialog was already opened this frame
2344
    ImGuiFileDialog* vContextPtr);        // ImGuiFileDialog context
2345
2346
IGFD_C_API bool IGFD_IsKeyOpened(    // say if the dialog key is opened
2347
    ImGuiFileDialog* vContextPtr,    // ImGuiFileDialog context
2348
    const char* vCurrentOpenedKey);  // the dialog key
2349
2350
IGFD_C_API bool IGFD_IsOpened(      // say if the dialog is opened somewhere
2351
    ImGuiFileDialog* vContextPtr);  // ImGuiFileDialog context
2352
2353
IGFD_C_API IGFD_Selection IGFD_GetSelection(  // Open File behavior : will return selection via a map<FileName, FilePathName>
2354
    ImGuiFileDialog* vContextPtr,             // user datas (can be retrieved in pane)
2355
    IGFD_ResultMode vMode);                   // Result Mode
2356
2357
IGFD_C_API char* IGFD_GetFilePathName(  // Save File behavior : will always return the content of the field with current
2358
                                        // filter extention and current path, WARNINGS you are responsible to free it
2359
    ImGuiFileDialog* vContextPtr,       // ImGuiFileDialog context
2360
    IGFD_ResultMode vMode);             // Result Mode
2361
2362
IGFD_C_API char* IGFD_GetCurrentFileName(  // Save File behavior : will always return the content of the field with
2363
                                           // current filter extention, WARNINGS you are responsible to free it
2364
    ImGuiFileDialog* vContextPtr,          // ImGuiFileDialog context
2365
    IGFD_ResultMode vMode);                // Result Mode
2366
2367
IGFD_C_API char* IGFD_GetCurrentPath(  // will return current path, WARNINGS you are responsible to free it
2368
    ImGuiFileDialog* vContextPtr);     // ImGuiFileDialog context
2369
2370
IGFD_C_API char* IGFD_GetCurrentFilter(  // will return selected filter, WARNINGS you are responsible to free it
2371
    ImGuiFileDialog* vContextPtr);       // ImGuiFileDialog context
2372
2373
IGFD_C_API void* IGFD_GetUserDatas(  // will return user datas send with Open Dialog
2374
    ImGuiFileDialog* vContextPtr);   // ImGuiFileDialog context
2375
2376
IGFD_C_API void IGFD_SetFileStyle(        // SetExtention datas for have custom display of particular file type
2377
    ImGuiFileDialog* vContextPtr,         // ImGuiFileDialog context
2378
    IGFD_FileStyleFlags vFileStyleFlags,  // file style type
2379
    const char* vFilter,                  // extention filter to tune
2380
    ImVec4 vColor,                        // wanted color for the display of the file with extention filter
2381
    const char* vIconText,                // wanted text or icon of the file with extention filter (can be sued with font icon)
2382
    ImFont* vFont);                       // wanted font pointer
2383
2384
IGFD_C_API void IGFD_SetFileStyle2(       // SetExtention datas for have custom display of particular file type
2385
    ImGuiFileDialog* vContextPtr,         // ImGuiFileDialog context
2386
    IGFD_FileStyleFlags vFileStyleFlags,  // file style type
2387
    const char* vFilter,                  // extention filter to tune
2388
    float vR,
2389
    float vG,
2390
    float vB,
2391
    float vA,               // wanted color channels RGBA for the display of the file with extention filter
2392
    const char* vIconText,  // wanted text or icon of the file with extention filter (can be sued with font icon)
2393
    ImFont* vFont);         // wanted font pointer
2394
2395
IGFD_C_API bool IGFD_GetFileStyle(ImGuiFileDialog* vContextPtr,  // ImGuiFileDialog context
2396
    IGFD_FileStyleFlags vFileStyleFlags,                         // file style type
2397
    const char* vFilter,                                         // extention filter (same as used in SetExtentionInfos)
2398
    ImVec4* vOutColor,                                           // color to retrieve
2399
    char** vOutIconText,                                         // icon or text to retrieve, WARNINGS you are responsible to free it
2400
    ImFont** vOutFont);                                          // font pointer to retrived
2401
2402
IGFD_C_API void IGFD_ClearFilesStyle(  // clear extentions setttings
2403
    ImGuiFileDialog* vContextPtr);     // ImGuiFileDialog context
2404
2405
IGFD_C_API void SetLocales(        // set locales to use before and after display
2406
    ImGuiFileDialog* vContextPtr,  // ImGuiFileDialog context
2407
    const int vCategory,           // set local category
2408
    const char* vBeginLocale,      // locale to use at begining of the dialog display
2409
    const char* vEndLocale);       // locale to set at end of the dialog display
2410
2411
#ifdef USE_EXPLORATION_BY_KEYS
2412
IGFD_C_API void IGFD_SetFlashingAttenuationInSeconds(  // set the flashing time of the line in file list when use
2413
                                                       // exploration keys
2414
    ImGuiFileDialog* vContextPtr,                      // ImGuiFileDialog context
2415
    float vAttenValue);                                // set the attenuation (from flashed to not flashed) in seconds
2416
#endif
2417
2418
#ifdef USE_BOOKMARK
2419
IGFD_C_API char* IGFD_SerializeBookmarks(    // serialize bookmarks : return bookmark buffer to save in a file, WARNINGS
2420
                                             // you are responsible to free it
2421
    ImGuiFileDialog* vContextPtr,            // ImGuiFileDialog context
2422
    bool vDontSerializeCodeBasedBookmarks);  // for avoid serialization of bookmarks added by code
2423
2424
IGFD_C_API void IGFD_DeserializeBookmarks(  // deserialize bookmarks : load bookmar buffer to load in the dialog (saved
2425
                                            // from previous use with SerializeBookmarks())
2426
    ImGuiFileDialog* vContextPtr,           // ImGuiFileDialog context
2427
    const char* vBookmarks);                // bookmark buffer to load
2428
2429
IGFD_C_API void IGFD_AddBookmark(  // add a bookmark by code
2430
    ImGuiFileDialog* vContextPtr,  // ImGuiFileDialog context
2431
    const char* vBookMarkName,     // bookmark name
2432
    const char* vBookMarkPath);    // bookmark path
2433
2434
IGFD_C_API void IGFD_RemoveBookmark(  // remove a bookmark by code, return true if succeed
2435
    ImGuiFileDialog* vContextPtr,     // ImGuiFileDialog context
2436
    const char* vBookMarkName);       // bookmark name to remove
2437
#endif
2438
2439
#ifdef USE_THUMBNAILS
2440
IGFD_C_API void SetCreateThumbnailCallback(        // define the callback for create the thumbnails texture
2441
    ImGuiFileDialog* vContextPtr,                  // ImGuiFileDialog context
2442
    IGFD_CreateThumbnailFun vCreateThumbnailFun);  // the callback for create the thumbnails texture
2443
2444
IGFD_C_API void SetDestroyThumbnailCallback(         // define the callback for destroy the thumbnails texture
2445
    ImGuiFileDialog* vContextPtr,                    // ImGuiFileDialog context
2446
    IGFD_DestroyThumbnailFun vDestroyThumbnailFun);  // the callback for destroy the thumbnails texture
2447
2448
IGFD_C_API void ManageGPUThumbnails(  // must be call in gpu zone, possibly a thread, will call the callback for create
2449
                                      // / destroy the textures
2450
    ImGuiFileDialog* vContextPtr);    // ImGuiFileDialog context
2451
#endif                                // USE_THUMBNAILS
2452
2453
#pragma endregion