├── CMakeLists.txt ├── Documentation.md ├── ImGuiFileDialog.cpp ├── ImGuiFileDialog.h ├── ImGuiFileDialogConfig.h ├── LICENSE ├── README.md ├── dirent ├── ChangeLog ├── LICENSE ├── README.md └── dirent.h └── stb ├── LICENSE ├── README.md ├── stb_image.h └── stb_image_resize2.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(ImGuiFileDialog) 4 | 5 | add_library(ImGuiFileDialog STATIC 6 | ImGuiFileDialog.cpp 7 | ImGuiFileDialog.h 8 | ImGuiFileDialogConfig.h 9 | ) 10 | 11 | target_include_directories(ImGuiFileDialog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 12 | 13 | if(UNIX) 14 | target_compile_options(ImGuiFileDialog PUBLIC -Wno-unknown-pragmas) 15 | endif() 16 | -------------------------------------------------------------------------------- /Documentation.md: -------------------------------------------------------------------------------- 1 | # ImGuiFileDialog 2 | 3 | ## Purpose 4 | 5 | ImGuiFileDialog is a file selection dialog built for (and using only) [Dear ImGui](https://github.com/ocornut/imgui). 6 | 7 | My primary goal was to have a custom pane with widgets according to file extension. This was not possible using other 8 | solutions. 9 | 10 | ## Features 11 | 12 | - C Api (succesfully tested with CimGui) 13 | - Separate system for call and display 14 | - Can have many function calls with different parameters for one display function, for example 15 | - Can create a custom pane with any widgets via function binding 16 | - This pane can block the validation of the dialog 17 | - Can also display different things according to current filter and UserDatas 18 | - Advanced file style for file/dir/link coloring / icons / font 19 | - predefined form or user custom form by lambda function (the lambda mode is not available for the C API) 20 | - Multi-selection (ctrl/shift + click) : 21 | - 0 => Infinite 22 | - 1 => One file (default) 23 | - n => n files 24 | - Compatible with MacOs, Linux, Windows, Emscripten, Android 25 | - Supports modal or standard dialog types 26 | - Select files or directories 27 | - Filter groups and custom filter names 28 | - can ignore filter Case for file searching 29 | - Keyboard navigation (arrows, backspace, enter) 30 | - Exploring by entering characters (case insensitive) 31 | - Custom places (bookmarks, system devices, whatever you want) 32 | - Directory manual entry (right click on any path element) 33 | - Optional 'Confirm to Overwrite" dialog if file exists 34 | - Thumbnails Display (agnostic way for compatibility with any backend, sucessfully tested with OpenGl and Vulkan) 35 | - The dialog can be embedded in another user frame than the standard or modal dialog 36 | - Can tune validation buttons (placements, widths, inversion) 37 | - Can quick select a parrallel directory of a path, in the path composer (when you clikc on a / you have a popup) 38 | - regex support for filters, collection of filters and filestyle (the regex is recognized when between (( and )) in a filter) 39 | - multi layer extentions like : .a.b.c .json.cpp .vcxproj.filters etc.. 40 | - advanced behavior regarding asterisk based filter. like : .* .*.* .vcx.* .*.filters .vcs*.filt.* etc.. (internally regex is used) 41 | - result modes GetFilePathName, GetFileName and GetSelection (overwrite file ext, keep file, add ext if no user ext exist) 42 | - you can use your own FileSystem Api 43 | - by default Api Dirent and std::filesystem are defined 44 | - you can override GetDrieveList for specify by ex on android other fs, like local and SDCards 45 | - can select all displayed files with "ctrl+a" as in any OS 46 | - Natural sorting for filenames and extension on deamnde 47 | 48 | ### WARNINGS : 49 | - the nav system keyboard behavior is not working as expected, so maybe full of bug for ImGuiFileDialog 50 | 51 | ### Filter format 52 | 53 | A filter is recognized only if it respects theses rules : 54 | 55 | 0) a filter must have 2 chars mini and the first must be a . 56 | 1) a regex must be in (( and )) 57 | 2) a , will separate filters except if between a ( and ) 58 | 3) name{filter1, filter2} is a special form for collection filters 59 | - the name can be composed of what you want except { and } 60 | - a filter can be a regex 61 | 4) the filters cannot integrate these chars '(' ')' '{' '}' ' ' except for a regex with respect to rule 1) 62 | 5) the filters cannot integrate a ',' 63 | 64 |

Singleton Pattern vs. Multiple Instances :

65 | 66 | ### Single Dialog : 67 | 68 | If you only need to display one file dialog at a time, use ImGuiFileDialog's singleton pattern to avoid explicitly 69 | declaring an object: 70 | 71 | ```cpp 72 | ImGuiFileDialog::Instance()->method_of_your_choice(); 73 | ``` 74 | 75 | ### Multiple Dialogs : 76 | 77 | If you need to have multiple file dialogs open at once, declare each dialog explicity: 78 | 79 | ```cpp 80 | ImGuiFileDialog instance_a; 81 | instance_a.method_of_your_choice(); 82 | ImGuiFileDialog instance_b; 83 | instance_b.method_of_your_choice(); 84 | ``` 85 | 86 |
87 | 88 |

Simple Dialog :

89 | 90 | ```cpp 91 | void drawGui() { 92 | // open Dialog Simple 93 | if (ImGui::Begin("##OpenDialogCommand")) { 94 | if (ImGui::Button("Open File Dialog")) { 95 | IGFD::FileDialogConfig config;config.path = "."; 96 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config); 97 | } 98 | ) 99 | ImGui::End(); 100 | 101 | // display 102 | if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey")) { // => will show a dialog 103 | if (ImGuiFileDialog::Instance()->IsOk()) { // action if OK 104 | std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); 105 | std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); 106 | // action 107 | } 108 | 109 | // close 110 | ImGuiFileDialog::Instance()->Close(); 111 | } 112 | } 113 | ``` 114 | 115 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/dlg_simple.gif) 116 | 117 |
118 | 119 |

Modal Dialog :

120 | 121 | you have now a flag for open modal dialog : 122 | 123 | 124 | ```cpp 125 | ImGuiFileDialogFlags_Modal 126 | ``` 127 | 128 | you can use it like that : 129 | 130 | ```cpp 131 | IGFD::FileDialogConfig config; 132 | config.path = "."; 133 | config.countSelectionMax = 1; 134 | config.flags = ImGuiFileDialogFlags_Modal; 135 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config); 136 | ``` 137 | 138 |
139 | 140 |

Directory Chooser :

141 | 142 | To have a directory chooser, set the file extension filter to nullptr: 143 | 144 | ```cpp 145 | IGFD::FileDialogConfig config; 146 | config.path = "."; 147 | ImGuiFileDialog::Instance()->OpenDialog("ChooseDirDlgKey", "Choose a Directory", nullptr, config); 148 | ``` 149 | 150 | In this mode you can select any directory with one click and open a directory with a double-click. 151 | 152 | ![directoryChooser](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/directoryChooser.gif) 153 | 154 |
155 | 156 |

Dialog with Custom Pane :

157 | 158 | The signature of the custom pane callback is: 159 | 160 | ### for C++ : 161 | 162 | ```cpp 163 | void(const char *vFilter, IGFDUserDatas vUserDatas, bool *vCantContinue) 164 | ``` 165 | 166 | ### for C : 167 | 168 | ```c 169 | void(const char *vFilter, void* vUserDatas, bool *vCantContinue) 170 | ``` 171 | 172 | ### Example : 173 | 174 | ```cpp 175 | static bool canValidateDialog = false; 176 | inline void InfosPane(cosnt char *vFilter, IGFDUserDatas vUserDatas, bool *vCantContinue) // if vCantContinue is false, the user cant validate the dialog 177 | { 178 | ImGui::TextColored(ImVec4(0, 1, 1, 1), "Infos Pane"); 179 | ImGui::Text("Selected Filter : %s", vFilter.c_str()); 180 | if (vUserDatas) 181 | ImGui::Text("UserDatas : %s", vUserDatas); 182 | ImGui::Checkbox("if not checked you cant validate the dialog", &canValidateDialog); 183 | if (vCantContinue) 184 | *vCantContinue = canValidateDialog; 185 | } 186 | 187 | void drawGui() 188 | { 189 | if (ImGui::Begin("##OpenDialogCommand")) { 190 | // open Dialog with Pane 191 | if (ImGui::Button("Open File Dialog with a custom pane")) { 192 | IGFD::FileDialogConfig config; 193 | config.path = "."; 194 | config.countSelectionMax = 1; 195 | config.sidePane = std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); 196 | config.sidePaneWidth = 350.0f; 197 | config.useDatas = UserDatas("InfosPane"); 198 | config.flags = ImGuiFileDialogFlags_Modal; 199 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config); 200 | } 201 | } 202 | ImGui::End(); 203 | 204 | // display and action if ok 205 | if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey")) // => will show a dialog 206 | { 207 | if (ImGuiFileDialog::Instance()->IsOk()) 208 | { 209 | std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); 210 | std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); 211 | std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter(); 212 | // here convert from string because a string was passed as a userDatas, but it can be what you want 213 | std::string userDatas; 214 | if (ImGuiFileDialog::Instance()->GetUserDatas()) 215 | userDatas = std::string((const char*)ImGuiFileDialog::Instance()->GetUserDatas()); 216 | auto selection = ImGuiFileDialog::Instance()->GetSelection(); // multiselection 217 | 218 | // action 219 | } 220 | // close 221 | ImGuiFileDialog::Instance()->Close(); 222 | } 223 | } 224 | ``` 225 | 226 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/dlg_with_pane.gif) 227 | 228 |
229 | 230 |

File Style : Custom icons and colors by extension :

231 | 232 | You can define style for files/dirs/links in many ways : 233 | 234 | the style can be colors, icons and fonts 235 | 236 | the general form is : 237 | ```cpp 238 | ImGuiFileDialog::Instance()->SetFileStyle(styleType, criteria, color, icon, font); 239 | ``` 240 | 241 | ### Predefined Form : 242 | 243 | styleType can be thoses : 244 | 245 | ```cpp 246 | IGFD_FileStyleByTypeFile // define style for all files 247 | IGFD_FileStyleByTypeDir // define style for all dir 248 | IGFD_FileStyleByTypeLink // define style for all link 249 | IGFD_FileStyleByExtention // define style by extention, for files or links 250 | IGFD_FileStyleByFullName // define style for particular file/dir/link full name (filename + extention) 251 | IGFD_FileStyleByContainedInFullName // define style for file/dir/link when criteria is contained in full name 252 | ``` 253 | 254 | ### Lambda Function Form : 255 | 256 | You can define easily your own style include your own detection by using lambda function : 257 | 258 | ** To note, this mode is not available with the C API ** 259 | 260 | this lamba will treat a file and return a shared pointer of your files style 261 | 262 | see in action a styling of all files and dir starting by a dot 263 | 264 | this lambda input a FileInfos and output a FileStyle 265 | return true if a FileStyle was defined 266 | 267 | ```cpp 268 | ImGuiFileDialog::Instance()->SetFileStyle([](const IGFD::FileInfos& vFile, IGFD::FileStyle &vOutStyle) -> bool { 269 | if (!vFile.fileNameExt.empty() && vFile.fileNameExt[0] == '.') { 270 | vOutStyle = IGFD::FileStyle(ImVec4(0.0f, 0.9f, 0.9f, 1.0f), ICON_IGFD_REMOVE); 271 | return true; 272 | } 273 | return false; 274 | }); 275 | ``` 276 | 277 | see sample app for the code in action 278 | 279 | ### Samples : 280 | 281 | ImGuiFileDialog accepts icon font macros as well as text tags for file types. 282 | 283 | [ImGuIFontStudio](https://github.com/aiekick/ImGuiFontStudio) is useful here. I wrote it to make it easy to create 284 | custom icon sets for use with Dear ImGui. 285 | 286 | It is inspired by [IconFontCppHeaders](https://github.com/juliettef/IconFontCppHeaders), which can also be used with 287 | ImGuiFileDialog. 288 | 289 | samples : 290 | 291 | ```cpp 292 | // define style by file extention and Add an icon for .png files 293 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".png", ImVec4(0.0f, 1.0f, 1.0f, 0.9f), ICON_IGFD_FILE_PIC, font1); 294 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".gif", ImVec4(0.0f, 1.0f, 0.5f, 0.9f), "[GIF]"); 295 | 296 | // define style for all directories 297 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FOLDER); 298 | // can be for a specific directory 299 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, ".git", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FOLDER); 300 | 301 | // define style for all files 302 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FILE); 303 | // can be for a specific file 304 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, ".git", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FILE); 305 | 306 | // define style for all links 307 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeLink, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f)); 308 | // can be for a specific link 309 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeLink, "Readme.md", ImVec4(0.5f, 1.0f, 0.9f, 0.9f)); 310 | 311 | // define style for any files/dirs/links by fullname 312 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByFullName, "doc", ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_FILE_PIC); 313 | 314 | // define style by file who are containing this string 315 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByContainedInFullName, ".git", ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_BOOKMARK); 316 | 317 | all of theses can be miwed with IGFD_FileStyleByTypeDir / IGFD_FileStyleByTypeFile / IGFD_FileStyleByTypeLink 318 | like theses by ex : 319 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir | IGFD_FileStyleByContainedInFullName, ".git", ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_BOOKMARK); 320 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile | IGFD_FileStyleByFullName, "cmake", ImVec4(0.5f, 0.8f, 0.5f, 0.9f), ICON_IGFD_SAVE); 321 | 322 | // for all these,s you can use a regex 323 | // ex for color files like Custom*.h 324 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByFullName, "((Custom.+[.]h))", ImVec4(0.0f, 1.0f, 1.0f, 0.9f), ICON_IGFD_FILE_PIC, font1); 325 | 326 | // lambda function 327 | // set file style with a lambda function 328 | // return true is a file style was defined 329 | ImGuiFileDialog::Instance()->SetFileStyle([](const IGFD::FileInfos& vFile, IGFD::FileStyle &vOutStyle) -> bool { 330 | if (!vFile.fileNameExt.empty() && vFile.fileNameExt[0] == '.') { 331 | vOutStyle = IGFD::FileStyle(ImVec4(0.0f, 0.9f, 0.9f, 1.0f), ICON_IGFD_REMOVE); 332 | return true; 333 | } 334 | return false; 335 | }); 336 | ``` 337 | 338 | this sample code of [master/main.cpp](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/main.cpp) produce the picture above : 339 | 340 | ```cpp 341 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".cpp", ImVec4(1.0f, 1.0f, 0.0f, 0.9f)); 342 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".h", ImVec4(0.0f, 1.0f, 0.0f, 0.9f)); 343 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".hpp", ImVec4(0.0f, 0.0f, 1.0f, 0.9f)); 344 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".md", ImVec4(1.0f, 0.0f, 1.0f, 0.9f)); 345 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".png", ImVec4(0.0f, 1.0f, 1.0f, 0.9f), ICON_IGFD_FILE_PIC); // add an icon for the filter type 346 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtention, ".gif", ImVec4(0.0f, 1.0f, 0.5f, 0.9f), "[GIF]"); // add an text for a filter type 347 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, nullptr, ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_IGFD_FOLDER); // for all dirs 348 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, "CMakeLists.txt", ImVec4(0.1f, 0.5f, 0.5f, 0.9f), ICON_IGFD_ADD); 349 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByFullName, "doc", ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_FILE_PIC); 350 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir | IGFD_FileStyleByContainedInFullName, ".git", ImVec4(0.9f, 0.2f, 0.0f, 0.9f), ICON_IGFD_BOOKMARK); 351 | ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile | IGFD_FileStyleByContainedInFullName, ".git", ImVec4(0.5f, 0.8f, 0.5f, 0.9f), ICON_IGFD_SAVE); 352 | ``` 353 | 354 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/color_filter.png) 355 | 356 |
357 | 358 |

Filter Collections :

359 | 360 | You can define a custom filter name that corresponds to a group of filters using this syntax: 361 | 362 | You can also use a regex for the filtering. the regex must be betwwen the ( and ) for be recognized as a regex 363 | 364 | 365 | ```custom_name1{filter1,filter2,filter3,(regex0),(regex1)},custom_name2{filter1,filter2,(regex0)},filter1``` 366 | 367 | When you select custom_name1, filters 1 to 3 will be applied. The characters `{` and `}` are reserved. Don't use them 368 | for filter names. 369 | 370 | 371 | this code : 372 | 373 | ```cpp 374 | const char *filters = "Source files (*.cpp *.h *.hpp){.cpp,.h,.hpp},Image files (*.png *.gif *.jpg *.jpeg){.png,.gif,.jpg,.jpeg},.md"; 375 | IGFD::FileDialogConfig config; 376 | config.path = "."; 377 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", ICON_IMFDLG_FOLDER_OPEN " Choose a File", filters, config); 378 | ``` 379 | 380 | will produce : 381 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/collectionFilters.gif) 382 | 383 |
384 | 385 |

Multi Selection :

386 | 387 | You can define in OpenDialog call the count file you want to select : 388 | 389 | - 0 => infinite 390 | - 1 => one file only (default) 391 | - n => n files only 392 | 393 | See the define at the end of these funcs after path. 394 | 395 | ```cpp 396 | IGFD::FileDialogConfig config; config.path = "."; 397 | 398 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".*,.cpp,.h,.hpp", config); 399 | 400 | config.countSelectionMax = 1; 401 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose 1 File", ".*,.cpp,.h,.hpp", config); 402 | 403 | config.countSelectionMax = 5; 404 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose 5 File", ".*,.cpp,.h,.hpp", config); 405 | 406 | config.countSelectionMax = 0; 407 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose many File", ".*,.cpp,.h,.hpp", config); 408 | 409 | config.countSelectionMax = 1; 410 | config.sidePane = std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); 411 | config.sidePaneWidth = 350.0f; 412 | config.useDatas = UserDatas("SaveFile"); 413 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".png,.jpg", config); // 1 file 414 | ``` 415 | 416 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/multiSelection.gif) 417 | 418 |
419 | 420 |

File Dialog Constraints :

421 | 422 | You can set the minimum and/or maximum size of the dialog: 423 | 424 | ```cpp 425 | ImVec2 maxSize = ImVec2((float)display_w, (float)display_h); // The full display area 426 | ImVec2 minSize = maxSize * 0.5f; // Half the display area 427 | ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey", ImGuiWindowFlags_NoCollapse, minSize, maxSize); 428 | ``` 429 | 430 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/dialog_constraints.gif) 431 | 432 |
433 | 434 |

Exploring by keys :

435 | 436 | You can activate this feature by uncommenting `#define USE_EXPLORATION_BY_KEYS` 437 | in your custom config file (CustomImGuiFileDialogConfig.h) 438 | 439 | You can also uncomment the next lines to define navigation keys: 440 | 441 | * IGFD_KEY_UP => Up key for explore to the top 442 | * IGFD_KEY_DOWN => Down key for explore to the bottom 443 | * IGFD_KEY_ENTER => Enter key for open directory 444 | * IGFD_KEY_BACKSPACE => BackSpace for comming back to the last directory 445 | 446 | You can also jump to a point in the file list by pressing the corresponding key of the first filename character. 447 | 448 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/explore_ny_keys.gif) 449 | 450 | As you see the current item is flashed by default for 1 second. You can define the flashing lifetime with the function 451 | 452 | ```cpp 453 | ImGuiFileDialog::Instance()->SetFlashingAttenuationInSeconds(1.0f); 454 | ``` 455 | 456 |
457 | 458 |

Places :

459 | 460 | the Places system is a generic way for add custom links in the left side pane 461 | 462 | you can organize them by groups 463 | 464 | The bookmarks and devices are now groups in the left side pane. 465 | 466 | for using it you need to 467 | ```cpp 468 | #define USE_PLACES_FEATURE 469 | 470 | // for have default bookmark editable groups 471 | #define USE_PLACES_BOOKMARKS 472 | 473 | // for have default groups for system devices (returned by the IFileSystem interface) 474 | #define USE_PLACES_DEVICES 475 | ``` 476 | 477 | see the config file for more customization 478 | 479 | you can also add your custom groups editable or not like what is done 480 | the DemoApp branch with the "quick access" paths of win10 481 | 482 | You must add a group first, then add a place to it : 483 | 484 | ```cpp 485 | // you must add a group first, specifu display order, and say : 486 | // if the user can add or remove palce like (bookmarks) 487 | // if the group is opened by default 488 | ImGuiFileDialog::Instance()->AddPlacesGroup(group_name, display_order, can_be_user_edited, opened_by_default); 489 | // then you must get the group 490 | auto places_ptr = ImGuiFileDialog::Instance()->GetPlacesGroupPtr(group_name); 491 | if (places_ptr != nullptr) { 492 | // then add a place to the group 493 | // you msut specify the place name, the palce path, say if the palce can be serialized, and sepcify the style 494 | // for the moment the style support only the icon, can be extended if user needed in futur 495 | places_ptr->AddPlace(place_name, place_path, can_be_saved, style); 496 | // you can also add a separator 497 | places_ptr->AddPlaceSeparator(separator_thickness); 498 | } 499 | ``` 500 | 501 | for editable group : 502 | * You can select each place to edit the displayed name corresponding to a path 503 | * Double-click on the label to apply the place 504 | 505 | ![places.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/places.gif) 506 | 507 | You can also serialize/deserialize groups and places (for example to load/save from/to a file): 508 | ```cpp 509 | Load => ImGuiFileDialog::Instance()->DeserializePlaces(placesString); 510 | Save => std::string placesString = ImGuiFileDialog::Instance()->SerializePlaces(); 511 | ``` 512 | 513 | (please see DemoApp branch for details) 514 | 515 |
516 | 517 |

Path Edition :

518 | 519 | Right clicking on any path element button allows the user to manually edit the path from that portion of the tree. 520 | Pressing the completion key (GLFW uses `enter` by default) validates the new path. Pressing the cancel key (GLFW 521 | uses`escape` by default) cancels the manual entry and restores the original path. 522 | 523 | Here's the manual entry operation in action: 524 | ![inputPathEdition.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/inputPathEdition.gif) 525 | 526 |
527 | 528 |

Confirm Overwrite Dialog :

529 | 530 | If you want avoid overwriting files after selection, ImGuiFileDialog can show a dialog to confirm or cancel the 531 | operation. 532 | 533 | To do so, define the flag ImGuiFileDialogFlags_ConfirmOverwrite in your call to OpenDialog/OpenModal. 534 | 535 | 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 536 | behavior. (by design! :) ) 537 | 538 | Example code For Standard Dialog : 539 | 540 | ```cpp 541 | IGFD::FileDialogConfig config; 542 | config.path = "."; 543 | config.flags = ImGuiFileDialogFlags_ConfirmOverwrite; 544 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", 545 | ICON_IGFD_SAVE " Choose a File", filters, config); 546 | ``` 547 | 548 | Example code For Modal Dialog : 549 | 550 | ```cpp 551 | IGFD::FileDialogConfig config; 552 | config.path = "."; 553 | config.flags = ImGuiFileDialogFlags_Modal | ImGuiFileDialogFlags_ConfirmOverwrite; 554 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", ICON_IGFD_SAVE " Choose a File", filters, config); 555 | ``` 556 | 557 | This dialog will only verify the file in the file field, not with `GetSelection()`. 558 | 559 | The confirmation dialog will be a non-movable modal (input blocking) dialog displayed in the middle of the current 560 | ImGuiFileDialog window. 561 | 562 | As usual, you can customize the dialog in your custom config file (CustomImGuiFileDialogConfig.h in this example) 563 | 564 | Uncomment these line for customization options: 565 | 566 | ```cpp 567 | //#define OverWriteDialogTitleString "The file Already Exist !" 568 | //#define OverWriteDialogMessageString "Would you like to OverWrite it ?" 569 | //#define OverWriteDialogConfirmButtonString "Confirm" 570 | //#define OverWriteDialogCancelButtonString "Cancel" 571 | ``` 572 | 573 | See the result : 574 | 575 | ![ConfirmToOverWrite.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/ConfirmToOverWrite.gif) 576 | 577 |
578 | 579 |

Open / Save dialog Behavior :

580 | 581 | ImGuiFileDialog uses the same code internally for Open and Save dialogs. To distinguish between them access the various 582 | data return functions depending on what the dialog is doing. 583 | 584 | When selecting an existing file (for example, a Load or Open dialog), use 585 | 586 | ```cpp 587 | std::map GetSelection(); // Returns selection via a map 588 | UserDatas GetUserDatas(); // Get user data provided by the Open dialog 589 | ``` 590 | 591 | To selecting a new file (for example, a Save As... dialog), use: 592 | 593 | ```cpp 594 | std::string GetFilePathName(); // Returns the content of the selection field with current file extension and current path 595 | std::string GetCurrentFileName(); // Returns the content of the selection field with current file extension but no path 596 | std::string GetCurrentPath(); // Returns current path only 597 | std::string GetCurrentFilter(); // The file extension 598 | ``` 599 | 600 |
601 | 602 |

Thumbnails Display :

603 | 604 | You can now, display thumbnails of pictures. 605 | 606 | ![thumbnails.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/thumbnails.gif) 607 | 608 | The file resize use stb/image so the following files extentions are supported : 609 | * .png (tested sucessfully) 610 | * .bmp (tested sucessfully) 611 | * .tga (tested sucessfully) 612 | * .jpg (tested sucessfully) 613 | * .jpeg (tested sucessfully) 614 | * .gif (tested sucessfully_ but not animation just first frame) 615 | * .psd (not tested) 616 | * .pic (not tested) 617 | * .ppm (not tested) 618 | * .pgm (not tested) 619 | 620 | Corresponding to your backend (ex : OpenGl) you need to define two callbacks : 621 | * the first is a callback who will be called by ImGuiFileDialog for create the backend texture 622 | * the second is a callback who will be called by ImGuiFileDialog for destroy the backend texture 623 | 624 | After that you need to call the function who is responsible to create / destroy the textures. 625 | this function must be called in your GPU Rendering zone for avoid destroying of used texture. 626 | if you do that at the same place of your imgui code, some backend can crash your app, by ex with vulkan. 627 | 628 | To Clarify : 629 | 630 | This feature is spliited in two zones : 631 | - CPU Zone : for load/destroy picture file 632 | - GPU Zone : for load/destroy gpu textures. 633 | This modern behavior for avoid destroying of used texture, 634 | was needed for vulkan. 635 | 636 | This feature was Successfully tested on my side with Opengl and Vulkan. 637 | But im sure is perfectly compatible with other modern apis like DirectX and Metal 638 | 639 | ex, for opengl : 640 | 641 | ```cpp 642 | // Create thumbnails texture 643 | ImGuiFileDialog::Instance()->SetCreateThumbnailCallback([](IGFD_Thumbnail_Info *vThumbnail_Info) -> void 644 | { 645 | if (vThumbnail_Info && 646 | vThumbnail_Info->isReadyToUpload && 647 | vThumbnail_Info->textureFileDatas) 648 | { 649 | GLuint textureId = 0; 650 | glGenTextures(1, &textureId); 651 | vThumbnail_Info->textureID = (void*)textureId; 652 | 653 | glBindTexture(GL_TEXTURE_2D, textureId); 654 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 655 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 656 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 657 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 658 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 659 | (GLsizei)vThumbnail_Info->textureWidth, (GLsizei)vThumbnail_Info->textureHeight, 660 | 0, GL_RGBA, GL_UNSIGNED_BYTE, vThumbnail_Info->textureFileDatas); 661 | glFinish(); 662 | glBindTexture(GL_TEXTURE_2D, 0); 663 | 664 | delete[] vThumbnail_Info->textureFileDatas; 665 | vThumbnail_Info->textureFileDatas = nullptr; 666 | 667 | vThumbnail_Info->isReadyToUpload = false; 668 | vThumbnail_Info->isReadyToDisplay = true; 669 | } 670 | }); 671 | ``` 672 | 673 | ```cpp 674 | // Destroy thumbnails texture 675 | ImGuiFileDialog::Instance()->SetDestroyThumbnailCallback([](IGFD_Thumbnail_Info* vThumbnail_Info) 676 | { 677 | if (vThumbnail_Info) 678 | { 679 | GLuint texID = (GLuint)vThumbnail_Info->textureID; 680 | glDeleteTextures(1, &texID); 681 | glFinish(); 682 | } 683 | }); 684 | ``` 685 | 686 | ```cpp 687 | // GPU Rendering Zone // To call for Create/ Destroy Textures 688 | ImGuiFileDialog::Instance()->ManageGPUThumbnails(); 689 | ``` 690 | 691 |
692 | 693 |

Embedded in other frames :

694 | 695 | The dialog can be embedded in another user frame than the standard or modal dialog 696 | 697 | You have to create a variable of type ImGuiFileDialog. (if you are suing the singleton, you will not have the possibility to open other dialog) 698 | 699 | ex : 700 | 701 | ```cpp 702 | ImGuiFileDialog fileDialog; 703 | 704 | // open dialog; in this case, Bookmark, directory creation are disabled with, and also the file input field is readonly. 705 | // btw you can od what you want 706 | IGFD::FileDialogConfig config; 707 | config.path = "."; 708 | config.countSelectionMax = -1; 709 | config.flags = ImGuiFileDialogFlags_NoDialog | 710 | ImGuiFileDialogFlags_DisableBookmarkMode | 711 | ImGuiFileDialogFlags_DisableCreateDirectoryButton | 712 | ImGuiFileDialogFlags_ReadOnlyFileNameField); 713 | fileDialog.OpenDialog("embedded", "Select File", ".*", config); 714 | // then display, here 715 | // to note, when embedded the ImVec2(0,350) (MinSize) is the frame size, (MaxSize) do nothing 716 | fileDialog.Display("embedded", ImGuiWindowFlags_NoCollapse, ImVec2(0,350))) 717 | ``` 718 | the result : 719 | 720 | ![Embedded.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/Embedded.gif) 721 | 722 |
723 | 724 |

Quick Parallel Path Selection in Path Composer :

725 | 726 | you have a separator between two directories in the path composer 727 | when you click on it you can explore a list of parrallels directories of this point 728 | 729 | this feature is disabled by default 730 | you can enable it with the compiler flag : #define USE_QUICK_PATH_SELECT 731 | 732 | you can also customize the spacing between path button's with and without this mode 733 | you can do that by define the compiler flag : #define CUSTOM_PATH_SPACING 2 734 | if undefined the spacing is defined by the imgui theme 735 | 736 | ![quick_composer_path_select.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/quick_composer_path_select.gif) 737 | 738 |
739 | 740 |

Case Insensitive Filtering :

741 | 742 | you can use this flag 'ImGuiFileDialogFlags_CaseInsensitiveExtention' when you call the open functions 743 | 744 | ``` 745 | by ex : 746 | if the flag ImGuiFileDialogFlags_CaseInsensitiveExtention is used 747 | with filters like .jpg or .Jpg or .JPG 748 | all files with extentions by ex : .jpg and .JPG will be displayed 749 | ``` 750 | 751 |
752 | 753 |

How to Integrate ImGuiFileDialog in your project :

754 | 755 | ### Customize ImGuiFileDialog : 756 | 757 | You can customize many aspects of ImGuiFileDialog by overriding `ImGuiFileDialogConfig.h`. 758 | 759 | To enable your customizations, define the preprocessor directive CUSTOM_IMGUIFILEDIALOG_CONFIG with the path of your 760 | custom config file. This path must be relative to the directory where you put the ImGuiFileDialog module. 761 | 762 | This operation is demonstrated in `CustomImGuiFileDialog.h` in the example project to: 763 | 764 | * Have a custom icon font instead of labels for buttons or message titles 765 | * Customize the button text (the button call signature must be the same, by the way! :) 766 | 767 | The custom icon font used in the example code ([CustomFont.cpp](CustomFont.cpp) and [CustomFont.h](CustomFont.h)) was made 768 | with [ImGuiFontStudio](https://github.com/aiekick/ImGuiFontStudio), which I wrote. :) 769 | 770 | ImGuiFontStudio uses ImGuiFileDialog! Check it out. 771 | 772 | ### Overriding ImGuiFileDialog : 773 | 774 | You can also override it to draw differently or to add/remove widgets. 775 | 776 | Take a look at the example application where I show how to use it to display a read-only checkbox. 777 | 778 | see the 'CustomDrawReadOnlyCheckBoxFileDialog' class. 779 | 780 |
781 | 782 |

Tune the validations button group :

783 | 784 | You can specify : 785 | - the width of "ok" and "cancel" buttons, by the set the defines "okButtonWidth" and "cancelButtonWidth" 786 | - the alignement of the button group (left, right, middle, etc..) by set the define "okCancelButtonAlignement" 787 | - if you want to have the ok button on the left and cancel button on the right or inverted by set the define "invertOkAndCancelButtons" 788 | 789 | just see theses defines in the config file 790 | ```cpp 791 | //Validation buttons 792 | //#define okButtonString " OK" 793 | //#define okButtonWidth 0.0f 794 | //#define cancelButtonString " Cancel" 795 | //#define cancelButtonWidth 0.0f 796 | //alignement [0:1], 0.0 is left, 0.5 middle, 1.0 right, and other ratios 797 | //#define okCancelButtonAlignement 0.0f 798 | //#define invertOkAndCancelButtons false 799 | ``` 800 | with Alignement 0.0 => left 801 | 802 | ![alignement_0.0.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/alignement_0.0.png) 803 | 804 | with Alignement 1.0 => right 805 | 806 | ![alignement_1.0.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/alignement_1.0.png) 807 | 808 | with Alignement 0.5 => middle 809 | 810 | ![alignement_0.5.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/alignement_0.5.png) 811 | 812 | ok and cancel buttons inverted (cancel on the left and ok on the right) 813 | 814 | ![validation_buttons_inverted.gif](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/validation_buttons_inverted.png) 815 | 816 |
817 | 818 |

Filtering by a regex :

819 | 820 | you can use a regex for filtering and file Styling 821 | 822 | for have a filter recognized as a regex, you must have it between a (( and a )) 823 | 824 | this one will filter files who start by the word "Common" and finish by ".h" 825 | ```cpp 826 | ex : "((Custom.+[.]h))" 827 | ``` 828 | 829 | use cases : 830 | 831 | * Simple filter : 832 | ```cpp 833 | OpenDialog("toto", "Choose File", "((Custom.+[.]h))"); 834 | ``` 835 | 836 | * Collections filter : 837 | for this one the filter is between "{" and "}", so you can use the "(" and ")" outside 838 | 839 | ```cpp 840 | OpenDialog("toto", "Choose File", "Source files (*.cpp *.h *.hpp){((Custom.+[.]h)),.h,.hpp}"); 841 | ``` 842 | 843 | * file coloring : 844 | this one will colorized all files who start by the word "Common" and finish by ".h" 845 | ```cpp 846 | SetFileStyle(IGFD_FileStyleByFullName, "((Custom.+[.]h))", ImVec4(1.0f, 1.0f, 0.0f, 0.9f)); 847 | ``` 848 | 849 | * with this feature you can by ex filter and colorize render frame pictures who have ext like .000, .001, .002, etc.. 850 | ```cpp 851 | OpenDialog("toto", "Choose File", "(([.][0-9]{3}))"); 852 | SetFileStyle(IGFD_FileStyleByFullName, "(([.][0-9]{3}))", ImVec4(1.0f, 1.0f, 0.0f, 0.9f)); 853 | ``` 854 | 855 |
856 | 857 |

Multi Layer / asterisk based filter :

858 | 859 | you can add filter in the form : .a.b.c .json.cpp .vcxproj.filters 860 | 861 | you can also add filter in the form : .* .*.* .vcx.* .*.filters .vcx*.filt.* etc.. 862 | all the * based filter are internally using regex's 863 | 864 |
865 | 866 |

Result Modes for GetFilePathName, getFileName and GetSelection :

867 | 868 | you can add have various behavior when you get the file results at dialog end 869 | 870 | you can specify a result mode to thoses function : 871 | 872 | ```cpp 873 | GetFilePathName(IGFD_ResultMode = IGFD_ResultMode_AddIfNoFileExt) 874 | GetFileName(IGFD_ResultMode = IGFD_ResultMode_AddIfNoFileExt) 875 | GetFileSelection(IGFD_ResultMode = IGFD_ResultMode_KeepInputFile) 876 | ``` 877 | You can see these function who their default modes. 878 | but you can modify them. 879 | 880 | There is 3 Modes : 881 | ```cpp 882 | IGFD_ResultMode_AddIfNoFileExt [DEFAULT for 883 | This mode add the filter ext only if there is no file ext. (compatible multi layer) 884 | ex : 885 | filter {.cpp,.h} with file : 886 | toto.h => toto.h 887 | toto.a.h => toto.a.h 888 | toto.a. => toto.a.cpp 889 | toto. => toto.cpp 890 | toto => toto.cpp 891 | filter {.z,.a.b} with file : 892 | toto.a.h => toto.a.h 893 | toto. => toto.z 894 | toto => toto.z 895 | filter {.g.z,.a} with file : 896 | toto.a.h => toto.a.h 897 | toto. => toto.g.z 898 | toto => toto.g.z 899 | 900 | IGFD_ResultMode_OverwriteFileExt 901 | This mode Overwrite the file extention by the current filter 902 | This mode is the old behavior for imGuiFileDialog pre v0.6.6 903 | ex : 904 | filter {.cpp,.h} with file : 905 | toto.h => toto.cpp 906 | toto.a.h => toto.a.cpp 907 | toto.a. => toto.a.cpp 908 | toto.a.h.t => toto.a.h.cpp 909 | toto. => toto.cpp 910 | toto => toto.cpp 911 | filter {.z,.a.b} with file : 912 | toto.a.h => toto.z 913 | toto.a.h.t => toto.a.z 914 | toto. => toto.z 915 | toto => toto.z 916 | filter {.g.z,.a} with file : 917 | toto.a.h => toto.g.z 918 | toto.a.h.y => toto.a.g.z 919 | toto.a. => toto.g.z 920 | toto. => toto.g.z 921 | toto => toto.g.z 922 | 923 | IGFD_ResultMode_KeepInputFile 924 | This mode keep the input file. no modification 925 | es : 926 | filter {.cpp,.h} with file : 927 | toto.h => toto.h 928 | toto. => toto. 929 | toto => toto 930 | filter {.z,.a.b} with file : 931 | toto.a.h => toto.a.h 932 | toto. => toto. 933 | toto => toto 934 | filter {.g.z,.a} with file : 935 | toto.a.h => toto.a.h 936 | toto. => toto. 937 | toto => toto 938 | ``` 939 | 940 | to note : 941 | - in case of a collection of filter. the default filter will be the first. 942 | so in collection {.cpp,((.vcxproj.*)), .ft.*}, the default filter used for renaming will be .cpp 943 | - when you have multilayer filter in collection. 944 | we consider a filter to be replaced according to the max dot of filters for a whole collection 945 | a collection {.a, .b.z} is a two dots filter, so a file toto.g.z will be replaced by toto.a 946 | a collection {.z; .b} is a one dot filter, so a file toto.g.z will be replaced by toto.g.a 947 | 948 |
949 | 950 |

Custom FileSystem

951 | 952 | you can use your custom file system interface. 953 | 954 | by default IGFD come with the File System Interfaces for Dirent or std::filesystem 955 | but you have now a FileSystem interface called IFileSystem who can be overrided with your needs 956 | by ex for android, emscripten, or boost 957 | 958 | 2 steps : 959 | 960 | 1) create a include file who must contain : 961 | - your override of IGFD::IFileSystem 962 | - a define of your class name in FILE_SYSTEM_OVERRIDE (ex : #define FILE_SYSTEM_OVERRIDE FileSystemBoost) 963 | 964 | 2) define your file system include file path in the preprocessor var "CUSTOM_FILESYSTEM_INCLUDE" 965 | ex : #define CUSTOM_FILESYSTEM_INCLUDE "src/FileSystemBoost.hpp" 966 | 967 | you can check the DemoApp who is using an override for the Boost::filesystem 968 | 969 |
970 | 971 |

Modify file infos during scan by a callback

972 | 973 | In some case, it can be unsefull to modify file infos during scan 974 | so you can define your callback and attached it in the FileDialogConfig struct in the field userFileAttributes 975 | 976 | the callback stamp is : 977 | ```cpp 978 | bool (IGFD::FileInfos* vFileInfosPtr, IGFD::UserDatas vUserDatas) 979 | ``` 980 | if the callback is returning false, the file is ignored, so not displayed by the dialog 981 | 982 | example : with the gltf separated files : (see the branch DemoApp for example use) 983 | 984 | A gltf file can have data description and datas files separated. 985 | in this case only the file with description will be shown in the dialog, so with not the full size of all attached datas 986 | 987 | with this function, you can compose the path of the bin file, get his size, sum it to the desciption file size and use it 988 | 989 | syntax : 990 | ```cpp 991 | config.userFileAttributes = [](IGFD::FileInfos* vFileInfosPtr, IGFD::UserDatas vUserDatas) -> bool { 992 | if (vFileInfosPtr != nullptr) { 993 | // this demo not take into account .gltf who have data insise. besauce keepd easy just for demo 994 | if (vFileInfosPtr->SearchForExt(".gltf", true)) { 995 | auto bin_file_path_name = vFileInfosPtr->filePath + IGFD::Utils::GetPathSeparator() + vFileInfosPtr->fileNameLevels[0] + ".bin"; 996 | struct stat statInfos = {}; 997 | char timebuf[100]; 998 | int result = stat(bin_file_path_name.c_str(), &statInfos); 999 | if (!result) { 1000 | vFileInfosPtr->fileSize += (size_t)statInfos.st_size; // add the size of bin file to the size of the gltf file 1001 | } else { 1002 | // no bin, so escaped. 1003 | // normally we must parse the file and check the uri for get the buffer file 1004 | // but here we keep the example as easy for demo. 1005 | return false; 1006 | } 1007 | } 1008 | } 1009 | return true; 1010 | }; 1011 | ``` 1012 | 1013 | Before the User of the userAttribute callback : 1014 | 1015 | ![user_files_attributes_before.png](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/user_files_attributes_before.png) 1016 | 1017 | After : 1018 | 1019 | ![user_files_attributes_after.png](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/user_files_attributes_after.png) 1020 | 1021 | You can also display a tootlip for a file displayed when the mouse is over a dedicated column 1022 | 1023 | you juste need to set your message for the FileDialogConfig.tooltipMessage 1024 | and specify the column in FileDialogConfig.tooltipColumn 1025 | 1026 | ex code from the DemoApp branch for display the decomposition of gltf total size 1027 | 1028 | syntax : 1029 | ```cpp 1030 | vFileInfosPtr->tooltipMessage = toStr("%s : %s\n%s : %s", // 1031 | (vFileInfosPtr->fileNameLevels[0] + ".gltf").c_str(), // 1032 | IGFD::Utils::FormatFileSize(vFileInfosPtr->fileSize).c_str(), // 1033 | (vFileInfosPtr->fileNameLevels[0] + ".bin").c_str(), // 1034 | IGFD::Utils::FormatFileSize((size_t)statInfos.st_size).c_str()); // 1035 | vFileInfosPtr->tooltipColumn = 1; // column of file size 1036 | ``` 1037 | ![file_tooltip_message.png](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/file_tooltip_message.png) 1038 | 1039 |
1040 | 1041 |

Natural sorting

1042 | 1043 | The natural sorting will sort filenames/directories ans their extension 1044 | Since slower than the base sroting, its optionnal and can be anebled with the flag ImGuiFileDialogFlags_NaturalSorting 1045 | 1046 | The supported number format is the same as [strtod](https://cplusplus.com/reference/cstdlib/strtod/) function 1047 | 1048 |
1049 |

C Api :

1050 | 1051 | this api was sucessfully tested with CImGui 1052 | 1053 | A C API is available let you include ImGuiFileDialog in your C project. 1054 | btw, ImGuiFileDialog depend of ImGui and dirent (for windows) 1055 | 1056 | Sample code with cimgui : 1057 | 1058 | ```cpp 1059 | // create ImGuiFileDialog 1060 | ImGuiFileDialog *cfileDialog = IGFD_Create(); 1061 | 1062 | // open dialog 1063 | if (igButton("Open File", buttonSize)) { 1064 | IGFD_FileDialog_Config config = IGFD_FileDialog_Config_Get(); 1065 | config.path = "."; 1066 | config.flags = ImGuiFileDialogFlags_ConfirmOverwrite; // ImGuiFileDialogFlags 1067 | IGFD_OpenDialog(cfiledialog, 1068 | "filedlg", // dialog key (make it possible to have different treatment reagrding the dialog key 1069 | "Open a File", // dialog title 1070 | "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.. 1071 | config); // the file dialog config 1072 | } 1073 | 1074 | ImGuiIO* ioptr = igGetIO(); 1075 | ImVec2 maxSize; 1076 | maxSize.x = ioptr->DisplaySize.x * 0.8f; 1077 | maxSize.y = ioptr->DisplaySize.y * 0.8f; 1078 | ImVec2 minSize; 1079 | minSize.x = maxSize.x * 0.25f; 1080 | minSize.y = maxSize.y * 0.25f; 1081 | 1082 | // display dialog 1083 | if (IGFD_DisplayDialog(cfiledialog, "filedlg", ImGuiWindowFlags_NoCollapse, minSize, maxSize)) 1084 | { 1085 | if (IGFD_IsOk(cfiledialog)) // result ok 1086 | { 1087 | char* cfilePathName = IGFD_GetFilePathName(cfiledialog); 1088 | printf("GetFilePathName : %s\n", cfilePathName); 1089 | char* cfilePath = IGFD_GetCurrentPath(cfiledialog); 1090 | printf("GetCurrentPath : %s\n", cfilePath); 1091 | char* cfilter = IGFD_GetCurrentFilter(cfiledialog); 1092 | printf("GetCurrentFilter : %s\n", cfilter); 1093 | // here convert from string because a string was passed as a userDatas, but it can be what you want 1094 | void* cdatas = IGFD_GetUserDatas(cfiledialog); 1095 | if (cdatas) 1096 | printf("GetUserDatas : %s\n", (const char*)cdatas); 1097 | struct IGFD_Selection csel = IGFD_GetSelection(cfiledialog); // multi selection 1098 | printf("Selection :\n"); 1099 | for (int i = 0; i < (int)csel.count; i++) 1100 | { 1101 | printf("(%i) FileName %s => path %s\n", i, csel.table[i].fileName, csel.table[i].filePathName); 1102 | } 1103 | // action 1104 | 1105 | // destroy 1106 | if (cfilePathName) free(cfilePathName); 1107 | if (cfilePath) free(cfilePath); 1108 | if (cfilter) free(cfilter); 1109 | 1110 | IGFD_Selection_DestroyContent(&csel); 1111 | } 1112 | IGFD_CloseDialog(cfiledialog); 1113 | } 1114 | 1115 | // destroy ImGuiFileDialog 1116 | IGFD_Destroy(cfiledialog); 1117 | ``` 1118 | 1119 |
1120 | -------------------------------------------------------------------------------- /ImGuiFileDialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | _____ _____ _ ______ _ _ _____ _ _ 3 | |_ _| / ____| (_)| ____|(_)| | | __ \ (_) | | 4 | | | _ __ ___ | | __ _ _ _ | |__ _ | | ___ | | | | _ __ _ | | ___ __ _ 5 | | | | '_ ` _ \ | | |_ || | | || || __| | || | / _ \| | | || | / _` || | / _ \ / _` | 6 | _| |_ | | | | | || |__| || |_| || || | | || || __/| |__| || || (_| || || (_) || (_| | 7 | |_____||_| |_| |_| \_____| \__,_||_||_| |_||_| \___||_____/ |_| \__,_||_| \___/ \__, | 8 | __/ | 9 | |___/ 10 | ___ __ ___ 11 | / _ \ / / / _ \ 12 | __ __| | | | / /_ | (_) | 13 | \ \ / /| | | | | '_ \ > _ < 14 | \ V / | |_| |_| (_) |_| (_) | 15 | \_/ \___/(_)\___/(_)\___/ 16 | 17 | GITHUB REPOT : https://github.com/aiekick/ImGuiFileDialog 18 | DOCUMENTATION : see the attached Documentation.md 19 | 20 | generated with "Text to ASCII Art Generator (TAAG)" 21 | https://patorjk.com/software/taag/#p=display&h=1&v=0&f=Big&t=ImGuiFileDialog%0Av0.6.8 22 | 23 | MIT License 24 | 25 | Copyright (c) 2018-2024 Stephane Cuillerdier (aka aiekick) 26 | 27 | Permission is hereby granted, free of charge, to any person obtaining a copy 28 | of this software and associated documentation files (the "Software"), to deal 29 | in the Software without restriction, including without limitation the rights 30 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 31 | copies of the Software, and to permit persons to whom the Software is 32 | furnished to do so, subject to the following conditions: 33 | 34 | The above copyright notice and this permission notice shall be included in all 35 | copies or substantial portions of the Software. 36 | 37 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 39 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 40 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 42 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 43 | SOFTWARE. 44 | */ 45 | 46 | #pragma once 47 | 48 | #define IGFD_VERSION "v0.6.8" 49 | #define IGFD_IMGUI_SUPPORTED_VERSION "1.90.5 WIP" 50 | 51 | // Config file 52 | #ifndef CUSTOM_IMGUIFILEDIALOG_CONFIG 53 | #include "ImGuiFileDialogConfig.h" 54 | #else // CUSTOM_IMGUIFILEDIALOG_CONFIG 55 | #include CUSTOM_IMGUIFILEDIALOG_CONFIG 56 | #endif // CUSTOM_IMGUIFILEDIALOG_CONFIG 57 | 58 | // Define attributes of all API symbols declarations (e.g. for DLL under Windows) 59 | // Using ImGuiFileDialog via a shared library is not recommended, because we don't guarantee 60 | // backward nor forward ABI compatibility and also function call overhead. If you 61 | // do use ImGuiFileDialog as a DLL, be sure to call ImGui::SetImGuiContext (see ImGui doc Miscellanous section). 62 | 63 | #ifndef IGFD_API 64 | #define IGFD_API 65 | #endif // IGFD_API 66 | 67 | /////////////////////////////////////////////////////////// 68 | /////////////// FLAGS ///////////////////////////////////// 69 | /////////////////////////////////////////////////////////// 70 | 71 | // file style enum for file display (color, icon, font) 72 | typedef int IGFD_FileStyleFlags; // -> enum IGFD_FileStyleFlags_ 73 | enum IGFD_FileStyleFlags_ // by evaluation / priority order 74 | { 75 | IGFD_FileStyle_None = 0, // define none style 76 | IGFD_FileStyleByTypeFile = (1 << 0), // define style for all files 77 | IGFD_FileStyleByTypeDir = (1 << 1), // define style for all dir 78 | IGFD_FileStyleByTypeLink = (1 << 2), // define style for all link 79 | IGFD_FileStyleByExtention = (1 << 3), // define style by extention, for files or links 80 | IGFD_FileStyleByFullName = (1 << 4), // define style for particular file/dir/link full name (filename + extention) 81 | IGFD_FileStyleByContainedInFullName = (1 << 5), // define style for file/dir/link when criteria is contained in full name 82 | }; 83 | 84 | typedef int ImGuiFileDialogFlags; // -> enum ImGuiFileDialogFlags_ 85 | enum ImGuiFileDialogFlags_ { 86 | ImGuiFileDialogFlags_None = 0, // define none default flag 87 | ImGuiFileDialogFlags_ConfirmOverwrite = (1 << 0), // show confirm to overwrite dialog 88 | ImGuiFileDialogFlags_DontShowHiddenFiles = (1 << 1), // dont show hidden file (file starting with a .) 89 | ImGuiFileDialogFlags_DisableCreateDirectoryButton = (1 << 2), // disable the create directory button 90 | ImGuiFileDialogFlags_HideColumnType = (1 << 3), // hide column file type 91 | ImGuiFileDialogFlags_HideColumnSize = (1 << 4), // hide column file size 92 | ImGuiFileDialogFlags_HideColumnDate = (1 << 5), // hide column file date 93 | ImGuiFileDialogFlags_NoDialog = (1 << 6), // let the dialog embedded in your own imgui begin / end scope 94 | ImGuiFileDialogFlags_ReadOnlyFileNameField = (1 << 7), // don't let user type in filename field for file open style dialogs 95 | ImGuiFileDialogFlags_CaseInsensitiveExtentionFiltering = (1 << 8), // the file extentions filtering will not take into account the case 96 | ImGuiFileDialogFlags_Modal = (1 << 9), // modal 97 | ImGuiFileDialogFlags_DisableThumbnailMode = (1 << 10), // disable the thumbnail mode 98 | ImGuiFileDialogFlags_DisablePlaceMode = (1 << 11), // disable the place mode 99 | ImGuiFileDialogFlags_DisableQuickPathSelection = (1 << 12), // disable the quick path selection 100 | ImGuiFileDialogFlags_ShowDevicesButton = (1 << 13), // show the devices selection button 101 | ImGuiFileDialogFlags_NaturalSorting = (1 << 14), // enable the antural sorting for filenames and extentions, slower than standard sorting 102 | 103 | // default behavior when no flags is defined. seems to be the more common cases 104 | ImGuiFileDialogFlags_Default = ImGuiFileDialogFlags_ConfirmOverwrite | // 105 | ImGuiFileDialogFlags_Modal | // 106 | ImGuiFileDialogFlags_HideColumnType 107 | }; 108 | 109 | // flags used for GetFilePathName(flag) or GetSelection(flag) 110 | typedef int IGFD_ResultMode; // -> enum IGFD_ResultMode_ 111 | enum IGFD_ResultMode_ { 112 | // IGFD_ResultMode_AddIfNoFileExt 113 | // add the file ext only if there is no file ext 114 | // filter {.cpp,.h} with file : 115 | // toto.h => toto.h 116 | // toto.a.h => toto.a.h 117 | // toto.a. => toto.a.cpp 118 | // toto. => toto.cpp 119 | // toto => toto.cpp 120 | // filter {.z,.a.b} with file : 121 | // toto.a.h => toto.a.h 122 | // toto. => toto.z 123 | // toto => toto.z 124 | // filter {.g.z,.a} with file : 125 | // toto.a.h => toto.a.h 126 | // toto. => toto.g.z 127 | // toto => toto.g.z 128 | IGFD_ResultMode_AddIfNoFileExt = 0, // default 129 | 130 | // IGFD_ResultMode_OverwriteFileExt 131 | // Overwrite the file extention by the current filter : 132 | // filter {.cpp,.h} with file : 133 | // toto.h => toto.cpp 134 | // toto.a.h => toto.a.cpp 135 | // toto.a. => toto.a.cpp 136 | // toto.a.h.t => toto.a.h.cpp 137 | // toto. => toto.cpp 138 | // toto => toto.cpp 139 | // filter {.z,.a.b} with file : 140 | // toto.a.h => toto.z 141 | // toto.a.h.t => toto.a.z 142 | // toto. => toto.z 143 | // toto => toto.z 144 | // filter {.g.z,.a} with file : 145 | // toto.a.h => toto.g.z 146 | // toto.a.h.y => toto.a.g.z 147 | // toto.a. => toto.g.z 148 | // toto. => toto.g.z 149 | // toto => toto.g.z 150 | IGFD_ResultMode_OverwriteFileExt = 1, // behavior pre IGFD v0.6.6 151 | 152 | // IGFD_ResultMode_KeepInputFile 153 | // keep the input file => no modification : 154 | // filter {.cpp,.h} with file : 155 | // toto.h => toto.h 156 | // toto. => toto. 157 | // toto => toto 158 | // filter {.z,.a.b} with file : 159 | // toto.a.h => toto.a.h 160 | // toto. => toto. 161 | // toto => toto 162 | // filter {.g.z,.a} with file : 163 | // toto.a.h => toto.a.h 164 | // toto. => toto. 165 | // toto => toto 166 | IGFD_ResultMode_KeepInputFile = 2 167 | }; 168 | 169 | /////////////////////////////////////////////////////////// 170 | /////////////// STRUCTS /////////////////////////////////// 171 | /////////////////////////////////////////////////////////// 172 | 173 | #ifdef USE_THUMBNAILS 174 | struct IGFD_Thumbnail_Info { 175 | int isReadyToDisplay = 0; // ready to be rendered, so texture created 176 | int isReadyToUpload = 0; // ready to upload to gpu 177 | int isLoadingOrLoaded = 0; // was sent to laoding or loaded 178 | int textureWidth = 0; // width of the texture to upload 179 | int textureHeight = 0; // height of the texture to upload 180 | int textureChannels = 0; // count channels of the texture to upload 181 | unsigned char* textureFileDatas = 0; // file texture datas, will be rested to null after gpu upload 182 | void* textureID = 0; // 2d texture id (void* is like ImtextureID type) (GL, DX, VK, Etc..) 183 | void* userDatas = 0; // user datas 184 | }; 185 | #endif // USE_THUMBNAILS 186 | 187 | // stdint is used for cpp and c apî (cstdint is only for cpp) 188 | #include 189 | 190 | #ifdef __cplusplus 191 | 192 | #ifndef IMGUI_DEFINE_MATH_OPERATORS 193 | #define IMGUI_DEFINE_MATH_OPERATORS 194 | #endif // IMGUI_DEFINE_MATH_OPERATORS 195 | 196 | #ifdef IMGUI_INCLUDE 197 | #include IMGUI_INCLUDE 198 | #else // IMGUI_INCLUDE 199 | #include 200 | #endif // IMGUI_INCLUDE 201 | 202 | #include 203 | #include 204 | #include 205 | #include 206 | #include 207 | #include 208 | #include 209 | #include 210 | #include 211 | #include 212 | #include 213 | #include 214 | #include 215 | #include 216 | #include 217 | #include 218 | 219 | #ifndef defaultSortField 220 | #define defaultSortField FIELD_FILENAME 221 | #endif // defaultSortField 222 | 223 | #ifndef defaultSortOrderFilename 224 | #define defaultSortOrderFilename true 225 | #endif // defaultSortOrderFilename 226 | #ifndef defaultSortOrderType 227 | #define defaultSortOrderType true 228 | #endif // defaultSortOrderType 229 | #ifndef defaultSortOrderSize 230 | #define defaultSortOrderSize true 231 | #endif // defaultSortOrderSize 232 | #ifndef defaultSortOrderDate 233 | #define defaultSortOrderDate true 234 | #endif // defaultSortOrderDate 235 | #ifndef defaultSortOrderThumbnails 236 | #define defaultSortOrderThumbnails true 237 | #endif // defaultSortOrderThumbnails 238 | 239 | #ifndef MAX_FILE_DIALOG_NAME_BUFFER 240 | #define MAX_FILE_DIALOG_NAME_BUFFER 1024 241 | #endif // MAX_FILE_DIALOG_NAME_BUFFER 242 | 243 | #ifndef MAX_PATH_BUFFER_SIZE 244 | #define MAX_PATH_BUFFER_SIZE 1024 245 | #endif // MAX_PATH_BUFFER_SIZE 246 | 247 | #ifndef EXT_MAX_LEVEL 248 | #define EXT_MAX_LEVEL 10U 249 | #endif // EXT_MAX_LEVEL 250 | 251 | namespace IGFD { 252 | 253 | template 254 | class SearchableVector { 255 | private: 256 | std::unordered_map m_Dico; 257 | std::vector m_Array; 258 | 259 | public: 260 | void clear() { 261 | m_Dico.clear(); 262 | m_Array.clear(); 263 | } 264 | bool empty() const { 265 | return m_Array.empty(); 266 | } 267 | size_t size() const { 268 | return m_Array.size(); 269 | } 270 | T& operator[](const size_t& vIdx) { 271 | return m_Array[vIdx]; 272 | } 273 | T& at(const size_t& vIdx) { 274 | return m_Array.at(vIdx); 275 | } 276 | typename std::vector::iterator begin() { 277 | return m_Array.begin(); 278 | } 279 | typename std::vector::const_iterator begin() const { 280 | return m_Array.begin(); 281 | } 282 | typename std::vector::iterator end() { 283 | return m_Array.end(); 284 | } 285 | typename std::vector::const_iterator end() const { 286 | return m_Array.end(); 287 | } 288 | 289 | bool try_add(T vKey) { 290 | if (!exist(vKey)) { 291 | m_Dico[vKey] = m_Array.size(); 292 | m_Array.push_back(vKey); 293 | return true; 294 | } 295 | return false; 296 | } 297 | 298 | bool try_set_existing(T vKey) { 299 | if (exist(vKey)) { 300 | auto row = m_Dico.at(vKey); 301 | m_Array[row] = vKey; 302 | return true; 303 | } 304 | return false; 305 | } 306 | 307 | bool exist(const std::string& vKey) const { 308 | return (m_Dico.find(vKey) != m_Dico.end()); 309 | } 310 | }; 311 | 312 | class IGFD_API FileInfos; 313 | class IGFD_API FileDialogInternal; 314 | 315 | class IGFD_API Utils { 316 | friend class TestUtils; 317 | public: 318 | struct PathStruct { 319 | std::string path; 320 | std::string name; 321 | std::string ext; 322 | bool isOk = false; 323 | }; 324 | 325 | public: 326 | static bool ImSplitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f); 327 | static bool ReplaceString(std::string& str, const std::string& oldStr, const std::string& newStr, const size_t& vMaxRecursion = 10U); 328 | static void AppendToBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr); 329 | static void ResetBuffer(char* vBuffer); 330 | static void SetBuffer(char* vBuffer, size_t vBufferLen, const std::string& vStr); 331 | static std::string UTF8Encode(const std::wstring& wstr); 332 | static std::wstring UTF8Decode(const std::string& str); 333 | static std::vector SplitStringToVector(const std::string& vText, const std::string& vDelimiterPattern, const bool vPushEmpty); 334 | static std::vector SplitStringToVector(const std::string& vText, const char& vDelimiter, const bool vPushEmpty); 335 | static std::string LowerCaseString(const std::string& vString); // turn all text in lower case for search facilitie 336 | static size_t GetCharCountInString(const std::string& vString, const char& vChar); 337 | static size_t GetLastCharPosWithMinCharCount(const std::string& vString, const char& vChar, const size_t& vMinCharCount); 338 | static std::string GetPathSeparator(); // return the slash for any OS ( \\ win, / unix) 339 | static std::string RoundNumber(double vvalue, int n); // custom rounding number 340 | static std::string FormatFileSize(size_t vByteSize); // format file size field 341 | static bool NaturalCompare(const std::string& vA, const std::string& vB, bool vInsensitiveCase, bool vDescending); // natural sorting 342 | 343 | private: 344 | static bool M_IsAValidCharExt(const char& c); 345 | static bool M_IsAValidCharSuffix(const char& c); 346 | static bool M_ExtractNumFromStringAtPos(const std::string& str, size_t& pos, double& vOutNum); 347 | }; 348 | 349 | class IGFD_API FileStyle { 350 | public: 351 | typedef std::function FileStyleFunctor; 352 | 353 | public: 354 | ImVec4 color = ImVec4(0, 0, 0, 0); 355 | std::string icon; 356 | ImFont* font = nullptr; 357 | IGFD_FileStyleFlags flags = 0; 358 | 359 | public: 360 | FileStyle(); 361 | FileStyle(const FileStyle& vStyle); 362 | FileStyle(const ImVec4& vColor, const std::string& vIcon = "", ImFont* vFont = nullptr); 363 | }; 364 | 365 | class IGFD_API SearchManager { 366 | public: 367 | std::string searchTag; 368 | char searchBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; 369 | bool searchInputIsActive = false; 370 | 371 | public: 372 | void Clear(); // clear datas 373 | void DrawSearchBar(FileDialogInternal& vFileDialogInternal); // draw the search bar 374 | }; 375 | 376 | class IGFD_API FilterInfos { 377 | private: 378 | // just for return a default const std::string& in getFirstFilter. 379 | // cannot be const, because FilterInfos must be affected to an another FilterInfos 380 | // must stay empty all time 381 | std::string empty_string; 382 | 383 | public: 384 | std::string title; // displayed filter.can be different than rela filter 385 | SearchableVector filters; // filters 386 | SearchableVector filters_optimized; // optimized filters for case insensitive search 387 | std::vector filters_regex; // collection of regex filter type 388 | size_t count_dots = 0U; // the max count dot the max per filter of all filters 389 | 390 | public: 391 | void clear(); // clear the datas 392 | bool empty() const; // is filter empty 393 | const std::string& getFirstFilter() const; // get the first filter 394 | bool regexExist(const std::string& vFilter) const; // is regex filter exist 395 | bool exist(const FileInfos& vFileInfos, bool vIsCaseInsensitive) const; // is filter exist 396 | void setCollectionTitle(const std::string& vTitle); // set the collection title 397 | void addFilter(const std::string& vFilter, const bool vIsRegex); // add a filter 398 | void addCollectionFilter(const std::string& vFilter, const bool vIsRegex); // add a filter in collection 399 | static std::string transformAsteriskBasedFilterToRegex(const std::string& vFilter); // will transform a filter who contain * to a regex 400 | }; 401 | 402 | class IGFD_API FilterManager { 403 | friend class TestFilterManager; 404 | private: 405 | std::vector m_ParsedFilters; 406 | std::unordered_map > > m_FilesStyle; // file infos for file 407 | // extention only 408 | std::vector m_FilesStyleFunctors; // file style via lambda function 409 | FilterInfos m_SelectedFilter; 410 | 411 | public: 412 | std::string dLGFilters; 413 | std::string dLGdefaultExt; 414 | 415 | public: 416 | const FilterInfos& GetSelectedFilter() const; 417 | void ParseFilters(const char* vFilters); // Parse filter syntax, detect and parse filter collection 418 | void SetSelectedFilterWithExt(const std::string& vFilter); // Select filter 419 | bool FillFileStyle(std::shared_ptr vFileInfos) const; // fill with the good style 420 | void SetFileStyle(const IGFD_FileStyleFlags& vFlags, const char* vCriteria, const FileStyle& vInfos); // Set FileStyle 421 | void SetFileStyle(const IGFD_FileStyleFlags& vFlags, const char* vCriteria, const ImVec4& vColor, const std::string& vIcon, 422 | ImFont* vFont); // link file style to Color and Icon and Font 423 | void SetFileStyle(FileStyle::FileStyleFunctor vFunctor); // lambda functor for set file style. 424 | bool GetFileStyle(const IGFD_FileStyleFlags& vFlags, const std::string& vCriteria, ImVec4* vOutColor, std::string* vOutIcon, 425 | ImFont** vOutFont); // Get Color and Icon for Filter 426 | void ClearFilesStyle(); // clear m_FileStyle 427 | bool IsCoveredByFilters(const FileInfos& vFileInfos, 428 | bool vIsCaseInsensitive) const; // check if current file extention (vExt) is covered by current filter, or by regex (vNameExt) 429 | float GetFilterComboBoxWidth() const; // will return the current combo box widget width 430 | bool DrawFilterComboBox(FileDialogInternal& vFileDialogInternal); // draw the filter combobox // get the current selected filter 431 | std::string ReplaceExtentionWithCurrentFilterIfNeeded(const std::string& vFileName, 432 | IGFD_ResultMode vFlag) const; // replace the extention of the current file by the selected filter 433 | void SetDefaultFilterIfNotDefined(); // define the first filter if no filter is selected 434 | }; 435 | 436 | class IGFD_API FileType { 437 | public: 438 | enum class ContentType { 439 | // The ordering will be used during sort. 440 | Invalid = -1, 441 | Directory = 0, 442 | File = 1, 443 | LinkToUnknown = 2, // link to something that is not a regular file or directory. 444 | }; 445 | 446 | private: 447 | ContentType m_Content = ContentType::Invalid; 448 | bool m_Symlink = false; 449 | 450 | public: 451 | FileType(); 452 | FileType(const ContentType& vContentType, const bool vIsSymlink); 453 | 454 | void SetContent(const ContentType& vContentType); 455 | void SetSymLink(const bool vIsSymlink); 456 | 457 | bool isValid() const; 458 | bool isDir() const; 459 | bool isFile() const; 460 | bool isLinkToUnknown() const; 461 | bool isSymLink() const; 462 | 463 | // Comparisons only care about the content type, ignoring whether it's a symlink or not. 464 | bool operator==(const FileType& rhs) const; 465 | bool operator!=(const FileType& rhs) const; 466 | bool operator<(const FileType& rhs) const; 467 | bool operator>(const FileType& rhs) const; 468 | }; 469 | 470 | class IGFD_API FileInfos { 471 | public: 472 | static std::shared_ptr create(); 473 | 474 | public: 475 | // 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} 476 | // 10 level max are sufficient i guess. the others levels will be checked if countExtDot > 1 477 | std::array fileExtLevels; 478 | std::array fileExtLevels_optimized; // optimized for search => insensitivecase 479 | // same for file name, can be sued in userFileAttributesFun 480 | std::array fileNameLevels; 481 | std::array fileNameLevels_optimized; // optimized for search => insensitivecase 482 | size_t countExtDot = 0U; // count dots in file extention. this count will give the levels in fileExtLevels 483 | FileType fileType; // fileType 484 | std::string filePath; // path of the file 485 | std::string fileName; // file name only 486 | std::string fileNameExt; // filename of the file (file name + extention) (but no path) 487 | std::string fileNameExt_optimized; // optimized for search => insensitivecase 488 | std::string deviceInfos; // quick infos to display after name for devices 489 | std::string tooltipMessage; // message to display on the tooltip, is not empty 490 | int32_t tooltipColumn = -1; // the tooltip will appears only when the mouse is over the tooltipColumn if > -1 491 | size_t fileSize = 0U; // for sorting operations 492 | std::string formatedFileSize; // file size formated (10 o, 10 ko, 10 mo, 10 go) 493 | std::string fileModifDate; // file user defined format of the date (data + time by default) 494 | std::shared_ptr fileStyle = nullptr; // style of the file 495 | #ifdef USE_THUMBNAILS 496 | IGFD_Thumbnail_Info thumbnailInfo; // structre for the display for image file tetxure 497 | #endif // USE_THUMBNAILS 498 | 499 | public: 500 | bool SearchForTag(const std::string& vTag) const; // will search a tag in fileNameExt and fileNameExt_optimized 501 | bool SearchForExt(const std::string& vExt, const bool vIsCaseInsensitive, 502 | const size_t& vMaxLevel = EXT_MAX_LEVEL) const; // will check the fileExtLevels levels for vExt, until vMaxLevel 503 | bool SearchForExts(const std::string& vComaSepExts, const bool vIsCaseInsensitive, 504 | const size_t& vMaxLevel = EXT_MAX_LEVEL) const; // will check the fileExtLevels levels for vExts (ext are coma separated), until vMaxLevel 505 | bool FinalizeFileTypeParsing(const size_t& vMaxDotToExtract); // finalize the parsing the file (only a file or link to file. no dir) 506 | }; 507 | 508 | typedef std::pair PathDisplayedName; 509 | 510 | class IFileSystem { 511 | public: 512 | virtual ~IFileSystem() = default; 513 | // say if a directory can be openened or for any reason locked 514 | virtual bool IsDirectoryCanBeOpened(const std::string& vName) = 0; 515 | // say if a directory exist 516 | virtual bool IsDirectoryExist(const std::string& vName) = 0; 517 | // say if a file exist 518 | virtual bool IsFileExist(const std::string& vName) = 0; 519 | // say if a directory was created, return false if vName is invalid or alreayd exist 520 | virtual bool CreateDirectoryIfNotExist(const std::string& vName) = 0; 521 | // extract the component of a file path name, like path, name, ext 522 | virtual IGFD::Utils::PathStruct ParsePathFileName(const std::string& vPathFileName) = 0; 523 | // will return a list of files inside a path 524 | virtual std::vector ScanDirectory(const std::string& vPath) = 0; 525 | // say if the path is well a directory 526 | virtual bool IsDirectory(const std::string& vFilePathName) = 0; 527 | // return a device list () on windows, but can be used on other platforms for give to the user a list of devices paths. 528 | virtual std::vector GetDevicesList() = 0; 529 | }; 530 | 531 | class IGFD_API FileManager { 532 | friend class TestFileManager; 533 | public: // types 534 | enum class SortingFieldEnum { // sorting for filetering of the file lsit 535 | FIELD_NONE = 0, // no sorting reference, result indetermined haha.. 536 | FIELD_FILENAME, // sorted by filename 537 | FIELD_TYPE, // sorted by filetype 538 | FIELD_SIZE, // sorted by filesize (formated file size) 539 | FIELD_DATE, // sorted by filedate 540 | FIELD_THUMBNAILS, // sorted by thumbnails (comparaison by width then by height) 541 | }; 542 | 543 | private: 544 | std::string m_CurrentPath; // current path (to be decomposed in m_CurrentPathDecomposition 545 | std::vector m_CurrentPathDecomposition; // part words 546 | std::vector > m_FileList; // base container 547 | std::vector > m_FilteredFileList; // filtered container (search, sorting, etc..) 548 | std::vector > m_PathList; // base container for path selection 549 | std::vector > m_FilteredPathList; // filtered container for path selection (search, sorting, etc..) 550 | std::vector::iterator m_PopupComposedPath; // iterator on m_CurrentPathDecomposition for Current Path popup 551 | std::string m_LastSelectedFileName; // for shift multi selection 552 | std::set m_SelectedFileNames; // the user selection of FilePathNames 553 | bool m_CreateDirectoryMode = false; // for create directory widget 554 | std::string m_FileSystemName; 555 | std::unique_ptr m_FileSystemPtr = nullptr; 556 | 557 | public: 558 | bool inputPathActivated = false; // show input for path edition 559 | bool devicesClicked = false; // event when a drive button is clicked 560 | bool pathClicked = false; // event when a path button was clicked 561 | char inputPathBuffer[MAX_PATH_BUFFER_SIZE] = ""; // input path buffer for imgui widget input text (displayed in palce of composer) 562 | char variadicBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // called by m_SelectableItem 563 | char fileNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // file name buffer in footer for imgui widget input text 564 | char directoryNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // directory name buffer (when in directory mode) 565 | std::string headerFileName; // detail view name of column file 566 | std::string headerFileType; // detail view name of column type 567 | std::string headerFileSize; // detail view name of column size 568 | std::string headerFileDate; // detail view name of column date + time 569 | #ifdef USE_THUMBNAILS 570 | std::string headerFileThumbnails; // detail view name of column thumbnails 571 | bool sortingDirection[5] = { // true => Ascending, false => Descending 572 | defaultSortOrderFilename, defaultSortOrderType, defaultSortOrderSize, defaultSortOrderDate, defaultSortOrderThumbnails}; 573 | #else 574 | bool sortingDirection[4] = { // true => Ascending, false => Descending 575 | defaultSortOrderFilename, defaultSortOrderType, defaultSortOrderSize, defaultSortOrderDate}; 576 | #endif 577 | SortingFieldEnum sortingField = SortingFieldEnum::FIELD_FILENAME; // detail view sorting column 578 | bool showDevices = false; // devices are shown (only on os windows) 579 | 580 | std::string dLGpath; // base path set by user when OpenDialog was called 581 | std::string dLGDefaultFileName; // base default file path name set by user when OpenDialog was called 582 | size_t dLGcountSelectionMax = 1U; // 0 for infinite // base max selection count set by user when OpenDialog was called 583 | bool dLGDirectoryMode = false; // is directory mode (defiend like : dLGDirectoryMode = (filters.empty())) 584 | 585 | std::string fsRoot; 586 | 587 | private: 588 | static void m_CompleteFileInfos(const std::shared_ptr& vInfos); // set time and date infos of a file (detail view mode) 589 | void m_RemoveFileNameInSelection(const std::string& vFileName); // selection : remove a file name 590 | void m_AddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName); // selection : add a file name 591 | void m_AddFile(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, 592 | const FileType& vFileType); // add file called by scandir 593 | void m_AddPath(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, 594 | const FileType& vFileType); // add file called by scandir 595 | void m_ScanDirForPathSelection(const FileDialogInternal& vFileDialogInternal, 596 | const std::string& vPath); // scan the directory for retrieve the path list 597 | void m_OpenPathPopup(const FileDialogInternal& vFileDialogInternal, 598 | std::vector::iterator vPathIter); // open the popup list of paths 599 | void m_SetCurrentPath(std::vector::iterator vPathIter); // set the current path, update the path bar 600 | void m_ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal, std::vector >& vFileInfosList, std::vector >& vFileInfosFilteredList); 601 | static bool M_SortStrings(const FileDialogInternal& vFileDialogInternal, // 602 | const bool vInsensitiveCase, const bool vDescendingOrder, // 603 | const std::string& vA, const std::string& vB); 604 | void m_SortFields(const FileDialogInternal& vFileDialogInternal, std::vector >& vFileInfosList, 605 | std::vector >& vFileInfosFilteredList); // will sort a column 606 | bool m_CompleteFileInfosWithUserFileAttirbutes(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr& vInfos); 607 | 608 | public: 609 | FileManager(); 610 | bool IsComposerEmpty() const; 611 | size_t GetComposerSize() const; 612 | bool IsFileListEmpty() const; 613 | bool IsPathListEmpty() const; 614 | bool IsFilteredListEmpty() const; 615 | bool IsPathFilteredListEmpty() const; 616 | size_t GetFullFileListSize() const; 617 | std::shared_ptr GetFullFileAt(size_t vIdx); 618 | size_t GetFilteredListSize() const; 619 | size_t GetPathFilteredListSize() const; 620 | std::shared_ptr GetFilteredFileAt(size_t vIdx); 621 | std::shared_ptr GetFilteredPathAt(size_t vIdx); 622 | std::vector::iterator GetCurrentPopupComposedPath() const; 623 | bool IsFileNameSelected(const std::string& vFileName); 624 | std::string GetBack(); 625 | void ClearComposer(); 626 | void ClearFileLists(); // clear file list, will destroy thumbnail textures 627 | void ClearPathLists(); // clear path list, will destroy thumbnail textures 628 | void ClearAll(); 629 | void ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal); 630 | void SortFields(const FileDialogInternal& vFileDialogInternal); // will sort a column 631 | void OpenCurrentPath(const FileDialogInternal& vFileDialogInternal); // set the path of the dialog, will launch the scandir for populate the file listview 632 | bool GetDevices(); // list devices 633 | bool CreateDir(const std::string& vPath); // create a directory on the file system 634 | std::string ComposeNewPath(std::vector::iterator vIter); // compose a path from the compose path widget 635 | bool SetPathOnParentDirectoryIfAny(); // compose paht on parent directory 636 | std::string GetCurrentPath(); // get the current path 637 | void SetCurrentPath(const std::string& vCurrentPath); // set the current path 638 | void SetDefaultFileName(const std::string& vFileName); 639 | bool SelectDirectory(const std::shared_ptr& vInfos); // enter directory 640 | void SelectAllFileNames(); 641 | void SelectFileName(const std::shared_ptr& vInfos); // add a filename in selection 642 | void SelectOrDeselectFileName(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr& vInfos); // add/remove a filename in selection 643 | void SetCurrentDir(const std::string& vPath); // define current directory for scan 644 | void ScanDir(const FileDialogInternal& vFileDialogInternal, 645 | const std::string& vPath); // scan the directory for retrieve the file list 646 | std::string GetResultingPath(); 647 | std::string GetResultingFileName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag); 648 | std::string GetResultingFilePathName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag); 649 | std::map GetResultingSelection(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag); 650 | 651 | void DrawDirectoryCreation(const FileDialogInternal& vFileDialogInternal); // draw directory creation widget 652 | void DrawPathComposer(const FileDialogInternal& vFileDialogInternal); 653 | 654 | IFileSystem* GetFileSystemInstance() const { 655 | return m_FileSystemPtr.get(); 656 | } 657 | const std::string& GetFileSystemName() const { 658 | return m_FileSystemName; 659 | } 660 | }; 661 | 662 | typedef void* UserDatas; 663 | typedef std::function PaneFun; // side pane function binding 664 | typedef std::function UserFileAttributesFun; // custom file Attributes call back, reject file if false 665 | 666 | struct IGFD_API FileDialogConfig { 667 | std::string path; // path 668 | std::string fileName; // defaut file name 669 | std::string filePathName; // if not empty, the filename and the path will be obtained from filePathName 670 | int32_t countSelectionMax = 1; // count selection max, 0 for infinite 671 | UserDatas userDatas = nullptr; // user datas (can be retrieved in pane) 672 | ImGuiFileDialogFlags flags = ImGuiFileDialogFlags_None; // ImGuiFileDialogFlags 673 | PaneFun sidePane; // side pane callback 674 | float sidePaneWidth = 250.0f; // side pane width 675 | UserFileAttributesFun userFileAttributes; // user file Attibutes callback 676 | }; 677 | 678 | class IGFD_API FileDialogInternal { 679 | public: 680 | FileManager fileManager; // the file manager 681 | FilterManager filterManager; // the filter manager 682 | SearchManager searchManager; // the search manager 683 | 684 | public: 685 | std::string name; // the internal dialog name (title + ##word) 686 | bool showDialog = false; // the dialog is shown 687 | ImVec2 dialogCenterPos = ImVec2(0, 0); // center pos for display the confirm overwrite dialog 688 | int lastImGuiFrameCount = 0; // to be sure than only one dialog displayed per frame 689 | float footerHeight = 0.0f; // footer height 690 | bool canWeContinue = true; // events 691 | bool okResultToConfirm = false; // to confim if ok for OverWrite 692 | bool isOk = false; // is dialog ok button click 693 | bool fileInputIsActive = false; // when input text for file or directory is active 694 | bool fileListViewIsActive = false; // when list view is active 695 | std::string dLGkey; // the dialog key 696 | std::string dLGtitle; // the dialog title 697 | bool needToExitDialog = false; // we need to exit the dialog 698 | bool puUseCustomLocale = false; // custom user locale 699 | int localeCategory = LC_ALL; // locale category to use 700 | std::string localeBegin; // the locale who will be applied at start of the display dialog 701 | std::string localeEnd; // the locale who will be applaied at end of the display dialog 702 | 703 | private: 704 | FileDialogConfig m_DialogConfig; 705 | 706 | public: 707 | void NewFrame(); // new frame, so maybe neded to do somethings, like reset events 708 | void EndFrame(); // end frame, so maybe neded to do somethings fater all 709 | void ResetForNewDialog(); // reset what is needed to reset for the openging of a new dialog 710 | 711 | void configureDialog( // open simple dialog 712 | const std::string& vKey, // key dialog 713 | const std::string& vTitle, // title 714 | const char* vFilters, // filters, if null, will display only directories 715 | const FileDialogConfig& vConfig); // FileDialogConfig 716 | const FileDialogConfig& getDialogConfig() const; 717 | FileDialogConfig& getDialogConfigRef(); 718 | }; 719 | 720 | class IGFD_API ThumbnailFeature { 721 | protected: 722 | ThumbnailFeature(); 723 | ~ThumbnailFeature(); 724 | 725 | void m_NewThumbnailFrame(FileDialogInternal& vFileDialogInternal); 726 | void m_EndThumbnailFrame(FileDialogInternal& vFileDialogInternal); 727 | void m_QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal); 728 | 729 | #ifdef USE_THUMBNAILS 730 | public: 731 | typedef std::function CreateThumbnailFun; // texture 2d creation function binding 732 | typedef std::function DestroyThumbnailFun; // texture 2d destroy function binding 733 | 734 | protected: 735 | enum class DisplayModeEnum { FILE_LIST = 0, THUMBNAILS_LIST, THUMBNAILS_GRID }; 736 | 737 | private: 738 | uint32_t m_CountFiles = 0U; 739 | bool m_IsWorking = false; 740 | std::shared_ptr m_ThumbnailGenerationThread = nullptr; 741 | std::list > m_ThumbnailFileDatasToGet; // base container 742 | std::mutex m_ThumbnailFileDatasToGetMutex; 743 | std::condition_variable m_ThumbnailFileDatasToGetCv; 744 | std::list > m_ThumbnailToCreate; // base container 745 | std::mutex m_ThumbnailToCreateMutex; 746 | std::list m_ThumbnailToDestroy; // base container 747 | std::mutex m_ThumbnailToDestroyMutex; 748 | 749 | CreateThumbnailFun m_CreateThumbnailFun = nullptr; 750 | DestroyThumbnailFun m_DestroyThumbnailFun = nullptr; 751 | 752 | protected: 753 | DisplayModeEnum m_DisplayMode = DisplayModeEnum::FILE_LIST; 754 | 755 | private: 756 | void m_VariadicProgressBar(float fraction, const ImVec2& size_arg, const char* fmt, ...); 757 | 758 | protected: 759 | // will be call in cpu zone (imgui computations, will call a texture file retrieval thread) 760 | void m_StartThumbnailFileDatasExtraction(); // start the thread who will get byte buffer from image files 761 | bool m_StopThumbnailFileDatasExtraction(); // stop the thread who will get byte buffer from image files 762 | void m_ThreadThumbnailFileDatasExtractionFunc(); // the thread who will get byte buffer from image files 763 | void m_DrawThumbnailGenerationProgress(); // a little progressbar who will display the texture gen status 764 | void m_AddThumbnailToLoad(const std::shared_ptr& vFileInfos); // add texture to load in the thread 765 | void m_AddThumbnailToCreate(const std::shared_ptr& vFileInfos); 766 | void m_AddThumbnailToDestroy(const IGFD_Thumbnail_Info& vIGFD_Thumbnail_Info); 767 | void m_DrawDisplayModeToolBar(); // draw display mode toolbar (file list, thumbnails list, small thumbnails grid, big thumbnails grid) 768 | void m_ClearThumbnails(FileDialogInternal& vFileDialogInternal); 769 | 770 | public: 771 | void SetCreateThumbnailCallback(const CreateThumbnailFun& vCreateThumbnailFun); 772 | void SetDestroyThumbnailCallback(const DestroyThumbnailFun& vCreateThumbnailFun); 773 | 774 | // must be call in gpu zone (rendering, possibly one rendering thread) 775 | void ManageGPUThumbnails(); // in gpu rendering zone, whill create or destroy texture 776 | #endif 777 | }; 778 | 779 | class IGFD_API PlacesFeature { 780 | protected: 781 | PlacesFeature(); 782 | 783 | #ifdef USE_PLACES_FEATURE 784 | private: 785 | struct PlaceStruct { 786 | std::string name; // name of the place 787 | // todo: the path could be relative, better if the app is moved but place path can be outside of the app 788 | std::string path; // absolute path of the place 789 | bool canBeSaved = true; // defined by code, can be used for prevent serialization / deserialization 790 | FileStyle style; 791 | float thickness = 0.0f; // when more than 0.0f, is a separator 792 | }; 793 | 794 | struct GroupStruct { 795 | bool canBeSaved = false; // defined by code, can be used for prevent serialization / deserialization 796 | size_t displayOrder = 0U; // the display order will be usedf first, then alphanumeric 797 | bool defaultOpened = false; // the group is opened by default 798 | bool canBeEdited = false; // will show +/- button for add/remove place in the group 799 | char editBuffer[MAX_FILE_DIALOG_NAME_BUFFER] = ""; // temp buffer for name edition 800 | int32_t selectedPlaceForEdition = -1; 801 | ImGuiTreeNodeFlags collapsingHeaderFlag = ImGuiTreeNodeFlags_None; 802 | ImGuiListClipper clipper; // the list clipper of the grou 803 | std::string name; // the group name, will be displayed 804 | std::vector places; // the places (name + path) 805 | bool AddPlace( // add a place by code 806 | const std::string& vPlaceName, // place name 807 | const std::string& vPlacePath, // place path 808 | const bool vCanBeSaved, // prevent serialization 809 | const FileStyle& vStyle = {}); // style 810 | void AddPlaceSeparator(const float& vThickness = 1.0f); 811 | bool RemovePlace( // remove a place by code, return true if succeed 812 | const std::string& vPlaceName); // place name to remove 813 | }; 814 | 815 | private: 816 | std::unordered_map > m_Groups; 817 | std::map > m_OrderedGroups; 818 | 819 | protected: 820 | float m_PlacesPaneWidth = 200.0f; 821 | bool m_PlacesPaneShown = false; 822 | 823 | protected: 824 | void m_InitPlaces(FileDialogInternal& vFileDialogInternal); 825 | void m_DrawPlacesButton(); // draw place button 826 | bool m_DrawPlacesPane(FileDialogInternal& vFileDialogInternal, const ImVec2& vSize); // draw place Pane 827 | 828 | public: 829 | std::string SerializePlaces( // serialize place : return place buffer to save in a file 830 | const bool vForceSerialisationForAll = true); // for avoid serialization of places with flag 'canBeSaved to false' 831 | void DeserializePlaces( // deserialize place : load place buffer to load in the dialog (saved from 832 | const std::string& vPlaces); // previous use with SerializePlaces()) place buffer to load 833 | bool AddPlacesGroup( // add a group 834 | const std::string& vGroupName, // the group name 835 | const size_t& vDisplayOrder, // the display roder of the group 836 | const bool vCanBeEdited = false, // let the user add/remove place in the group 837 | const bool vOpenedByDefault = true); // hte group is opened by default 838 | bool RemovePlacesGroup(const std::string& vGroupName); // remove the group 839 | GroupStruct* GetPlacesGroupPtr(const std::string& vGroupName); // get the group, if not existed, will be created 840 | #endif // USE_PLACES_FEATURE 841 | }; 842 | 843 | // file localization by input chat // widget flashing 844 | class IGFD_API KeyExplorerFeature { 845 | protected: 846 | KeyExplorerFeature(); 847 | 848 | #ifdef USE_EXPLORATION_BY_KEYS 849 | private: 850 | bool m_LocateFileByInputChar_lastFound = false; 851 | ImWchar m_LocateFileByInputChar_lastChar = 0; 852 | float m_FlashAlpha = 0.0f; // flash when select by char 853 | float m_FlashAlphaAttenInSecs = 1.0f; // fps display dependant 854 | int m_LocateFileByInputChar_InputQueueCharactersSize = 0; 855 | size_t m_FlashedItem = 0; // flash when select by char 856 | size_t m_LocateFileByInputChar_lastFileIdx = 0; 857 | 858 | protected: 859 | void m_LocateByInputKey(FileDialogInternal& vFileDialogInternal); // select a file line in listview according to char key 860 | bool m_LocateItem_Loop(FileDialogInternal& vFileDialogInternal, 861 | ImWchar vC); // restrat for start of list view if not found a corresponding file 862 | void m_ExploreWithkeys(FileDialogInternal& vFileDialogInternal, 863 | ImGuiID vListViewID); // select file/directory line in listview accroding to up/down enter/backspace keys 864 | void m_StartFlashItem(size_t vIdx); // define than an item must be flashed 865 | bool m_BeginFlashItem(size_t vIdx); // start the flashing of a line in lsit view 866 | static void m_EndFlashItem(); // end the fleshing accrdoin to var m_FlashAlphaAttenInSecs 867 | static bool m_FlashableSelectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, bool vFlashing = false, 868 | const ImVec2& size = ImVec2(0, 0)); // custom flashing selectable widgets, for flash the selected line in a short time 869 | 870 | public: 871 | void SetFlashingAttenuationInSeconds( // set the flashing time of the line in file list when use exploration keys 872 | float vAttenValue); // set the attenuation (from flashed to not flashed) in seconds 873 | #endif // USE_EXPLORATION_BY_KEYS 874 | }; 875 | 876 | class IGFD_API FileDialog : public PlacesFeature, public KeyExplorerFeature, public ThumbnailFeature { 877 | protected: 878 | FileDialogInternal m_FileDialogInternal; 879 | ImGuiListClipper m_FileListClipper; 880 | ImGuiListClipper m_PathListClipper; 881 | float prOkCancelButtonWidth = 0.0f; 882 | ImGuiWindowFlags m_CurrentDisplayedFlags; 883 | 884 | public: 885 | // Singleton for easier accces form anywhere but only one dialog at a time 886 | // vCopy or vForce can be used for share a memory pointer in a new memory space like a dll module 887 | static FileDialog* Instance(FileDialog* vCopy = nullptr, bool vForce = false) { 888 | static FileDialog _instance; 889 | static FileDialog* _instance_copy = nullptr; 890 | if (vCopy || vForce) { 891 | _instance_copy = vCopy; 892 | } 893 | if (_instance_copy) { 894 | return _instance_copy; 895 | } 896 | return &_instance; 897 | } 898 | 899 | public: 900 | FileDialog(); // ImGuiFileDialog Constructor. can be used for have many dialog at same time (not possible with singleton) 901 | virtual ~FileDialog(); // ImGuiFileDialog Destructor 902 | 903 | // standard dialog 904 | virtual void OpenDialog( // open simple dialog 905 | const std::string& vKey, // key dialog 906 | const std::string& vTitle, // title 907 | const char* vFilters, // filters, if null, will display only directories 908 | const FileDialogConfig& vConfig = {}); // FileDialogConfig 909 | 910 | // Display / Close dialog form 911 | bool Display( // Display the dialog. return true if a result was obtained (Ok or not) 912 | const std::string& vKey, // key dialog to display (if not the same key as defined by OpenDialog => no opening) 913 | ImGuiWindowFlags vFlags = ImGuiWindowFlags_NoCollapse, // ImGuiWindowFlags 914 | ImVec2 vMinSize = ImVec2(0, 0), // mininmal size contraint for the ImGuiWindow 915 | ImVec2 vMaxSize = ImVec2(FLT_MAX, FLT_MAX)); // maximal size contraint for the ImGuiWindow 916 | 917 | void Close(); // close dialog 918 | 919 | // queries 920 | bool WasOpenedThisFrame(const std::string& vKey) const; // say if the dialog key was already opened this frame 921 | bool WasOpenedThisFrame() const; // say if the dialog was already opened this frame 922 | bool IsOpened(const std::string& vKey) const; // say if the key is opened 923 | bool IsOpened() const; // say if the dialog is opened somewhere 924 | std::string GetOpenedKey() const; // return the dialog key who is opened, return nothing if not opened 925 | 926 | // get result 927 | bool IsOk() const; // true => Dialog Closed with Ok result / false : Dialog closed with cancel result 928 | std::map GetSelection(IGFD_ResultMode vFlag = IGFD_ResultMode_KeepInputFile); // Open File behavior : will return selection via a 929 | // map 930 | std::string GetFilePathName(IGFD_ResultMode vFlag = IGFD_ResultMode_AddIfNoFileExt); // Save File behavior : will return the current file path name 931 | std::string GetCurrentFileName(IGFD_ResultMode vFlag = IGFD_ResultMode_AddIfNoFileExt); // Save File behavior : will return the content file name 932 | std::string GetCurrentPath(); // will return current file path 933 | std::string GetCurrentFilter(); // will return current filter 934 | UserDatas GetUserDatas() const; // will return user datas send with Open Dialog 935 | 936 | // file style by extentions 937 | void SetFileStyle( // SetExtention datas for have custom display of particular file type 938 | const IGFD_FileStyleFlags& vFlags, // file style 939 | const char* vCriteria, // extention filter to tune 940 | const FileStyle& vInfos); // Filter Extention Struct who contain Color and Icon/Text for the display of the 941 | // file with extention filter 942 | void SetFileStyle( // SetExtention datas for have custom display of particular file type 943 | const IGFD_FileStyleFlags& vFlags, // file style 944 | const char* vCriteria, // extention filter to tune 945 | const ImVec4& vColor, // wanted color for the display of the file with extention filter 946 | const std::string& vIcon = "", // wanted text or icon of the file with extention filter 947 | ImFont* vFont = nullptr); // wanted font 948 | void SetFileStyle(FileStyle::FileStyleFunctor vFunctor); // set file style via lambda function 949 | bool GetFileStyle( // GetExtention datas. return true is extention exist 950 | const IGFD_FileStyleFlags& vFlags, // file style 951 | const std::string& vCriteria, // extention filter (same as used in SetExtentionInfos) 952 | ImVec4* vOutColor, // color to retrieve 953 | std::string* vOutIcon = nullptr, // icon or text to retrieve 954 | ImFont** vOutFont = nullptr); // font to retreive 955 | void ClearFilesStyle(); // clear extentions setttings 956 | 957 | void SetLocales( // set locales to use before and after the dialog display 958 | const int& vLocaleCategory, // set local category 959 | const std::string& vLocaleBegin, // locale to use at begining of the dialog display 960 | const std::string& vLocaleEnd); // locale to use at the end of the dialog display 961 | 962 | protected: 963 | void m_NewFrame(); // new frame just at begining of display 964 | void m_EndFrame(); // end frame just at end of display 965 | void m_QuitFrame(); // quit frame when qui quit the dialog 966 | 967 | // others 968 | bool m_Confirm_Or_OpenOverWriteFileDialog_IfNeeded(bool vLastAction, ImGuiWindowFlags vFlags); // treatment of the result, start the confirm to overwrite dialog 969 | // if needed (if defined with flag) 970 | 971 | // dialog parts 972 | virtual void m_DrawHeader(); // draw header part of the dialog (place btn, dir creation, path composer, search 973 | // bar) 974 | virtual void m_DrawContent(); // draw content part of the dialog (place pane, file list, side pane) 975 | virtual bool m_DrawFooter(); // draw footer part of the dialog (file field, fitler combobox, ok/cancel btn's) 976 | 977 | // widgets components 978 | virtual void m_DisplayPathPopup(ImVec2 vSize); // draw path popup when click on a \ or / 979 | virtual bool m_DrawValidationButtons(); // draw validations btns, ok, cancel buttons 980 | virtual bool m_DrawOkButton(); // draw ok button 981 | virtual bool m_DrawCancelButton(); // draw cancel button 982 | virtual void m_DrawSidePane(float vHeight); // draw side pane 983 | virtual bool m_Selectable(int vRowIdx, const char* vLabel, bool vSelected, ImGuiSelectableFlags vFlags, const ImVec2& vSizeArg); 984 | virtual void m_SelectableItem(int vRowIdx, std::shared_ptr vInfos, bool vSelected, const char* vFmt, ...); // draw a custom selectable behavior item 985 | virtual void m_drawColumnText(int vColIdx, const char* vLabel, bool vSelected, bool vHovered); 986 | virtual void m_DrawFileListView(ImVec2 vSize); // draw file list view (default mode) 987 | 988 | #ifdef USE_THUMBNAILS 989 | virtual void m_DrawThumbnailsListView(ImVec2 vSize); // draw file list view with small thumbnails on the same line 990 | virtual void m_DrawThumbnailsGridView(ImVec2 vSize); // draw a grid of small thumbnails 991 | #endif 992 | 993 | // to be called only by these function and theirs overrides 994 | // - m_DrawFileListView 995 | // - m_DrawThumbnailsListView 996 | // - m_DrawThumbnailsGridView 997 | void m_BeginFileColorIconStyle(std::shared_ptr vFileInfos, bool& vOutShowColor, std::string& vOutStr, 998 | ImFont** vOutFont); // begin style apply of filter with color an icon if any 999 | void m_EndFileColorIconStyle(const bool vShowColor, ImFont* vFont); // end style apply of filter 1000 | 1001 | void m_DisplayFileInfosTooltip(const int32_t& vRowIdx, const int32_t& vColumnIdx, std::shared_ptr vFileInfos); 1002 | }; 1003 | 1004 | } // namespace IGFD 1005 | 1006 | #endif // __cplusplus 1007 | 1008 | ///////////////////////////////////////////////// 1009 | ////// C LANG API /////////////////////////////// 1010 | ///////////////////////////////////////////////// 1011 | 1012 | #ifdef __cplusplus 1013 | #define IGFD_C_API extern "C" IGFD_API 1014 | typedef IGFD::UserDatas IGFDUserDatas; 1015 | typedef IGFD::PaneFun IGFDPaneFun; 1016 | typedef IGFD::FileDialog ImGuiFileDialog; 1017 | #else // __cplusplus 1018 | #define IGFD_C_API 1019 | typedef struct ImGuiFileDialog ImGuiFileDialog; 1020 | typedef struct IGFD_Selection_Pair IGFD_Selection_Pair; 1021 | typedef struct IGFD_Selection IGFD_Selection; 1022 | #endif // __cplusplus 1023 | 1024 | typedef void (*IGFD_PaneFun)(const char*, void*, bool*); // callback fucntion for display the pane 1025 | 1026 | struct IGFD_FileDialog_Config { 1027 | const char* path; // path 1028 | const char* fileName; // defaut file name 1029 | const char* filePathName; // if not empty, the filename and the path will be obtained from filePathName 1030 | int32_t countSelectionMax; // count selection max 1031 | void* userDatas; // user datas (can be retrieved in pane) 1032 | IGFD_PaneFun sidePane; // side pane callback 1033 | float sidePaneWidth; // side pane width}; 1034 | ImGuiFileDialogFlags flags; // ImGuiFileDialogFlags 1035 | }; 1036 | IGFD_C_API struct IGFD_FileDialog_Config IGFD_FileDialog_Config_Get(); // return an initialized IGFD_FileDialog_Config 1037 | 1038 | struct IGFD_Selection_Pair { 1039 | char* fileName; 1040 | char* filePathName; 1041 | }; 1042 | 1043 | IGFD_C_API IGFD_Selection_Pair IGFD_Selection_Pair_Get(); // return an initialized IGFD_Selection_Pair 1044 | IGFD_C_API void IGFD_Selection_Pair_DestroyContent(IGFD_Selection_Pair* vSelection_Pair); // destroy the content of a IGFD_Selection_Pair 1045 | 1046 | struct IGFD_Selection { 1047 | IGFD_Selection_Pair* table; // 0 1048 | size_t count; // 0U 1049 | }; 1050 | 1051 | IGFD_C_API IGFD_Selection IGFD_Selection_Get(); // return an initialized IGFD_Selection 1052 | IGFD_C_API void IGFD_Selection_DestroyContent(IGFD_Selection* vSelection); // destroy the content of a IGFD_Selection 1053 | 1054 | // constructor / destructor 1055 | IGFD_C_API ImGuiFileDialog* IGFD_Create(void); // create the filedialog context 1056 | IGFD_C_API void IGFD_Destroy(ImGuiFileDialog* vContextPtr); // destroy the filedialog context 1057 | 1058 | #ifdef USE_THUMBNAILS 1059 | typedef void (*IGFD_CreateThumbnailFun)(IGFD_Thumbnail_Info*); // callback function for create thumbnail texture 1060 | typedef void (*IGFD_DestroyThumbnailFun)(IGFD_Thumbnail_Info*); // callback fucntion for destroy thumbnail texture 1061 | #endif // USE_THUMBNAILS 1062 | 1063 | IGFD_C_API void IGFD_OpenDialog( // open a standard dialog 1064 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1065 | const char* vKey, // key dialog 1066 | const char* vTitle, // title 1067 | const char* vFilters, // filters/filter collections. set it to null for directory mode 1068 | const struct IGFD_FileDialog_Config vConfig); // config 1069 | 1070 | IGFD_C_API bool IGFD_DisplayDialog( // Display the dialog 1071 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1072 | const char* vKey, // key dialog to display (if not the same key as defined by OpenDialog => no opening) 1073 | ImGuiWindowFlags vFlags, // ImGuiWindowFlags 1074 | ImVec2 vMinSize, // mininmal size contraint for the ImGuiWindow 1075 | ImVec2 vMaxSize); // maximal size contraint for the ImGuiWindow 1076 | 1077 | IGFD_C_API void IGFD_CloseDialog( // Close the dialog 1078 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1079 | 1080 | IGFD_C_API bool IGFD_IsOk( // true => Dialog Closed with Ok result / false : Dialog closed with cancel result 1081 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1082 | 1083 | IGFD_C_API bool IGFD_WasKeyOpenedThisFrame( // say if the dialog key was already opened this frame 1084 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1085 | const char* vKey); 1086 | 1087 | IGFD_C_API bool IGFD_WasOpenedThisFrame( // say if the dialog was already opened this frame 1088 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1089 | 1090 | IGFD_C_API bool IGFD_IsKeyOpened( // say if the dialog key is opened 1091 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1092 | const char* vCurrentOpenedKey); // the dialog key 1093 | 1094 | IGFD_C_API bool IGFD_IsOpened( // say if the dialog is opened somewhere 1095 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1096 | 1097 | IGFD_C_API IGFD_Selection IGFD_GetSelection( // Open File behavior : will return selection via a map 1098 | ImGuiFileDialog* vContextPtr, // user datas (can be retrieved in pane) 1099 | IGFD_ResultMode vMode); // Result Mode 1100 | 1101 | IGFD_C_API char* IGFD_GetFilePathName( // Save File behavior : will always return the content of the field with current 1102 | // filter extention and current path, WARNINGS you are responsible to free it 1103 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1104 | IGFD_ResultMode vMode); // Result Mode 1105 | 1106 | IGFD_C_API char* IGFD_GetCurrentFileName( // Save File behavior : will always return the content of the field with 1107 | // current filter extention, WARNINGS you are responsible to free it 1108 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1109 | IGFD_ResultMode vMode); // Result Mode 1110 | 1111 | IGFD_C_API char* IGFD_GetCurrentPath( // will return current path, WARNINGS you are responsible to free it 1112 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1113 | 1114 | IGFD_C_API char* IGFD_GetCurrentFilter( // will return selected filter, WARNINGS you are responsible to free it 1115 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1116 | 1117 | IGFD_C_API void* IGFD_GetUserDatas( // will return user datas send with Open Dialog 1118 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1119 | 1120 | IGFD_C_API void IGFD_SetFileStyle( // SetExtention datas for have custom display of particular file type 1121 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1122 | IGFD_FileStyleFlags vFileStyleFlags, // file style type 1123 | const char* vFilter, // extention filter to tune 1124 | ImVec4 vColor, // wanted color for the display of the file with extention filter 1125 | const char* vIconText, // wanted text or icon of the file with extention filter (can be sued with font icon) 1126 | ImFont* vFont); // wanted font pointer 1127 | 1128 | IGFD_C_API void IGFD_SetFileStyle2( // SetExtention datas for have custom display of particular file type 1129 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1130 | IGFD_FileStyleFlags vFileStyleFlags, // file style type 1131 | const char* vFilter, // extention filter to tune 1132 | float vR, float vG, float vB, 1133 | float vA, // wanted color channels RGBA for the display of the file with extention filter 1134 | const char* vIconText, // wanted text or icon of the file with extention filter (can be sued with font icon) 1135 | ImFont* vFont); // wanted font pointer 1136 | 1137 | IGFD_C_API bool IGFD_GetFileStyle(ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1138 | IGFD_FileStyleFlags vFileStyleFlags, // file style type 1139 | const char* vFilter, // extention filter (same as used in SetExtentionInfos) 1140 | ImVec4* vOutColor, // color to retrieve 1141 | char** vOutIconText, // icon or text to retrieve, WARNINGS you are responsible to free it 1142 | ImFont** vOutFont); // font pointer to retrived 1143 | 1144 | IGFD_C_API void IGFD_ClearFilesStyle( // clear extentions setttings 1145 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1146 | 1147 | IGFD_C_API void SetLocales( // set locales to use before and after display 1148 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1149 | const int vCategory, // set local category 1150 | const char* vBeginLocale, // locale to use at begining of the dialog display 1151 | const char* vEndLocale); // locale to set at end of the dialog display 1152 | 1153 | #ifdef USE_EXPLORATION_BY_KEYS 1154 | IGFD_C_API void IGFD_SetFlashingAttenuationInSeconds( // set the flashing time of the line in file list when use 1155 | // exploration keys 1156 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1157 | float vAttenValue); // set the attenuation (from flashed to not flashed) in seconds 1158 | #endif 1159 | 1160 | #ifdef USE_PLACES_FEATURE 1161 | IGFD_C_API char* IGFD_SerializePlaces( // serialize place : return place buffer to save in a file, WARNINGS 1162 | // you are responsible to free it 1163 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1164 | bool vDontSerializeCodeBasedPlaces); // for avoid serialization of place added by code 1165 | 1166 | IGFD_C_API void IGFD_DeserializePlaces( // deserialize place : load bookmar buffer to load in the dialog (saved 1167 | // from previous use with SerializePlaces()) 1168 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1169 | const char* vPlaces); // place buffer to load 1170 | 1171 | IGFD_C_API bool IGFD_AddPlacesGroup( // add a places group by code 1172 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1173 | const char* vGroupName, // the group name 1174 | size_t vDisplayOrder, // the display roder of the group 1175 | bool vCanBeEdited); // let the user add/remove place in the group 1176 | 1177 | IGFD_C_API bool IGFD_RemovePlacesGroup( // remove a place group by code, return true if succeed 1178 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1179 | const char* vGroupName); // place name to remove 1180 | 1181 | IGFD_C_API bool IGFD_AddPlace( // add a place by code 1182 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1183 | const char* vGroupName, // the group name 1184 | const char* vPlaceName, // place name 1185 | const char* vPlacePath, // place path 1186 | bool vCanBeSaved, // place can be saved 1187 | const char* vIconText); // wanted text or icon of the file with extention filter (can be used with font icon) 1188 | 1189 | IGFD_C_API bool IGFD_RemovePlace( // remove a place by code, return true if succeed 1190 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1191 | const char* vGroupName, // the group name 1192 | const char* vPlaceName); // place name to remove 1193 | 1194 | #endif 1195 | 1196 | #ifdef USE_THUMBNAILS 1197 | IGFD_C_API void SetCreateThumbnailCallback( // define the callback for create the thumbnails texture 1198 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1199 | IGFD_CreateThumbnailFun vCreateThumbnailFun); // the callback for create the thumbnails texture 1200 | 1201 | IGFD_C_API void SetDestroyThumbnailCallback( // define the callback for destroy the thumbnails texture 1202 | ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context 1203 | IGFD_DestroyThumbnailFun vDestroyThumbnailFun); // the callback for destroy the thumbnails texture 1204 | 1205 | IGFD_C_API void ManageGPUThumbnails( // must be call in gpu zone, possibly a thread, will call the callback for create 1206 | // / destroy the textures 1207 | ImGuiFileDialog* vContextPtr); // ImGuiFileDialog context 1208 | #endif // USE_THUMBNAILS 1209 | -------------------------------------------------------------------------------- /ImGuiFileDialogConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // uncomment and modify defines under for customize ImGuiFileDialog 4 | 5 | ///////////////////////////////// 6 | //// STL FILE SYSTEM //////////// 7 | ///////////////////////////////// 8 | 9 | // uncomment if you need to use your FileSystem Interface 10 | // if commented, you have two defualt interface, std::filesystem or dirent 11 | // #define USE_CUSTOM_FILESYSTEM 12 | // this options need c++17 13 | // #define USE_STD_FILESYSTEM 14 | 15 | ///////////////////////////////// 16 | //// MISC /////////////////////// 17 | ///////////////////////////////// 18 | 19 | // the spacing between button path's can be customized. 20 | // if disabled the spacing is defined by the imgui theme 21 | // define the space between path buttons 22 | // #define CUSTOM_PATH_SPACING 2 23 | 24 | // #define MAX_FILE_DIALOG_NAME_BUFFER 1024 25 | // #define MAX_PATH_BUFFER_SIZE 1024 26 | 27 | ///////////////////////////////// 28 | //// QUICK PATH ///////////////// 29 | ///////////////////////////////// 30 | 31 | // the slash's buttons in path cna be used for quick select parallles directories 32 | // #define USE_QUICK_PATH_SELECT 33 | 34 | ///////////////////////////////// 35 | //// THUMBNAILS ///////////////// 36 | ///////////////////////////////// 37 | 38 | // #define USE_THUMBNAILS 39 | // the thumbnail generation use the stb_image and stb_resize lib who need to define the implementation 40 | // btw if you already use them in your app, you can have compiler error due to "implemntation found in double" 41 | // so uncomment these line for prevent the creation of implementation of these libs again 42 | // #define DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION 43 | // #define DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION 44 | // #define IMGUI_RADIO_BUTTON RadioButton 45 | // #define DisplayMode_ThumbailsList_ImageHeight 32.0f 46 | // #define tableHeaderFileThumbnailsString "Thumbnails" 47 | // #define DisplayMode_FilesList_ButtonString "FL" 48 | // #define DisplayMode_FilesList_ButtonHelp "File List" 49 | // #define DisplayMode_ThumbailsList_ButtonString "TL" 50 | // #define DisplayMode_ThumbailsList_ButtonHelp "Thumbnails List" 51 | // todo 52 | // #define DisplayMode_ThumbailsGrid_ButtonString "TG" 53 | // #define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid" 54 | 55 | ///////////////////////////////// 56 | //// EXPLORATION BY KEYS //////// 57 | ///////////////////////////////// 58 | 59 | // #define USE_EXPLORATION_BY_KEYS 60 | // this mapping by default is for GLFW but you can use another 61 | // #include 62 | // Up key for explore to the top 63 | // #define IGFD_KEY_UP ImGuiKey_UpArrow 64 | // Down key for explore to the bottom 65 | // #define IGFD_KEY_DOWN ImGuiKey_DownArrow 66 | // Enter key for open directory 67 | // #define IGFD_KEY_ENTER ImGuiKey_Enter 68 | // BackSpace for comming back to the last directory 69 | // #define IGFD_KEY_BACKSPACE ImGuiKey_Backspace 70 | 71 | ///////////////////////////////// 72 | //// SHORTCUTS => ctrl + KEY //// 73 | ///////////////////////////////// 74 | 75 | // #define SelectAllFilesKey ImGuiKey_A 76 | 77 | ///////////////////////////////// 78 | //// DIALOG EXIT //////////////// 79 | ///////////////////////////////// 80 | 81 | // by ex you can quit the dialog by pressing the key excape 82 | // #define USE_DIALOG_EXIT_WITH_KEY 83 | // #define IGFD_EXIT_KEY ImGuiKey_Escape 84 | 85 | ///////////////////////////////// 86 | //// WIDGETS //////////////////// 87 | ///////////////////////////////// 88 | 89 | // widget 90 | // begin combo widget 91 | // #define IMGUI_BEGIN_COMBO ImGui::BeginCombo 92 | // when auto resized, FILTER_COMBO_MIN_WIDTH will be considered has minimum width 93 | // FILTER_COMBO_AUTO_SIZE is enabled by default now to 1 94 | // uncomment if you want disable 95 | // #define FILTER_COMBO_AUTO_SIZE 0 96 | // filter combobox width 97 | // #define FILTER_COMBO_MIN_WIDTH 120.0f 98 | // button widget use for compose path 99 | // #define IMGUI_PATH_BUTTON ImGui::Button 100 | // standard button 101 | // #define IMGUI_BUTTON ImGui::Button 102 | 103 | ///////////////////////////////// 104 | //// STRING'S /////////////////// 105 | ///////////////////////////////// 106 | 107 | // locales string 108 | // #define createDirButtonString "+" 109 | // #define resetButtonString "R" 110 | // #define devicesButtonString "Devices" 111 | // #define editPathButtonString "E" 112 | // #define searchString "Search" 113 | // #define dirEntryString "[DIR] " 114 | // #define linkEntryString "[LINK] " 115 | // #define fileEntryString "[FILE] " 116 | // #define fileNameString "File Name : " 117 | // #define dirNameString "Directory Path :" 118 | // #define buttonResetSearchString "Reset search" 119 | // #define buttonDriveString "Devices" 120 | // #define buttonEditPathString "Edit path\nYou can also right click on path buttons" 121 | // #define buttonResetPathString "Reset to current directory" 122 | // #define buttonCreateDirString "Create Directory" 123 | // #define OverWriteDialogTitleString "The file Already Exist !" 124 | // #define OverWriteDialogMessageString "Would you like to OverWrite it ?" 125 | // #define OverWriteDialogConfirmButtonString "Confirm" 126 | // #define OverWriteDialogCancelButtonString "Cancel" 127 | 128 | // Validation buttons 129 | // #define okButtonString " OK" 130 | // #define okButtonWidth 0.0f 131 | // #define cancelButtonString " Cancel" 132 | // #define cancelButtonWidth 0.0f 133 | // alignement [0:1], 0.0 is left, 0.5 middle, 1.0 right, and other ratios 134 | // #define okCancelButtonAlignement 0.0f 135 | // #define invertOkAndCancelButtons 0 136 | 137 | // DateTimeFormat 138 | // see strftime functionin for customize 139 | // "%Y/%m/%d %H:%M" give 2021:01:22 11:47 140 | // "%Y/%m/%d %i:%M%p" give 2021:01:22 11:45PM 141 | // #define DateTimeFormat "%Y/%m/%d %i:%M%p" 142 | 143 | ///////////////////////////////// 144 | //// SORTING ICONS ////////////// 145 | ///////////////////////////////// 146 | 147 | // theses icons will appear in table headers 148 | // #define USE_CUSTOM_SORTING_ICON 149 | // #define tableHeaderAscendingIcon "A|" 150 | // #define tableHeaderDescendingIcon "D|" 151 | // #define tableHeaderFileNameString " File name" 152 | // #define tableHeaderFileTypeString " Type" 153 | // #define tableHeaderFileSizeString " Size" 154 | // #define tableHeaderFileDateTimeString " Date" 155 | // #define fileSizeBytes "o" 156 | // #define fileSizeKiloBytes "Ko" 157 | // #define fileSizeMegaBytes "Mo" 158 | // #define fileSizeGigaBytes "Go" 159 | 160 | // default table sort field (must be FIELD_FILENAME, FIELD_TYPE, FIELD_SIZE, FIELD_DATE or FIELD_THUMBNAILS) 161 | // #define defaultSortField FIELD_FILENAME 162 | 163 | // default table sort order for each field (true => Descending, false => Ascending) 164 | // #define defaultSortOrderFilename true 165 | // #define defaultSortOrderType true 166 | // #define defaultSortOrderSize true 167 | // #define defaultSortOrderDate true 168 | // #define defaultSortOrderThumbnails true 169 | 170 | ///////////////////////////////// 171 | //// PLACES FEATURES //////////// 172 | ///////////////////////////////// 173 | 174 | // #define USE_PLACES_FEATURE 175 | // #define PLACES_PANE_DEFAULT_SHOWN false 176 | // #define placesPaneWith 150.0f 177 | // #define IMGUI_TOGGLE_BUTTON ToggleButton 178 | // #define placesButtonString "Place" 179 | // #define placesButtonHelpString "Places" 180 | // #define addPlaceButtonString "+" 181 | // #define removePlaceButtonString "-" 182 | // #define validatePlaceButtonString "ok" 183 | // #define editPlaceButtonString "E" 184 | 185 | ////////////////////////////////////// 186 | //// PLACES FEATURES : BOOKMARKS ///// 187 | ////////////////////////////////////// 188 | 189 | // a group for bookmarks will be added by default, but you can also create it yourself and many more 190 | // #define USE_PLACES_BOOKMARKS 191 | // #define PLACES_BOOKMARK_DEFAULT_OPEPEND true 192 | // #define placesBookmarksGroupName "Bookmarks" 193 | // #define placesBookmarksDisplayOrder 0 // to the first 194 | 195 | ////////////////////////////////////// 196 | //// PLACES FEATURES : DEVICES /////// 197 | ////////////////////////////////////// 198 | 199 | // a group for system devices (returned by IFileSystem), but you can also add yours 200 | // by ex if you would like to display a specific icon for some devices 201 | // #define USE_PLACES_DEVICES 202 | // #define PLACES_DEVICES_DEFAULT_OPEPEND true 203 | // #define placesDevicesGroupName "Devices" 204 | // #define placesDevicesDisplayOrder 10 // to the end 205 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2024 Stephane Cuillerdier (aka Aiekick) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImGuiFileDialog 2 | 3 | ## Build Matrix 4 | 5 | | | Win | Linux | MacOs | 6 | | :---: | :---: | :---: | :---: | 7 | | Msvc | [![Win Msvc](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Win_Msvc.yml/badge.svg)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Win_Msvc.yml) | | | 8 | | Gcc | | [![Linux Gcc](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Linux_Gcc.yml/badge.svg)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Linux_Gcc.yml) | [![Osx Gcc](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Osx_Gcc.yml/badge.svg)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Osx_Gcc.yml) | 9 | | Clang | | [![Linux Clang](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Linux_Clang.yml/badge.svg)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Linux_Clang.yml) | [![Osx Clang](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Osx_Clang.yml/badge.svg)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Osx_Clang.yml) | 10 | | Leak Sanitizer | | [![Leak Sanitizer](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Leak.yml/badge.svg)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Leak.yml) | | 11 | 12 | ## Purpose 13 | 14 | ImGuiFileDialog is a file selection dialog built for (and using only) [Dear ImGui](https://github.com/ocornut/imgui). 15 | 16 | My primary goal was to have a custom pane with widgets according to file extension. This was not possible using other 17 | solutions. 18 | 19 | ## Possible Dialog Customization 20 | 21 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/demo_dialog.png) 22 | 23 | ## ImGui Supported Version 24 | 25 | > [!NOTE] 26 | > ImGuiFileDialog follow the master and docking branch of ImGui. 27 | > Currently : [![Wrapped Dear ImGui Version](https://img.shields.io/badge/Dear%20ImGui%20Version-1.90.5-blue.svg)](https://github.com/ocornut/imgui) 28 | 29 | ### Documentation : 30 | 31 | > [!NOTE] 32 | > for a complete explanation and howto about ImGuiFileDialog Api, 33 | > you can check the [**Documentation**](https://github.com/aiekick/ImGuiFileDialog/blob/master/Documentation.md) 34 | 35 | ## Structure 36 | 37 | * The library is in [Master branch](https://github.com/aiekick/ImGuiFileDialog/tree/master) 38 | * A demo app can be found in the [DemoApp branch](https://github.com/aiekick/ImGuiFileDialog/tree/DemoApp) 39 | 40 | This library is designed to be dropped into your source code rather than compiled separately. 41 | 42 | From your project directory: 43 | 44 | ``` 45 | mkdir lib 46 | cd lib 47 | git clone https://github.com/aiekick/ImGuiFileDialog.git 48 | git checkout master 49 | ``` 50 | 51 | These commands create a `lib` directory where you can store any third-party dependencies used in your project, downloads 52 | the ImGuiFileDialog git repository and checks out the Lib_Only branch where the actual library code is located. 53 | 54 | Add `lib/ImGuiFileDialog/ImGuiFileDialog.cpp` to your build system and include 55 | `lib/ImGuiFileDialog/ImGuiFileDialog.h` in your source code. ImGuiFileLib will compile with and be included directly in 56 | your executable file. 57 | 58 | If, for example, your project uses cmake, look for a line like `add_executable(my_project_name main.cpp)` 59 | and change it to `add_executable(my_project_name lib/ImGuiFileDialog/ImGuiFileDialog.cpp main.cpp)`. This tells the 60 | compiler where to find the source code declared in `ImGuiFileDialog.h` which you included in your own source code. 61 | 62 | ## Requirements: 63 | 64 | You must also, of course, have added [Dear ImGui](https://github.com/ocornut/imgui) to your project for this to work at 65 | all. 66 | 67 | ImguiFileDialog is agnostic about the filesystem api you can use. 68 | It provides a IFileSystem you can override for your needs. 69 | 70 | By default you can use dirent or std::filesystem. you have also a demo of uisng boos filesystem api in the DemoApp branch 71 | 72 | Android Requirements : Api 21 mini 73 | 74 | ## Features 75 | 76 | - C Api (succesfully tested with CimGui) 77 | - Separate system for call and display 78 | - Can have many function calls with different parameters for one display function, for example 79 | - Can create a custom pane with any widgets via function binding 80 | - This pane can block the validation of the dialog 81 | - Can also display different things according to current filter and UserDatas 82 | - Advanced file style for file/dir/link coloring / icons / font 83 | - predefined form or user custom form by lambda function (the lambda mode is not available for the C API) 84 | - Multi-selection (ctrl/shift + click) : 85 | - 0 => Infinite 86 | - 1 => One file (default) 87 | - n => n files 88 | - Compatible with MacOs, Linux, Windows, Emscripten, Android 89 | - Supports modal or standard dialog types 90 | - Select files or directories 91 | - Filter groups and custom filter names 92 | - can ignore filter Case for file searching 93 | - Keyboard navigation (arrows, backspace, enter) 94 | - Exploring by entering characters (case insensitive) 95 | - Custom places (bookmarks, system devices, whatever you want) 96 | - Directory manual entry (right click on any path element) 97 | - Optional 'Confirm to Overwrite" dialog if file exists 98 | - Thumbnails Display (agnostic way for compatibility with any backend, sucessfully tested with OpenGl and Vulkan) 99 | - The dialog can be embedded in another user frame than the standard or modal dialog 100 | - Can tune validation buttons (placements, widths, inversion) 101 | - Can quick select a parrallel directory of a path, in the path composer (when you clikc on a / you have a popup) 102 | - regex support for filters, collection of filters and filestyle (the regex is recognized when between (( and )) in a filter) 103 | - multi layer extentions like : .a.b.c .json.cpp .vcxproj.filters etc.. 104 | - advanced behavior regarding asterisk based filter. like : .* .*.* .vcx.* .*.filters .vcs*.filt.* etc.. (internally regex is used) 105 | - result modes GetFilePathName, GetFileName and GetSelection (overwrite file ext, keep file, add ext if no user ext exist) 106 | - you can use your own FileSystem Api 107 | - by default Api Dirent and std::filesystem are defined 108 | - you can override GetDrieveList for specify by ex on android other fs, like local and SDCards 109 | 110 | ### WARNINGS : 111 | - the nav system keyboard behavior is not working as expected, so maybe full of bug for ImGuiFileDialog 112 | 113 | ### Simple Usage : 114 | 115 | ```cpp 116 | void drawGui() { 117 | // open Dialog Simple 118 | if (ImGui::Button("Open File Dialog")) { 119 | IGFD::FileDialogConfig config; 120 | config.path = "."; 121 | ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Choose File", ".cpp,.h,.hpp", config); 122 | } 123 | // display 124 | if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey")) { 125 | if (ImGuiFileDialog::Instance()->IsOk()) { // action if OK 126 | std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); 127 | std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); 128 | // action 129 | } 130 | 131 | // close 132 | ImGuiFileDialog::Instance()->Close(); 133 | } 134 | } 135 | ``` 136 | 137 | ![alt text](https://github.com/aiekick/ImGuiFileDialog/blob/DemoApp/doc/dlg_simple.gif) 138 | 139 | ### How to build the sample app 140 | 141 | The sample app is [here in master branch](https://github.com/aiekick/ImGuiFileDialog/tree/master) 142 | 143 | You need to use CMake. For the 3 Os (Win, Linux, MacOs), the CMake usage is exactly the same, 144 | 145 | Choose a build directory. (called here my_build_directory for instance) and 146 | Choose a Build Mode : "Release" / "MinSizeRel" / "RelWithDebInfo" / "Debug" (called here BuildMode for instance) 147 | Run CMake in console : (the first for generate cmake build files, the second for build the binary) 148 | 149 | cmake -B my_build_directory -DCMAKE_BUILD_TYPE=BuildMode 150 | cmake --build my_build_directory --config BuildMode 151 | 152 | Some CMake version need Build mode define via the directive CMAKE_BUILD_TYPE or via --Config when we launch the build. This is why i put the boths possibilities 153 | 154 | By the way you need before, to make sure, you have needed dependencies. 155 | 156 | ### On Windows : 157 | 158 | You need to have the opengl library installed 159 | 160 | ### On Linux : 161 | 162 | You need many lib : (X11, xrandr, xinerama, xcursor, mesa) 163 | 164 | If you are on debian you can run : 165 | 166 | sudo apt-get update 167 | sudo apt-get install libgl1-mesa-dev libx11-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev 168 | 169 | ### On MacOs : 170 | 171 | you need many lib : opengl and cocoa framework 172 | 173 | 174 | 175 | ## That's all folks :-) 176 | 177 | You can check by example in this repo with the file CustomImGuiFileDialogConfig.h : 178 | - this trick was used to have custom icon font instead of labels for buttons or messages titles 179 | - you can also use your custom imgui button, the button call stamp must be same by the way :) 180 | 181 | The Custom Icon Font (in CustomFont.cpp and CustomFont.h) was made with ImGuiFontStudio (https://github.com/aiekick/ImGuiFontStudio) i wrote for that :) 182 | ImGuiFontStudio is also using ImGuiFileDialog.$ 183 | 184 | ![Alt](https://repobeats.axiom.co/api/embed/22a6eef207d0bce7c03519d94f55100973b451ca.svg "Repobeats analytics image") 185 | -------------------------------------------------------------------------------- /dirent/ChangeLog: -------------------------------------------------------------------------------- 1 | 2018-05-08 Toni Rönkkö 2 | 3 | * Version 1.23.2: fixes bad scandir prototype. 4 | 5 | 2017-08-27 Toni Rönkkö 6 | 7 | * Version 1.23: support readdir_r and scandir functions. 8 | 9 | 2017-07-18 Toni Rönkkö 10 | 11 | * Created release branches v1.22 and v1.21 to Git. Published version 12 | 1.22 at softagalleria.net. 13 | 14 | 2016-09-11 Toni Rönkkö 15 | 16 | * Version 1.22: added support for CMake. Thanks to Paul Fultz II. 17 | 18 | 2014-09-25 Toni Rönkkö 19 | 20 | * Version 1.21: compiles correctly under Open Watcom. Thanks to 21 | Virgil Banowetz for a patch! 22 | 23 | 2014-04-07 Toni Rönkkö 24 | 25 | * Version 1.20.1: the zip file from the previous version did not open 26 | correctly with Microsoft's compressed folders. Thanks to Alexandre 27 | for info! 28 | 29 | 2014-03-17 Toni Ronkko 30 | 31 | * Version 1.20: dirent.h compiles correctly in 64-bit architecture. 32 | Thanks to Aaron Simmons! 33 | 34 | 2014-03-03 Toni Ronkko 35 | 36 | * Version 1.13.2: define DT_LNK for compatibility with Unix 37 | programs. Thanks to Joel Bruick for suggestion! 38 | 39 | 2013-01-27 Toni Ronkko 40 | 41 | * Version 1.13.1: patch from Edward Berner fixes set_errno() on 42 | Windows NT 4.0. 43 | 44 | * Revised wcstombs() and mbstowcs() wrappers to make sure that they do 45 | not write past their target string. 46 | 47 | * PATH_MAX from windows.h includes zero terminator so there is no 48 | need to add one extra byte to variables and structures. 49 | 50 | 2012-12-12 Toni Ronkko 51 | 52 | * Version 1.13: use the traditional 8+3 file naming scheme if a file 53 | name cannot be represented in the default ANSI code page. Now 54 | compiles again with MSVC 6.0. Thanks to Konstantin Khomoutov for 55 | testing. 56 | 57 | 2012-10-01 Toni Ronkko 58 | 59 | * Version 1.12.1: renamed wide-character DIR structure _wDIR to 60 | _WDIR (with capital W) in order to maintain compatibility with MingW. 61 | 62 | 2012-09-30 Toni Ronkko 63 | 64 | * Version 1.12: define PATH_MAX and NAME_MAX. Added wide-character 65 | variants _wDIR, _wdirent, _wopendir(), _wreaddir(), _wclosedir() and 66 | _wrewinddir(). Thanks to Edgar Buerkle and Jan Nijtmans for ideas 67 | and code. 68 | 69 | * Now avoiding windows.h. This allows dirent.h to be integrated 70 | more easily into programs using winsock. Thanks to Fernando 71 | Azaldegui. 72 | 73 | 2011-03-15 Toni Ronkko 74 | 75 | * Version 1.11: defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0. 76 | 77 | 2010-08-11 Toni Ronkko 78 | 79 | * Version 1.10: added d_type and d_namlen fields to dirent structure. 80 | The former is especially useful for determining whether directory 81 | entry represents a file or a directory. For more information, see 82 | http://www.delorie.com/gnu/docs/glibc/libc_270.html 83 | 84 | * Improved conformance to the standards. For example, errno is now 85 | set properly on failure and assert() is never used. Thanks to Peter 86 | Brockam for suggestions. 87 | 88 | * Fixed a bug in rewinddir(): when using relative directory names, 89 | change of working directory no longer causes rewinddir() to fail. 90 | 91 | 2009-12-15 John Cunningham 92 | 93 | * Version 1.9: added rewinddir member function 94 | 95 | 2008-01-18 Toni Ronkko 96 | 97 | * Version 1.8: Using FindFirstFileA and WIN32_FIND_DATAA to avoid 98 | converting string between multi-byte and unicode representations. 99 | This makes the code simpler and also allows the code to be compiled 100 | under MingW. Thanks to Azriel Fasten for the suggestion. 101 | 102 | 2007-03-04 Toni Ronkko 103 | 104 | * Bug fix: due to the strncpy_s() function this file only compiled in 105 | Visual Studio 2005. Using the new string functions only when the 106 | compiler version allows. 107 | 108 | 2006-11-02 Toni Ronkko 109 | 110 | * Major update: removed support for Watcom C, MS-DOS and Turbo C to 111 | simplify the file, updated the code to compile cleanly on Visual 112 | Studio 2005 with both unicode and multi-byte character strings, 113 | removed rewinddir() as it had a bug. 114 | 115 | 2006-08-20 Toni Ronkko 116 | 117 | * Removed all remarks about MSVC 1.0, which is antiqued now. 118 | Simplified comments by removing SGML tags. 119 | 120 | 2002-05-14 Toni Ronkko 121 | 122 | * Embedded the function definitions directly to the header so that no 123 | source modules need to be included in the Visual Studio project. 124 | Removed all the dependencies to other projects so that this header 125 | file can be used independently. 126 | 127 | 1998-05-28 Toni Ronkko 128 | 129 | * First version. 130 | -------------------------------------------------------------------------------- /dirent/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 1998-2019 Toni Ronkko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dirent/README.md: -------------------------------------------------------------------------------- 1 | # Dirent 2 | Dirent is a C/C++ programming interface that allows programmers to retrieve 3 | information about files and directories under Linux/UNIX. This project 4 | provides Linux compatible Dirent interface for Microsoft Windows. 5 | 6 | 7 | # Installation 8 | 9 | Download the latest Dirent installation package from 10 | [GitHub](https://github.com/tronkko/dirent/releases) and 11 | unpack the installation file with 7-zip, for example. The installation 12 | package contains dirent.h file as well as a few example programs and 13 | tests. 14 | 15 | 16 | ## Install Dirent for All Programs 17 | 18 | To make dirent.h available for all C/C++ programs, simply copy the 19 | ``include/dirent.h`` file to the system include directory. System include 20 | directory contains header files such as assert.h and windows.h. In Visual 21 | Studio 2008, for example, the system include may be found at 22 | ``C:\Program Files\Microsoft Visual Studio 9.0\VC\include``. 23 | 24 | Everything you need is included in the single dirent.h file, and you can 25 | start using Dirent immediately -- there is no need to add files to your 26 | Visual Studio project. 27 | 28 | 29 | ## Embed Dirent into Your Own Project 30 | 31 | If you wish to distribute dirent.h alongside with your own source code, then 32 | copy ``include/dirent.h`` file to a new sub-directory within your project and 33 | add that directory to include path on Windows while omitting the directory 34 | under Linux/UNIX. This allows your project to be compiled against native 35 | dirent.h on Linux/UNIX while substituting the functionality on Microsoft 36 | Windows. 37 | 38 | 39 | ## Examples 40 | 41 | The installation package contains four example programs: 42 | 43 | Program | Purpose 44 | -------- | ----------------------------------------------------------------- 45 | ls | List files in a directory, e.g. ls "c:\Program Files" 46 | find | Find files in subdirectories, e.g. find "c:\Program Files\CMake" 47 | updatedb | Build database of files in a drive, e.g. updatedb c:\ 48 | locate | Locate a file from database, e.g. locate notepad.exe 49 | 50 | To build the example programs, first install [CMake](https://cmake.org/). 51 | Then, with CMake installed, open command prompt and create a temporary 52 | directory ``c:\temp\dirent`` for the build files as 53 | 54 | ``` 55 | c:\ 56 | mkdir temp 57 | mkdir temp\dirent 58 | cd temp\dirent 59 | ``` 60 | 61 | Generate build files as 62 | 63 | ``` 64 | cmake d:\dirent 65 | ``` 66 | 67 | where ``d:\dirent`` is the root directory of the Dirent package (containing 68 | this README.md and LICENSE file). 69 | 70 | Once CMake is finished, open Visual Studio, load the generated dirent.sln file 71 | from the build directory and build the solution. Once the build completes, run 72 | the example programs from the command prompt as 73 | 74 | ``` 75 | cd Debug 76 | ls . 77 | find . 78 | updatedb c:\ 79 | locate cmd.exe 80 | ``` 81 | 82 | 83 | # Copying 84 | 85 | Dirent may be freely distributed under the MIT license. See the 86 | [LICENSE](LICENSE) file for details. 87 | 88 | 89 | # Alternatives to Dirent 90 | 91 | I ported Dirent to Microsoft Windows in 1998 when only a few alternatives 92 | were available. However, the situation has changed since then and nowadays 93 | both [Cygwin](http://www.cygwin.com) and [MingW](http://www.mingw.org) 94 | allow you to compile a great number of UNIX programs in Microsoft Windows. 95 | They both provide a full dirent API as well as many other UNIX APIs. MingW 96 | can even be used for commercial applications! 97 | -------------------------------------------------------------------------------- /dirent/dirent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dirent interface for Microsoft Visual Studio 3 | * 4 | * Copyright (C) 1998-2019 Toni Ronkko 5 | * This file is part of dirent. Dirent may be freely distributed 6 | * under the MIT license. For all details and documentation, see 7 | * https://github.com/tronkko/dirent 8 | */ 9 | #ifndef DIRENT_H 10 | #define DIRENT_H 11 | 12 | /* Hide warnings about unreferenced local functions */ 13 | #if defined(__clang__) 14 | # pragma clang diagnostic ignored "-Wunused-function" 15 | #elif defined(_MSC_VER) 16 | # pragma warning(disable:4505) 17 | #elif defined(__GNUC__) 18 | # pragma GCC diagnostic ignored "-Wunused-function" 19 | #endif 20 | 21 | /* 22 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with 23 | * Windows Sockets 2.0. 24 | */ 25 | #ifndef WIN32_LEAN_AND_MEAN 26 | # define WIN32_LEAN_AND_MEAN 27 | #endif 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /* Indicates that d_type field is available in dirent structure */ 41 | #define _DIRENT_HAVE_D_TYPE 42 | 43 | /* Indicates that d_namlen field is available in dirent structure */ 44 | #define _DIRENT_HAVE_D_NAMLEN 45 | 46 | /* Entries missing from MSVC 6.0 */ 47 | #if !defined(FILE_ATTRIBUTE_DEVICE) 48 | # define FILE_ATTRIBUTE_DEVICE 0x40 49 | #endif 50 | 51 | /* File type and permission flags for stat(), general mask */ 52 | #if !defined(S_IFMT) 53 | # define S_IFMT _S_IFMT 54 | #endif 55 | 56 | /* Directory bit */ 57 | #if !defined(S_IFDIR) 58 | # define S_IFDIR _S_IFDIR 59 | #endif 60 | 61 | /* Character device bit */ 62 | #if !defined(S_IFCHR) 63 | # define S_IFCHR _S_IFCHR 64 | #endif 65 | 66 | /* Pipe bit */ 67 | #if !defined(S_IFFIFO) 68 | # define S_IFFIFO _S_IFFIFO 69 | #endif 70 | 71 | /* Regular file bit */ 72 | #if !defined(S_IFREG) 73 | # define S_IFREG _S_IFREG 74 | #endif 75 | 76 | /* Read permission */ 77 | #if !defined(S_IREAD) 78 | # define S_IREAD _S_IREAD 79 | #endif 80 | 81 | /* Write permission */ 82 | #if !defined(S_IWRITE) 83 | # define S_IWRITE _S_IWRITE 84 | #endif 85 | 86 | /* Execute permission */ 87 | #if !defined(S_IEXEC) 88 | # define S_IEXEC _S_IEXEC 89 | #endif 90 | 91 | /* Pipe */ 92 | #if !defined(S_IFIFO) 93 | # define S_IFIFO _S_IFIFO 94 | #endif 95 | 96 | /* Block device */ 97 | #if !defined(S_IFBLK) 98 | # define S_IFBLK 0 99 | #endif 100 | 101 | /* Link */ 102 | #if !defined(S_IFLNK) 103 | # define S_IFLNK 0 104 | #endif 105 | 106 | /* Socket */ 107 | #if !defined(S_IFSOCK) 108 | # define S_IFSOCK 0 109 | #endif 110 | 111 | /* Read user permission */ 112 | #if !defined(S_IRUSR) 113 | # define S_IRUSR S_IREAD 114 | #endif 115 | 116 | /* Write user permission */ 117 | #if !defined(S_IWUSR) 118 | # define S_IWUSR S_IWRITE 119 | #endif 120 | 121 | /* Execute user permission */ 122 | #if !defined(S_IXUSR) 123 | # define S_IXUSR 0 124 | #endif 125 | 126 | /* Read group permission */ 127 | #if !defined(S_IRGRP) 128 | # define S_IRGRP 0 129 | #endif 130 | 131 | /* Write group permission */ 132 | #if !defined(S_IWGRP) 133 | # define S_IWGRP 0 134 | #endif 135 | 136 | /* Execute group permission */ 137 | #if !defined(S_IXGRP) 138 | # define S_IXGRP 0 139 | #endif 140 | 141 | /* Read others permission */ 142 | #if !defined(S_IROTH) 143 | # define S_IROTH 0 144 | #endif 145 | 146 | /* Write others permission */ 147 | #if !defined(S_IWOTH) 148 | # define S_IWOTH 0 149 | #endif 150 | 151 | /* Execute others permission */ 152 | #if !defined(S_IXOTH) 153 | # define S_IXOTH 0 154 | #endif 155 | 156 | /* Maximum length of file name */ 157 | #if !defined(PATH_MAX) 158 | # define PATH_MAX MAX_PATH 159 | #endif 160 | #if !defined(FILENAME_MAX) 161 | # define FILENAME_MAX MAX_PATH 162 | #endif 163 | #if !defined(NAME_MAX) 164 | # define NAME_MAX FILENAME_MAX 165 | #endif 166 | 167 | /* File type flags for d_type */ 168 | #define DT_UNKNOWN 0 169 | #define DT_REG S_IFREG 170 | #define DT_DIR S_IFDIR 171 | #define DT_FIFO S_IFIFO 172 | #define DT_SOCK S_IFSOCK 173 | #define DT_CHR S_IFCHR 174 | #define DT_BLK S_IFBLK 175 | #define DT_LNK S_IFLNK 176 | 177 | /* Macros for converting between st_mode and d_type */ 178 | #define IFTODT(mode) ((mode) & S_IFMT) 179 | #define DTTOIF(type) (type) 180 | 181 | /* 182 | * File type macros. Note that block devices, sockets and links cannot be 183 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are 184 | * only defined for compatibility. These macros should always return false 185 | * on Windows. 186 | */ 187 | #if !defined(S_ISFIFO) 188 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) 189 | #endif 190 | #if !defined(S_ISDIR) 191 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 192 | #endif 193 | #if !defined(S_ISREG) 194 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 195 | #endif 196 | #if !defined(S_ISLNK) 197 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 198 | #endif 199 | #if !defined(S_ISSOCK) 200 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 201 | #endif 202 | #if !defined(S_ISCHR) 203 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 204 | #endif 205 | #if !defined(S_ISBLK) 206 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 207 | #endif 208 | 209 | /* Return the exact length of the file name without zero terminator */ 210 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) 211 | 212 | /* Return the maximum size of a file name */ 213 | #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) 214 | 215 | 216 | #ifdef __cplusplus 217 | extern "C" { 218 | #endif 219 | 220 | 221 | /* Wide-character version */ 222 | struct _wdirent { 223 | /* Always zero */ 224 | long d_ino; 225 | 226 | /* File position within stream */ 227 | long d_off; 228 | 229 | /* Structure size */ 230 | unsigned short d_reclen; 231 | 232 | /* Length of name without \0 */ 233 | size_t d_namlen; 234 | 235 | /* File type */ 236 | int d_type; 237 | 238 | /* File name */ 239 | wchar_t d_name[PATH_MAX+1]; 240 | }; 241 | typedef struct _wdirent _wdirent; 242 | 243 | struct _WDIR { 244 | /* Current directory entry */ 245 | struct _wdirent ent; 246 | 247 | /* Private file data */ 248 | WIN32_FIND_DATAW data; 249 | 250 | /* True if data is valid */ 251 | int cached; 252 | 253 | /* Win32 search handle */ 254 | HANDLE handle; 255 | 256 | /* Initial directory name */ 257 | wchar_t *patt; 258 | }; 259 | typedef struct _WDIR _WDIR; 260 | 261 | /* Multi-byte character version */ 262 | struct dirent { 263 | /* Always zero */ 264 | long d_ino; 265 | 266 | /* File position within stream */ 267 | long d_off; 268 | 269 | /* Structure size */ 270 | unsigned short d_reclen; 271 | 272 | /* Length of name without \0 */ 273 | size_t d_namlen; 274 | 275 | /* File type */ 276 | int d_type; 277 | 278 | /* File name */ 279 | char d_name[PATH_MAX+1]; 280 | }; 281 | typedef struct dirent dirent; 282 | 283 | struct DIR { 284 | struct dirent ent; 285 | struct _WDIR *wdirp; 286 | }; 287 | typedef struct DIR DIR; 288 | 289 | 290 | /* Dirent functions */ 291 | static DIR *opendir (const char *dirname); 292 | static _WDIR *_wopendir (const wchar_t *dirname); 293 | 294 | static struct dirent *readdir (DIR *dirp); 295 | static struct _wdirent *_wreaddir (_WDIR *dirp); 296 | 297 | static int readdir_r( 298 | DIR *dirp, struct dirent *entry, struct dirent **result); 299 | static int _wreaddir_r( 300 | _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); 301 | 302 | static int closedir (DIR *dirp); 303 | static int _wclosedir (_WDIR *dirp); 304 | 305 | static void rewinddir (DIR* dirp); 306 | static void _wrewinddir (_WDIR* dirp); 307 | 308 | static int scandir (const char *dirname, struct dirent ***namelist, 309 | int (*filter)(const struct dirent*), 310 | int (*compare)(const struct dirent**, const struct dirent**)); 311 | 312 | static int alphasort (const struct dirent **a, const struct dirent **b); 313 | 314 | static int versionsort (const struct dirent **a, const struct dirent **b); 315 | 316 | 317 | /* For compatibility with Symbian */ 318 | #define wdirent _wdirent 319 | #define WDIR _WDIR 320 | #define wopendir _wopendir 321 | #define wreaddir _wreaddir 322 | #define wclosedir _wclosedir 323 | #define wrewinddir _wrewinddir 324 | 325 | 326 | /* Internal utility functions */ 327 | static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); 328 | static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); 329 | 330 | static int dirent_mbstowcs_s( 331 | size_t *pReturnValue, 332 | wchar_t *wcstr, 333 | size_t sizeInWords, 334 | const char *mbstr, 335 | size_t count); 336 | 337 | static int dirent_wcstombs_s( 338 | size_t *pReturnValue, 339 | char *mbstr, 340 | size_t sizeInBytes, 341 | const wchar_t *wcstr, 342 | size_t count); 343 | 344 | static void dirent_set_errno (int error); 345 | 346 | 347 | /* 348 | * Open directory stream DIRNAME for read and return a pointer to the 349 | * internal working area that is used to retrieve individual directory 350 | * entries. 351 | */ 352 | static _WDIR* 353 | _wopendir( 354 | const wchar_t *dirname) 355 | { 356 | _WDIR *dirp; 357 | DWORD n; 358 | wchar_t *p; 359 | 360 | /* Must have directory name */ 361 | if (dirname == NULL || dirname[0] == '\0') { 362 | dirent_set_errno (ENOENT); 363 | return NULL; 364 | } 365 | 366 | /* Allocate new _WDIR structure */ 367 | dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); 368 | if (!dirp) { 369 | return NULL; 370 | } 371 | 372 | /* Reset _WDIR structure */ 373 | dirp->handle = INVALID_HANDLE_VALUE; 374 | dirp->patt = NULL; 375 | dirp->cached = 0; 376 | 377 | /* 378 | * Compute the length of full path plus zero terminator 379 | * 380 | * Note that on WinRT there's no way to convert relative paths 381 | * into absolute paths, so just assume it is an absolute path. 382 | */ 383 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 384 | /* Desktop */ 385 | n = GetFullPathNameW (dirname, 0, NULL, NULL); 386 | #else 387 | /* WinRT */ 388 | n = wcslen (dirname); 389 | #endif 390 | 391 | /* Allocate room for absolute directory name and search pattern */ 392 | dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); 393 | if (dirp->patt == NULL) { 394 | goto exit_closedir; 395 | } 396 | 397 | /* 398 | * Convert relative directory name to an absolute one. This 399 | * allows rewinddir() to function correctly even when current 400 | * working directory is changed between opendir() and rewinddir(). 401 | * 402 | * Note that on WinRT there's no way to convert relative paths 403 | * into absolute paths, so just assume it is an absolute path. 404 | */ 405 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 406 | /* Desktop */ 407 | n = GetFullPathNameW (dirname, n, dirp->patt, NULL); 408 | if (n <= 0) { 409 | goto exit_closedir; 410 | } 411 | #else 412 | /* WinRT */ 413 | wcsncpy_s (dirp->patt, n+1, dirname, n); 414 | #endif 415 | 416 | /* Append search pattern \* to the directory name */ 417 | p = dirp->patt + n; 418 | switch (p[-1]) { 419 | case '\\': 420 | case '/': 421 | case ':': 422 | /* Directory ends in path separator, e.g. c:\temp\ */ 423 | /*NOP*/; 424 | break; 425 | 426 | default: 427 | /* Directory name doesn't end in path separator */ 428 | *p++ = '\\'; 429 | } 430 | *p++ = '*'; 431 | *p = '\0'; 432 | 433 | /* Open directory stream and retrieve the first entry */ 434 | if (!dirent_first (dirp)) { 435 | goto exit_closedir; 436 | } 437 | 438 | /* Success */ 439 | return dirp; 440 | 441 | /* Failure */ 442 | exit_closedir: 443 | _wclosedir (dirp); 444 | return NULL; 445 | } 446 | 447 | /* 448 | * Read next directory entry. 449 | * 450 | * Returns pointer to static directory entry which may be overwritten by 451 | * subsequent calls to _wreaddir(). 452 | */ 453 | static struct _wdirent* 454 | _wreaddir( 455 | _WDIR *dirp) 456 | { 457 | struct _wdirent *entry; 458 | 459 | /* 460 | * Read directory entry to buffer. We can safely ignore the return value 461 | * as entry will be set to NULL in case of error. 462 | */ 463 | (void) _wreaddir_r (dirp, &dirp->ent, &entry); 464 | 465 | /* Return pointer to statically allocated directory entry */ 466 | return entry; 467 | } 468 | 469 | /* 470 | * Read next directory entry. 471 | * 472 | * Returns zero on success. If end of directory stream is reached, then sets 473 | * result to NULL and returns zero. 474 | */ 475 | static int 476 | _wreaddir_r( 477 | _WDIR *dirp, 478 | struct _wdirent *entry, 479 | struct _wdirent **result) 480 | { 481 | WIN32_FIND_DATAW *datap; 482 | 483 | /* Read next directory entry */ 484 | datap = dirent_next (dirp); 485 | if (datap) { 486 | size_t n; 487 | DWORD attr; 488 | 489 | /* 490 | * Copy file name as wide-character string. If the file name is too 491 | * long to fit in to the destination buffer, then truncate file name 492 | * to PATH_MAX characters and zero-terminate the buffer. 493 | */ 494 | n = 0; 495 | while (n < PATH_MAX && datap->cFileName[n] != 0) { 496 | entry->d_name[n] = datap->cFileName[n]; 497 | n++; 498 | } 499 | entry->d_name[n] = 0; 500 | 501 | /* Length of file name excluding zero terminator */ 502 | entry->d_namlen = n; 503 | 504 | /* File type */ 505 | attr = datap->dwFileAttributes; 506 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 507 | entry->d_type = DT_CHR; 508 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 509 | entry->d_type = DT_DIR; 510 | } else { 511 | entry->d_type = DT_REG; 512 | } 513 | 514 | /* Reset dummy fields */ 515 | entry->d_ino = 0; 516 | entry->d_off = 0; 517 | entry->d_reclen = sizeof (struct _wdirent); 518 | 519 | /* Set result address */ 520 | *result = entry; 521 | 522 | } else { 523 | 524 | /* Return NULL to indicate end of directory */ 525 | *result = NULL; 526 | 527 | } 528 | 529 | return /*OK*/0; 530 | } 531 | 532 | /* 533 | * Close directory stream opened by opendir() function. This invalidates the 534 | * DIR structure as well as any directory entry read previously by 535 | * _wreaddir(). 536 | */ 537 | static int 538 | _wclosedir( 539 | _WDIR *dirp) 540 | { 541 | int ok; 542 | if (dirp) { 543 | 544 | /* Release search handle */ 545 | if (dirp->handle != INVALID_HANDLE_VALUE) { 546 | FindClose (dirp->handle); 547 | } 548 | 549 | /* Release search pattern */ 550 | free (dirp->patt); 551 | 552 | /* Release directory structure */ 553 | free (dirp); 554 | ok = /*success*/0; 555 | 556 | } else { 557 | 558 | /* Invalid directory stream */ 559 | dirent_set_errno (EBADF); 560 | ok = /*failure*/-1; 561 | 562 | } 563 | return ok; 564 | } 565 | 566 | /* 567 | * Rewind directory stream such that _wreaddir() returns the very first 568 | * file name again. 569 | */ 570 | static void 571 | _wrewinddir( 572 | _WDIR* dirp) 573 | { 574 | if (dirp) { 575 | /* Release existing search handle */ 576 | if (dirp->handle != INVALID_HANDLE_VALUE) { 577 | FindClose (dirp->handle); 578 | } 579 | 580 | /* Open new search handle */ 581 | dirent_first (dirp); 582 | } 583 | } 584 | 585 | /* Get first directory entry (internal) */ 586 | static WIN32_FIND_DATAW* 587 | dirent_first( 588 | _WDIR *dirp) 589 | { 590 | WIN32_FIND_DATAW *datap; 591 | DWORD error; 592 | 593 | /* Open directory and retrieve the first entry */ 594 | dirp->handle = FindFirstFileExW( 595 | dirp->patt, FindExInfoStandard, &dirp->data, 596 | FindExSearchNameMatch, NULL, 0); 597 | if (dirp->handle != INVALID_HANDLE_VALUE) { 598 | 599 | /* a directory entry is now waiting in memory */ 600 | datap = &dirp->data; 601 | dirp->cached = 1; 602 | 603 | } else { 604 | 605 | /* Failed to open directory: no directory entry in memory */ 606 | dirp->cached = 0; 607 | datap = NULL; 608 | 609 | /* Set error code */ 610 | error = GetLastError (); 611 | switch (error) { 612 | case ERROR_ACCESS_DENIED: 613 | /* No read access to directory */ 614 | dirent_set_errno (EACCES); 615 | break; 616 | 617 | case ERROR_DIRECTORY: 618 | /* Directory name is invalid */ 619 | dirent_set_errno (ENOTDIR); 620 | break; 621 | 622 | case ERROR_PATH_NOT_FOUND: 623 | default: 624 | /* Cannot find the file */ 625 | dirent_set_errno (ENOENT); 626 | } 627 | 628 | } 629 | return datap; 630 | } 631 | 632 | /* 633 | * Get next directory entry (internal). 634 | * 635 | * Returns 636 | */ 637 | static WIN32_FIND_DATAW* 638 | dirent_next( 639 | _WDIR *dirp) 640 | { 641 | WIN32_FIND_DATAW *p; 642 | 643 | /* Get next directory entry */ 644 | if (dirp->cached != 0) { 645 | 646 | /* A valid directory entry already in memory */ 647 | p = &dirp->data; 648 | dirp->cached = 0; 649 | 650 | } else if (dirp->handle != INVALID_HANDLE_VALUE) { 651 | 652 | /* Get the next directory entry from stream */ 653 | if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { 654 | /* Got a file */ 655 | p = &dirp->data; 656 | } else { 657 | /* The very last entry has been processed or an error occurred */ 658 | FindClose (dirp->handle); 659 | dirp->handle = INVALID_HANDLE_VALUE; 660 | p = NULL; 661 | } 662 | 663 | } else { 664 | 665 | /* End of directory stream reached */ 666 | p = NULL; 667 | 668 | } 669 | 670 | return p; 671 | } 672 | 673 | /* 674 | * Open directory stream using plain old C-string. 675 | */ 676 | static DIR* 677 | opendir( 678 | const char *dirname) 679 | { 680 | struct DIR *dirp; 681 | 682 | /* Must have directory name */ 683 | if (dirname == NULL || dirname[0] == '\0') { 684 | dirent_set_errno (ENOENT); 685 | return NULL; 686 | } 687 | 688 | /* Allocate memory for DIR structure */ 689 | dirp = (DIR*) malloc (sizeof (struct DIR)); 690 | if (!dirp) { 691 | return NULL; 692 | } 693 | { 694 | int error; 695 | wchar_t wname[PATH_MAX + 1]; 696 | size_t n; 697 | 698 | /* Convert directory name to wide-character string */ 699 | error = dirent_mbstowcs_s( 700 | &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); 701 | if (error) { 702 | /* 703 | * Cannot convert file name to wide-character string. This 704 | * occurs if the string contains invalid multi-byte sequences or 705 | * the output buffer is too small to contain the resulting 706 | * string. 707 | */ 708 | goto exit_free; 709 | } 710 | 711 | 712 | /* Open directory stream using wide-character name */ 713 | dirp->wdirp = _wopendir (wname); 714 | if (!dirp->wdirp) { 715 | goto exit_free; 716 | } 717 | 718 | } 719 | 720 | /* Success */ 721 | return dirp; 722 | 723 | /* Failure */ 724 | exit_free: 725 | free (dirp); 726 | return NULL; 727 | } 728 | 729 | /* 730 | * Read next directory entry. 731 | */ 732 | static struct dirent* 733 | readdir( 734 | DIR *dirp) 735 | { 736 | struct dirent *entry; 737 | 738 | /* 739 | * Read directory entry to buffer. We can safely ignore the return value 740 | * as entry will be set to NULL in case of error. 741 | */ 742 | (void) readdir_r (dirp, &dirp->ent, &entry); 743 | 744 | /* Return pointer to statically allocated directory entry */ 745 | return entry; 746 | } 747 | 748 | /* 749 | * Read next directory entry into called-allocated buffer. 750 | * 751 | * Returns zero on success. If the end of directory stream is reached, then 752 | * sets result to NULL and returns zero. 753 | */ 754 | static int 755 | readdir_r( 756 | DIR *dirp, 757 | struct dirent *entry, 758 | struct dirent **result) 759 | { 760 | WIN32_FIND_DATAW *datap; 761 | 762 | /* Read next directory entry */ 763 | datap = dirent_next (dirp->wdirp); 764 | if (datap) { 765 | size_t n; 766 | int error; 767 | 768 | /* Attempt to convert file name to multi-byte string */ 769 | error = dirent_wcstombs_s( 770 | &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); 771 | 772 | /* 773 | * If the file name cannot be represented by a multi-byte string, 774 | * then attempt to use old 8+3 file name. This allows traditional 775 | * Unix-code to access some file names despite of unicode 776 | * characters, although file names may seem unfamiliar to the user. 777 | * 778 | * Be ware that the code below cannot come up with a short file 779 | * name unless the file system provides one. At least 780 | * VirtualBox shared folders fail to do this. 781 | */ 782 | if (error && datap->cAlternateFileName[0] != '\0') { 783 | error = dirent_wcstombs_s( 784 | &n, entry->d_name, PATH_MAX + 1, 785 | datap->cAlternateFileName, PATH_MAX + 1); 786 | } 787 | 788 | if (!error) { 789 | DWORD attr; 790 | 791 | /* Length of file name excluding zero terminator */ 792 | entry->d_namlen = n - 1; 793 | 794 | /* File attributes */ 795 | attr = datap->dwFileAttributes; 796 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 797 | entry->d_type = DT_CHR; 798 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 799 | entry->d_type = DT_DIR; 800 | } else { 801 | entry->d_type = DT_REG; 802 | } 803 | 804 | /* Reset dummy fields */ 805 | entry->d_ino = 0; 806 | entry->d_off = 0; 807 | entry->d_reclen = sizeof (struct dirent); 808 | 809 | } else { 810 | 811 | /* 812 | * Cannot convert file name to multi-byte string so construct 813 | * an erroneous directory entry and return that. Note that 814 | * we cannot return NULL as that would stop the processing 815 | * of directory entries completely. 816 | */ 817 | entry->d_name[0] = '?'; 818 | entry->d_name[1] = '\0'; 819 | entry->d_namlen = 1; 820 | entry->d_type = DT_UNKNOWN; 821 | entry->d_ino = 0; 822 | entry->d_off = -1; 823 | entry->d_reclen = 0; 824 | 825 | } 826 | 827 | /* Return pointer to directory entry */ 828 | *result = entry; 829 | 830 | } else { 831 | 832 | /* No more directory entries */ 833 | *result = NULL; 834 | 835 | } 836 | 837 | return /*OK*/0; 838 | } 839 | 840 | /* 841 | * Close directory stream. 842 | */ 843 | static int 844 | closedir( 845 | DIR *dirp) 846 | { 847 | int ok; 848 | if (dirp) { 849 | 850 | /* Close wide-character directory stream */ 851 | ok = _wclosedir (dirp->wdirp); 852 | dirp->wdirp = NULL; 853 | 854 | /* Release multi-byte character version */ 855 | free (dirp); 856 | 857 | } else { 858 | 859 | /* Invalid directory stream */ 860 | dirent_set_errno (EBADF); 861 | ok = /*failure*/-1; 862 | 863 | } 864 | return ok; 865 | } 866 | 867 | /* 868 | * Rewind directory stream to beginning. 869 | */ 870 | static void 871 | rewinddir( 872 | DIR* dirp) 873 | { 874 | /* Rewind wide-character string directory stream */ 875 | _wrewinddir (dirp->wdirp); 876 | } 877 | 878 | /* 879 | * Scan directory for entries. 880 | */ 881 | static int 882 | scandir( 883 | const char *dirname, 884 | struct dirent ***namelist, 885 | int (*filter)(const struct dirent*), 886 | int (*compare)(const struct dirent**, const struct dirent**)) 887 | { 888 | struct dirent **files = NULL; 889 | size_t size = 0; 890 | size_t allocated = 0; 891 | const size_t init_size = 1; 892 | DIR *dir = NULL; 893 | struct dirent *entry; 894 | struct dirent *tmp = NULL; 895 | size_t i; 896 | int result = 0; 897 | 898 | /* Open directory stream */ 899 | dir = opendir (dirname); 900 | if (dir) { 901 | 902 | /* Read directory entries to memory */ 903 | while (1) { 904 | 905 | /* Enlarge pointer table to make room for another pointer */ 906 | if (size >= allocated) { 907 | void *p; 908 | size_t num_entries; 909 | 910 | /* Compute number of entries in the enlarged pointer table */ 911 | if (size < init_size) { 912 | /* Allocate initial pointer table */ 913 | num_entries = init_size; 914 | } else { 915 | /* Double the size */ 916 | num_entries = size * 2; 917 | } 918 | 919 | /* Allocate first pointer table or enlarge existing table */ 920 | p = realloc (files, sizeof (void*) * num_entries); 921 | if (p != NULL) { 922 | /* Got the memory */ 923 | files = (dirent**) p; 924 | allocated = num_entries; 925 | } else { 926 | /* Out of memory */ 927 | result = -1; 928 | break; 929 | } 930 | 931 | } 932 | 933 | /* Allocate room for temporary directory entry */ 934 | if (tmp == NULL) { 935 | tmp = (struct dirent*) malloc (sizeof (struct dirent)); 936 | if (tmp == NULL) { 937 | /* Cannot allocate temporary directory entry */ 938 | result = -1; 939 | break; 940 | } 941 | } 942 | 943 | /* Read directory entry to temporary area */ 944 | if (readdir_r (dir, tmp, &entry) == /*OK*/0) { 945 | 946 | /* Did we get an entry? */ 947 | if (entry != NULL) { 948 | int pass; 949 | 950 | /* Determine whether to include the entry in result */ 951 | if (filter) { 952 | /* Let the filter function decide */ 953 | pass = filter (tmp); 954 | } else { 955 | /* No filter function, include everything */ 956 | pass = 1; 957 | } 958 | 959 | if (pass) { 960 | /* Store the temporary entry to pointer table */ 961 | files[size++] = tmp; 962 | tmp = NULL; 963 | 964 | /* Keep up with the number of files */ 965 | result++; 966 | } 967 | 968 | } else { 969 | 970 | /* 971 | * End of directory stream reached => sort entries and 972 | * exit. 973 | */ 974 | qsort (files, size, sizeof (void*), 975 | (int (*) (const void*, const void*)) compare); 976 | break; 977 | 978 | } 979 | 980 | } else { 981 | /* Error reading directory entry */ 982 | result = /*Error*/ -1; 983 | break; 984 | } 985 | 986 | } 987 | 988 | } else { 989 | /* Cannot open directory */ 990 | result = /*Error*/ -1; 991 | } 992 | 993 | /* Release temporary directory entry */ 994 | free (tmp); 995 | 996 | /* Release allocated memory on error */ 997 | if (result < 0) { 998 | for (i = 0; i < size; i++) { 999 | free (files[i]); 1000 | } 1001 | free (files); 1002 | files = NULL; 1003 | } 1004 | 1005 | /* Close directory stream */ 1006 | if (dir) { 1007 | closedir (dir); 1008 | } 1009 | 1010 | /* Pass pointer table to caller */ 1011 | if (namelist) { 1012 | *namelist = files; 1013 | } 1014 | return result; 1015 | } 1016 | 1017 | /* Alphabetical sorting */ 1018 | static int 1019 | alphasort( 1020 | const struct dirent **a, const struct dirent **b) 1021 | { 1022 | return strcoll ((*a)->d_name, (*b)->d_name); 1023 | } 1024 | 1025 | /* Sort versions */ 1026 | static int 1027 | versionsort( 1028 | const struct dirent **a, const struct dirent **b) 1029 | { 1030 | /* FIXME: implement strverscmp and use that */ 1031 | return alphasort (a, b); 1032 | } 1033 | 1034 | /* Convert multi-byte string to wide character string */ 1035 | static int 1036 | dirent_mbstowcs_s( 1037 | size_t *pReturnValue, 1038 | wchar_t *wcstr, 1039 | size_t sizeInWords, 1040 | const char *mbstr, 1041 | size_t count) 1042 | { 1043 | int error; 1044 | 1045 | #if defined(_MSC_VER) && _MSC_VER >= 1400 1046 | 1047 | /* Microsoft Visual Studio 2005 or later */ 1048 | error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); 1049 | 1050 | #else 1051 | 1052 | /* Older Visual Studio or non-Microsoft compiler */ 1053 | size_t n; 1054 | 1055 | /* Convert to wide-character string (or count characters) */ 1056 | n = mbstowcs (wcstr, mbstr, sizeInWords); 1057 | if (!wcstr || n < count) { 1058 | 1059 | /* Zero-terminate output buffer */ 1060 | if (wcstr && sizeInWords) { 1061 | if (n >= sizeInWords) { 1062 | n = sizeInWords - 1; 1063 | } 1064 | wcstr[n] = 0; 1065 | } 1066 | 1067 | /* Length of resulting multi-byte string WITH zero terminator */ 1068 | if (pReturnValue) { 1069 | *pReturnValue = n + 1; 1070 | } 1071 | 1072 | /* Success */ 1073 | error = 0; 1074 | 1075 | } else { 1076 | 1077 | /* Could not convert string */ 1078 | error = 1; 1079 | 1080 | } 1081 | 1082 | #endif 1083 | return error; 1084 | } 1085 | 1086 | /* Convert wide-character string to multi-byte string */ 1087 | static int 1088 | dirent_wcstombs_s( 1089 | size_t *pReturnValue, 1090 | char *mbstr, 1091 | size_t sizeInBytes, /* max size of mbstr */ 1092 | const wchar_t *wcstr, 1093 | size_t count) 1094 | { 1095 | int error; 1096 | 1097 | #if defined(_MSC_VER) && _MSC_VER >= 1400 1098 | 1099 | /* Microsoft Visual Studio 2005 or later */ 1100 | error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); 1101 | 1102 | #else 1103 | 1104 | /* Older Visual Studio or non-Microsoft compiler */ 1105 | size_t n; 1106 | 1107 | /* Convert to multi-byte string (or count the number of bytes needed) */ 1108 | n = wcstombs (mbstr, wcstr, sizeInBytes); 1109 | if (!mbstr || n < count) { 1110 | 1111 | /* Zero-terminate output buffer */ 1112 | if (mbstr && sizeInBytes) { 1113 | if (n >= sizeInBytes) { 1114 | n = sizeInBytes - 1; 1115 | } 1116 | mbstr[n] = '\0'; 1117 | } 1118 | 1119 | /* Length of resulting multi-bytes string WITH zero-terminator */ 1120 | if (pReturnValue) { 1121 | *pReturnValue = n + 1; 1122 | } 1123 | 1124 | /* Success */ 1125 | error = 0; 1126 | 1127 | } else { 1128 | 1129 | /* Cannot convert string */ 1130 | error = 1; 1131 | 1132 | } 1133 | 1134 | #endif 1135 | return error; 1136 | } 1137 | 1138 | /* Set errno variable */ 1139 | static void 1140 | dirent_set_errno( 1141 | int error) 1142 | { 1143 | #if defined(_MSC_VER) && _MSC_VER >= 1400 1144 | 1145 | /* Microsoft Visual Studio 2005 and later */ 1146 | _set_errno (error); 1147 | 1148 | #else 1149 | 1150 | /* Non-Microsoft compiler or older Microsoft compiler */ 1151 | errno = error; 1152 | 1153 | #endif 1154 | } 1155 | 1156 | 1157 | #ifdef __cplusplus 1158 | } 1159 | #endif 1160 | #endif /*DIRENT_H*/ 1161 | -------------------------------------------------------------------------------- /stb/LICENSE: -------------------------------------------------------------------------------- 1 | This software is available under 2 licenses -- choose whichever you prefer. 2 | ------------------------------------------------------------------------------ 3 | ALTERNATIVE A - MIT License 4 | Copyright (c) 2017 Sean Barrett 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | ------------------------------------------------------------------------------ 21 | ALTERNATIVE B - Public Domain (www.unlicense.org) 22 | This is free and unencumbered software released into the public domain. 23 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 24 | software, either in source code form or as a compiled binary, for any purpose, 25 | commercial or non-commercial, and by any means. 26 | In jurisdictions that recognize copyright laws, the author or authors of this 27 | software dedicate any and all copyright interest in the software to the public 28 | domain. We make this dedication for the benefit of the public at large and to 29 | the detriment of our heirs and successors. We intend this dedication to be an 30 | overt act of relinquishment in perpetuity of all present and future rights to 31 | this software under copyright law. 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 36 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 37 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 38 | -------------------------------------------------------------------------------- /stb/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | stb 4 | === 5 | 6 | single-file public domain (or MIT licensed) libraries for C/C++ 7 | 8 | # This project discusses security-relevant bugs in public in Github Issues and Pull Requests, and it may take significant time for security fixes to be implemented or merged. If this poses an unreasonable risk to your project, do not use stb libraries. 9 | 10 | Noteworthy: 11 | 12 | * image loader: [stb_image.h](stb_image.h) 13 | * image writer: [stb_image_write.h](stb_image_write.h) 14 | * image resizer: [stb_image_resize2.h](stb_image_resize2.h) 15 | * font text rasterizer: [stb_truetype.h](stb_truetype.h) 16 | * typesafe containers: [stb_ds.h](stb_ds.h) 17 | 18 | Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, original stb_image_resize 19 | by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 and stb_sprintf by Jeff Roberts. 20 | 21 | 22 | 23 | library | lastest version | category | LoC | description 24 | --------------------- | ---- | -------- | --- | -------------------------------- 25 | **[stb_vorbis.c](stb_vorbis.c)** | 1.22 | audio | 5584 | decode ogg vorbis files from file/memory to float/16-bit signed output 26 | **[stb_hexwave.h](stb_hexwave.h)** | 0.5 | audio | 680 | audio waveform synthesizer 27 | **[stb_image.h](stb_image.h)** | 2.29 | graphics | 7985 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC 28 | **[stb_truetype.h](stb_truetype.h)** | 1.26 | graphics | 5077 | parse, decode, and rasterize characters from truetype fonts 29 | **[stb_image_write.h](stb_image_write.h)** | 1.16 | graphics | 1724 | image writing to disk: PNG, TGA, BMP 30 | **[stb_image_resize2.h](stb_image_resize2.h)** | 2.04 | graphics | 10325 | resize images larger/smaller with good quality 31 | **[stb_rect_pack.h](stb_rect_pack.h)** | 1.01 | graphics | 623 | simple 2D rectangle packer with decent quality 32 | **[stb_perlin.h](stb_perlin.h)** | 0.5 | graphics | 428 | perlin's revised simplex noise w/ different seeds 33 | **[stb_ds.h](stb_ds.h)** | 0.67 | utility | 1895 | typesafe dynamic array and hash tables for C, will compile in C++ 34 | **[stb_sprintf.h](stb_sprintf.h)** | 1.10 | utility | 1906 | fast sprintf, snprintf for C/C++ 35 | **[stb_textedit.h](stb_textedit.h)** | 1.14 | user interface | 1429 | guts of a text editor for games etc implementing them from scratch 36 | **[stb_voxel_render.h](stb_voxel_render.h)** | 0.89 | 3D graphics | 3807 | Minecraft-esque voxel rendering "engine" with many more features 37 | **[stb_dxt.h](stb_dxt.h)** | 1.12 | 3D graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor 38 | **[stb_easy_font.h](stb_easy_font.h)** | 1.1 | 3D graphics | 305 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc 39 | **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.42 | game dev | 4187 | embeddable tilemap editor 40 | **[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.7 | game dev | 1221 | herringbone Wang tile map generator 41 | **[stb_c_lexer.h](stb_c_lexer.h)** | 0.12 | parsing | 940 | simplify writing parsers for C-like languages 42 | **[stb_divide.h](stb_divide.h)** | 0.94 | math | 433 | more useful 32-bit modulus e.g. "euclidean divide" 43 | **[stb_connected_comp...](stb_connected_components.h)** | 0.96 | misc | 1049 | incrementally compute reachability on grids 44 | **[stb_leakcheck.h](stb_leakcheck.h)** | 0.6 | misc | 194 | quick-and-dirty malloc/free leak-checking 45 | **[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL 46 | 47 | Total libraries: 21 48 | Total lines of C code: 50806 49 | 50 | 51 | FAQ 52 | --- 53 | 54 | #### What's the license? 55 | 56 | These libraries are in the public domain. You can do anything you 57 | want with them. You have no legal obligation 58 | to do anything else, although I appreciate attribution. 59 | 60 | They are also licensed under the MIT open source license, if you have lawyers 61 | who are unhappy with public domain. Every source file includes an explicit 62 | dual-license for you to choose from. 63 | 64 | #### How do I use these libraries? 65 | 66 | The idea behind single-header file libraries is that they're easy to distribute and deploy 67 | because all the code is contained in a single file. By default, the .h files in here act as 68 | their own header files, i.e. they declare the functions contained in the file but don't 69 | actually result in any code getting compiled. 70 | 71 | So in addition, you should select _exactly one_ C/C++ source file that actually instantiates 72 | the code, preferably a file you're not editing frequently. This file should define a 73 | specific macro (this is documented per-library) to actually enable the function definitions. 74 | For example, to use stb_image, you should have exactly one C/C++ file that doesn't 75 | include stb_image.h regularly, but instead does 76 | 77 | #define STB_IMAGE_IMPLEMENTATION 78 | #include "stb_image.h" 79 | 80 | The right macro to define is pointed out right at the top of each of these libraries. 81 | 82 | #### Are there other single-file public-domain/open source libraries with minimal dependencies out there? 83 | 84 | [Yes.](https://github.com/nothings/single_file_libs) 85 | 86 | #### If I wrap an stb library in a new library, does the new library have to be public domain/MIT? 87 | 88 | No, because it's public domain you can freely relicense it to whatever license your new 89 | library wants to be. 90 | 91 | #### What's the deal with SSE support in GCC-based compilers? 92 | 93 | stb_image will either use SSE2 (if you compile with -msse2) or 94 | will not use any SIMD at all, rather than trying to detect the 95 | processor at runtime and handle it correctly. As I understand it, 96 | the approved path in GCC for runtime-detection require 97 | you to use multiple source files, one for each CPU configuration. 98 | Because stb_image is a header-file library that compiles in only 99 | one source file, there's no approved way to build both an 100 | SSE-enabled and a non-SSE-enabled variation. 101 | 102 | While we've tried to work around it, we've had multiple issues over 103 | the years due to specific versions of gcc breaking what we're doing, 104 | so we've given up on it. See https://github.com/nothings/stb/issues/280 105 | and https://github.com/nothings/stb/issues/410 for examples. 106 | 107 | #### Some of these libraries seem redundant to existing open source libraries. Are they better somehow? 108 | 109 | Generally they're only better in that they're easier to integrate, 110 | easier to use, and easier to release (single file; good API; no 111 | attribution requirement). They may be less featureful, slower, 112 | and/or use more memory. If you're already using an equivalent 113 | library, there's probably no good reason to switch. 114 | 115 | #### Can I link directly to the table of stb libraries? 116 | 117 | You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list. 118 | 119 | #### Why do you list "lines of code"? It's a terrible metric. 120 | 121 | Just to give you some idea of the internal complexity of the library, 122 | to help you manage your expectations, or to let you know what you're 123 | getting into. While not all the libraries are written in the same 124 | style, they're certainly similar styles, and so comparisons between 125 | the libraries are probably still meaningful. 126 | 127 | Note though that the lines do include both the implementation, the 128 | part that corresponds to a header file, and the documentation. 129 | 130 | #### Why single-file headers? 131 | 132 | Windows doesn't have standard directories where libraries 133 | live. That makes deploying libraries in Windows a lot more 134 | painful than open source developers on Unix-derivates generally 135 | realize. (It also makes library dependencies a lot worse in Windows.) 136 | 137 | There's also a common problem in Windows where a library was built 138 | against a different version of the runtime library, which causes 139 | link conflicts and confusion. Shipping the libs as headers means 140 | you normally just compile them straight into your project without 141 | making libraries, thus sidestepping that problem. 142 | 143 | Making them a single file makes it very easy to just 144 | drop them into a project that needs them. (Of course you can 145 | still put them in a proper shared library tree if you want.) 146 | 147 | Why not two files, one a header and one an implementation? 148 | The difference between 10 files and 9 files is not a big deal, 149 | but the difference between 2 files and 1 file is a big deal. 150 | You don't need to zip or tar the files up, you don't have to 151 | remember to attach *two* files, etc. 152 | 153 | #### Why "stb"? Is this something to do with Set-Top Boxes? 154 | 155 | No, they are just the initials for my name, Sean T. Barrett. 156 | This was not chosen out of egomania, but as a moderately sane 157 | way of namespacing the filenames and source function names. 158 | 159 | #### Will you add more image types to stb_image.h? 160 | 161 | No. As stb_image use has grown, it has become more important 162 | for us to focus on security of the codebase. Adding new image 163 | formats increases the amount of code we need to secure, so it 164 | is no longer worth adding new formats. 165 | 166 | #### Do you have any advice on how to create my own single-file library? 167 | 168 | Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt 169 | 170 | #### Why public domain? 171 | 172 | I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons. 173 | Some of them are listed here: 174 | https://github.com/nothings/stb/blob/master/docs/why_public_domain.md 175 | 176 | #### Why C? 177 | 178 | Primarily, because I use C, not C++. But it does also make it easier 179 | for other people to use them from other languages. 180 | 181 | #### Why not C99? stdint.h, declare-anywhere, etc. 182 | 183 | I still use MSVC 6 (1998) as my IDE because it has better human factors 184 | for me than later versions of MSVC. 185 | --------------------------------------------------------------------------------