| Fling Engine 0.00.1 Fling Engine is a game engine written in Vulkan

ImFileBrowser.hpp
Go to the documentation of this file.
1 #pragma once
2
3 // From https://github.com/AirGuanZ/imgui-filebrowser
4 // MIT liscence
5
6 #include <array>
7 #include <filesystem>
8 #include <functional>
9 #include <memory>
10 #include <string>
11
12 #ifndef IMGUI_VERSION
13 # error "include imgui.h before this header"
14 #endif
15
16 using ImGuiFileBrowserFlags = int;
17
18 enum ImGuiFileBrowserFlags_
19 {
20 ImGuiFileBrowserFlags_SelectDirectory = 1 << 0, // select directory instead of regular file
21 ImGuiFileBrowserFlags_EnterNewFilename = 1 << 1, // allow user to enter new filename when selecting regular file
22 ImGuiFileBrowserFlags_NoModal = 1 << 2, // file browsing window is modal by default. specify this to use a popup window
23 ImGuiFileBrowserFlags_NoTitleBar = 1 << 3, // hide window title bar
24 ImGuiFileBrowserFlags_NoStatusBar = 1 << 4, // hide status bar at the bottom of browsing window
25 ImGuiFileBrowserFlags_CloseOnEsc = 1 << 5, // close file browser when pressing 'ESC'
26 ImGuiFileBrowserFlags_CreateNewDir = 1 << 6, // allow user to create new directory
27 };
28
29 namespace ImGui
30 {
31 class FileBrowser
32 {
33 public:
34
35 // pwd is set to current working directory by default
36 explicit FileBrowser(ImGuiFileBrowserFlags flags = 0);
37
38 FileBrowser(const FileBrowser &copyFrom);
39
40 FileBrowser &operator=(const FileBrowser &copyFrom);
41
42 // set the window title text
43 void SetTitle(std::string title);
44
45 // open the browsing window
46 void Open();
47
48 // close the browsing window
49 void Close();
50
51 // the browsing window is opened or not
52 bool IsOpened() const noexcept;
53
54 // display the browsing window if opened
55 void Display();
56
57 // returns true when there is a selected filename and the "ok" button was clicked
58 bool HasSelected() const noexcept;
59
60 // set current browsing directory
61 bool SetPwd(const std::filesystem::path &pwd = std::filesystem::current_path());
62
63 // returns selected filename. make sense only when HasSelected returns true
64 std::filesystem::path GetSelected() const;
65
66 // set selected filename to empty
67 void ClearSelected();
68
69 void SetTypeFilters(const std::vector<const char*> &typeFilters);
70
71 private:
72
73 class ScopeGuard
74 {
75 std::function<void()> func_;
76
77 public:
78
79 template<typename T>
80 explicit ScopeGuard(T func) : func_(std::move(func)) { }
81 ~ScopeGuard() { func_(); }
82 };
83
84 void SetPwdUncatched(const std::filesystem::path &pwd);
85
86 #ifdef _WIN32
87 static std::uint32_t GetDrivesBitMask();
88 #endif
89
90 ImGuiFileBrowserFlags flags_;
91
92 std::string title_;
93 std::string openLabel_;
94
95 bool openFlag_;
96 bool closeFlag_;
97 bool isOpened_;
98 bool ok_;
99
100 std::string statusStr_;
101
102 std::vector<const char*> typeFilters_;
103 int typeFilterIndex_;
104
105 std::filesystem::path pwd_;
106 std::string selectedFilename_;
107
108 struct FileRecord
109 {
110 bool isDir = false;
111 std::string name;
112 std::string showName;
113 std::string extension;
114 };
115 std::vector<FileRecord> fileRecords_;
116
117 // IMPROVE: overflow when selectedFilename_.length() > inputNameBuf_.size() - 1
118 static constexpr size_t INPUT_NAME_BUF_SIZE = 512;
119 std::unique_ptr<std::array<char, INPUT_NAME_BUF_SIZE>> inputNameBuf_;
120
121 std::string openNewDirLabel_;
122 std::unique_ptr<std::array<char, INPUT_NAME_BUF_SIZE>> newDirNameBuf_;
123
124 #ifdef _WIN32
125 uint32_t drives_;
126 #endif
127 };
128 } // namespace ImGui
129
130 inline ImGui::FileBrowser::FileBrowser(ImGuiFileBrowserFlags flags)
131 : flags_(flags),
132 openFlag_(false), closeFlag_(false), isOpened_(false), ok_(false),
133 inputNameBuf_(std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>())
134 {
135 if(flags_ & ImGuiFileBrowserFlags_CreateNewDir)
136 newDirNameBuf_ = std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>();
137
138 inputNameBuf_->at(0) = '\0';
139 SetTitle("file browser");
140 SetPwd(std::filesystem::current_path());
141
142 typeFilters_.clear();
143 typeFilterIndex_ = 0;
144
145 #ifdef _WIN32
146 drives_ = GetDrivesBitMask();
147 #endif
148 }
149
150 inline ImGui::FileBrowser::FileBrowser(const FileBrowser &copyFrom)
151 : FileBrowser()
152 {
153 *this = copyFrom;
154 }
155
156 inline ImGui::FileBrowser &ImGui::FileBrowser::operator=(const FileBrowser &copyFrom)
157 {
158 flags_ = copyFrom.flags_;
159 SetTitle(copyFrom.title_);
160
161 openFlag_ = copyFrom.openFlag_;
162 closeFlag_ = copyFrom.closeFlag_;
163 isOpened_ = copyFrom.isOpened_;
164 ok_ = copyFrom.ok_;
165
166 statusStr_ = "";
167 pwd_ = copyFrom.pwd_;
168 selectedFilename_ = copyFrom.selectedFilename_;
169
170 fileRecords_ = copyFrom.fileRecords_;
171
172 *inputNameBuf_ = *copyFrom.inputNameBuf_;
173
174 if(flags_ & ImGuiFileBrowserFlags_CreateNewDir)
175 {
176 newDirNameBuf_ = std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>();
177 *newDirNameBuf_ = *copyFrom.newDirNameBuf_;
178 }
179
180 return *this;
181 }
182
183 inline void ImGui::FileBrowser::SetTitle(std::string title)
184 {
185 title_ = std::move(title);
186 openLabel_ = title_ + "##filebrowser_" + std::to_string(reinterpret_cast<size_t>(this));
187 openNewDirLabel_ = "new dir##new_dir_" + std::to_string(reinterpret_cast<size_t>(this));
188 }
189
190 inline void ImGui::FileBrowser::Open()
191 {
192 ClearSelected();
193 statusStr_ = std::string();
194 openFlag_ = true;
195 closeFlag_ = false;
196 #ifdef _WIN32
197 GetDrivesBitMask();
198 #endif
199 }
200
201 inline void ImGui::FileBrowser::Close()
202 {
203 ClearSelected();
204 statusStr_ = std::string();
205 closeFlag_ = true;
206 openFlag_ = false;
207 }
208
209 inline bool ImGui::FileBrowser::IsOpened() const noexcept
210 {
211 return isOpened_;
212 }
213
214 inline void ImGui::FileBrowser::Display()
215 {
216 PushID(this);
217 ScopeGuard exitThis([this] { openFlag_ = false; closeFlag_ = false; PopID(); });
218
219 if(openFlag_)
220 OpenPopup(openLabel_.c_str());
221 isOpened_ = false;
222
223 // open the popup window
224
225 if(openFlag_ && (flags_ & ImGuiFileBrowserFlags_NoModal))
226 SetNextWindowSize(ImVec2(700, 450));
227 else
228 SetNextWindowSize(ImVec2(700, 450), ImGuiCond_FirstUseEver);
229 if(flags_ & ImGuiFileBrowserFlags_NoModal)
230 {
231 if(!BeginPopup(openLabel_.c_str()))
232 return;
233 }
234 else if(!BeginPopupModal(openLabel_.c_str(), nullptr,
235 flags_ & ImGuiFileBrowserFlags_NoTitleBar ? ImGuiWindowFlags_NoTitleBar : 0))
236 {
237 return;
238 }
239 isOpened_ = true;
240 ScopeGuard endPopup([] { EndPopup(); });
241
242 // display elements in pwd
243
244 #ifdef _WIN32
245 char currentDrive = static_cast<char>(pwd_.c_str()[0]);
246 char driveStr[] = { currentDrive, ':', '\0' };
247
248 PushItemWidth(4 * GetFontSize());
249 if(BeginCombo("##SelectDrive", driveStr))
250 {
251 ScopeGuard guard([&] { ImGui::EndCombo(); });
252 for(int i = 0; i < 26; ++i)
253 {
254 if(!(drives_ & (1 << i)))
255 continue;
256 char driveCh = static_cast<char>('A' + i);
257 char selectableStr[] = { driveCh, ':', '\0' };
258 bool selected = currentDrive == driveCh;
259 if(Selectable(selectableStr, selected) && !selected)
260 {
261 char newPwd[] = { driveCh, ':', '\\', '\0' };
262 SetPwd(newPwd);
263 }
264 }
265 }
266 PopItemWidth();
267
268 SameLine();
269 #endif
270
271 int secIdx = 0, newPwdLastSecIdx = -1;
272 for(auto &sec : pwd_)
273 {
274 #ifdef _WIN32
275 if(secIdx == 1)
276 {
277 ++secIdx;
278 continue;
279 }
280 #endif
281 PushID(secIdx);
282 if(secIdx > 0)
283 SameLine();
284 if(SmallButton(sec.u8string().c_str()))
285 newPwdLastSecIdx = secIdx;
286 PopID();
287 ++secIdx;
288 }
289
290 if(newPwdLastSecIdx >= 0)
291 {
292 int i = 0;
293 std::filesystem::path newPwd;
294 for(auto &sec : pwd_)
295 {
296 if(i++ > newPwdLastSecIdx)
297 break;
298 newPwd /= sec;
299 }
300 #ifdef _WIN32
301 if(newPwdLastSecIdx == 0)
302 newPwd /= "\\";
303 #endif
304 SetPwd(newPwd);
305 }
306
307 SameLine();
308
309 if(SmallButton("*"))
310 SetPwd(pwd_);
311
312 if(newDirNameBuf_)
313 {
314 SameLine();
315 if(SmallButton("+"))
316 {
317 OpenPopup(openNewDirLabel_.c_str());
318 (*newDirNameBuf_)[0] = '\0';
319 }
320
321 if(BeginPopup(openNewDirLabel_.c_str()))
322 {
323 ScopeGuard endNewDirPopup([] { EndPopup(); });
324
325 InputText("name", newDirNameBuf_->data(), newDirNameBuf_->size()); SameLine();
326 if(Button("ok") && (*newDirNameBuf_)[0] != '\0')
327 {
328 ScopeGuard closeNewDirPopup([] { CloseCurrentPopup(); });
329 if(create_directory(pwd_ / newDirNameBuf_->data()))
330 SetPwd(pwd_);
331 else
332 statusStr_ = "failed to create " + std::string(newDirNameBuf_->data());
333 }
334 }
335 }
336
337 // browse files in a child window
338
339 float reserveHeight = GetItemsLineHeightWithSpacing();
340 std::filesystem::path newPwd; bool setNewPwd = false;
341 if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) && (flags_ & ImGuiFileBrowserFlags_EnterNewFilename))
342 reserveHeight += GetItemsLineHeightWithSpacing();
343 {
344 BeginChild("ch", ImVec2(0, -reserveHeight), true,
345 (flags_ & ImGuiFileBrowserFlags_NoModal) ? ImGuiWindowFlags_AlwaysHorizontalScrollbar : 0);
346 ScopeGuard endChild([] { EndChild(); });
347
348 for(auto &rsc : fileRecords_)
349 {
350 if (!rsc.isDir && typeFilters_.size() > 0 &&
351 static_cast<size_t>(typeFilterIndex_) < typeFilters_.size() &&
352 !(rsc.extension == typeFilters_[typeFilterIndex_]))
353 continue;
354
355 if(!rsc.name.empty() && rsc.name[0] == '$')
356 continue;
357
358 const bool selected = selectedFilename_ == rsc.name;
359 if(Selectable(rsc.showName.c_str(), selected, ImGuiSelectableFlags_DontClosePopups))
360 {
361 if(selected)
362 {
363 selectedFilename_ = std::string();
364 (*inputNameBuf_)[0] = '\0';
365 }
366 else if(rsc.name != "..")
367 {
368 if((rsc.isDir && (flags_ & ImGuiFileBrowserFlags_SelectDirectory)) ||
369 (!rsc.isDir && !(flags_ & ImGuiFileBrowserFlags_SelectDirectory)))
370 {
371 selectedFilename_ = rsc.name;
372 if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
373 std::strcpy(inputNameBuf_->data(), selectedFilename_.c_str());
374 }
375 }
376 }
377
378 if(IsItemClicked(0) && IsMouseDoubleClicked(0) && rsc.isDir)
379 {
380 setNewPwd = true;
381 newPwd = (rsc.name != "..") ? (pwd_ / rsc.name) : pwd_.parent_path();
382 }
383 }
384 }
385
386 if(setNewPwd)
387 SetPwd(newPwd);
388
389 if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) && (flags_ & ImGuiFileBrowserFlags_EnterNewFilename))
390 {
391 PushID(this);
392 ScopeGuard popTextID([] { PopID(); });
393
394 PushItemWidth(-1);
395 if(InputText("", inputNameBuf_->data(), inputNameBuf_->size()))
396 selectedFilename_ = inputNameBuf_->data();
397 PopItemWidth();
398 }
399
400 if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
401 {
402 if(Button(" ok ") && !selectedFilename_.empty())
403 {
404 ok_ = true;
405 CloseCurrentPopup();
406 }
407 }
408 else
409 {
410 if(selectedFilename_.empty())
411 {
412 if(Button(" ok "))
413 {
414 ok_ = true;
415 CloseCurrentPopup();
416 }
417 }
418 else if(Button("open"))
419 SetPwd(pwd_ / selectedFilename_);
420 }
421
422 SameLine();
423
424 int escIdx = GetIO().KeyMap[ImGuiKey_Escape];
425 if(Button("cancel") || closeFlag_ ||
426 ((flags_ & ImGuiFileBrowserFlags_CloseOnEsc) && IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && escIdx >= 0 && IsKeyPressed(escIdx)))
427 CloseCurrentPopup();
428
429 if(!statusStr_.empty() && !(flags_ & ImGuiFileBrowserFlags_NoStatusBar))
430 {
431 SameLine();
432 Text("%s", statusStr_.c_str());
433 }
434
435 if (!typeFilters_.empty())
436 {
437 SameLine();
438 PushItemWidth(8 * GetFontSize());
439 Combo("##Filters", &typeFilterIndex_, typeFilters_.data(), int(typeFilters_.size()));
440 PopItemWidth();
441 }
442 }
443
444 inline bool ImGui::FileBrowser::HasSelected() const noexcept
445 {
446 return ok_;
447 }
448
449 inline bool ImGui::FileBrowser::SetPwd(const std::filesystem::path &pwd)
450 {
451 try
452 {
453 SetPwdUncatched(pwd);
454 return true;
455 }
456 catch(const std::exception &err)
457 {
458 statusStr_ = std::string("last error: ") + err.what();
459 }
460 catch(...)
461 {
462 statusStr_ = "last error: unknown";
463 }
464
465 SetPwdUncatched(std::filesystem::current_path());
466 return false;
467 }
468
469 inline std::filesystem::path ImGui::FileBrowser::GetSelected() const
470 {
471 return pwd_ / selectedFilename_;
472 }
473
474 inline void ImGui::FileBrowser::ClearSelected()
475 {
476 selectedFilename_ = std::string();
477 (*inputNameBuf_)[0] = '\0';
478 ok_ = false;
479 }
480
481 inline void ImGui::FileBrowser::SetTypeFilters(const std::vector<const char*> &typeFilters)
482 {
483 typeFilters_ = typeFilters;
484 typeFilterIndex_ = 0;
485 }
486
487 inline void ImGui::FileBrowser::SetPwdUncatched(const std::filesystem::path &pwd)
488 {
489 fileRecords_ = { FileRecord{ true, "..", "[D] .." } };
490
491 for(auto &p : std::filesystem::directory_iterator(pwd))
492 {
493 FileRecord rcd;
494
495 if(p.is_regular_file())
496 rcd.isDir = false;
497 else if(p.is_directory())
498 rcd.isDir = true;
499 else
500 continue;
501
502 rcd.name = p.path().filename().string();
503 if(rcd.name.empty())
504 continue;
505
506 rcd.extension = p.path().filename().extension().string();
507
508 rcd.showName = (rcd.isDir ? "[D] " : "[F] ") + p.path().filename().u8string();
509 fileRecords_.push_back(rcd);
510 }
511
512 std::sort(fileRecords_.begin(), fileRecords_.end(),
513 [](const FileRecord &L, const FileRecord &R)
514 {
515 return (L.isDir ^ R.isDir) ? L.isDir : (L.name < R.name);
516 });
517
518 pwd_ = absolute(pwd);
519 selectedFilename_ = std::string();
520 (*inputNameBuf_)[0] = '\0';
521 }
522
523 #ifdef _WIN32
524
525 inline std::uint32_t ImGui::FileBrowser::GetDrivesBitMask()
526 {
527 char rootName[10];
528 DWORD mask = GetLogicalDrives();
529 uint32_t ret = 0;
530 for(int i = 0; i < 26; ++i)
531 {
532 if(!(mask & (1 << i)))
533 continue;
534 sprintf(rootName, "%c:\\", 'A' + i);
535 UINT type = GetDriveTypeA(rootName);
536 if(type == DRIVE_REMOVABLE || type == DRIVE_FIXED)
537 ret |= (1 << i);
538 }
539 return ret;
540 }
541
542 #endif
ImGuiFileBrowserFlags_NoStatusBar
Definition: ImFileBrowser.hpp:24
ImGui::FileBrowser::FileRecord
Definition: ImFileBrowser.hpp:108
ImGui::FileBrowser::typeFilters_
std::vector< const char * > typeFilters_
Definition: ImFileBrowser.hpp:102
ImGuiFileBrowserFlags_CreateNewDir
Definition: ImFileBrowser.hpp:26
ImGui::FileBrowser::FileRecord::name
std::string name
Definition: ImFileBrowser.hpp:111
ImGui::FileBrowser::SetTitle
void SetTitle(std::string title)
Definition: ImFileBrowser.hpp:183
ImGui::FileBrowser::openLabel_
std::string openLabel_
Definition: ImFileBrowser.hpp:93
ImGui::FileBrowser::statusStr_
std::string statusStr_
Definition: ImFileBrowser.hpp:100
ImGuiFileBrowserFlags_CloseOnEsc
Definition: ImFileBrowser.hpp:25
ImGui::FileBrowser::typeFilterIndex_
int typeFilterIndex_
Definition: ImFileBrowser.hpp:103
ImGui::FileBrowser::SetPwd
bool SetPwd(const std::filesystem::path &pwd=std::filesystem::current_path())
Definition: ImFileBrowser.hpp:449
std
Definition: Vertex.h:74
ImGuiFileBrowserFlags_
ImGuiFileBrowserFlags_
Definition: ImFileBrowser.hpp:18
ImGui::FileBrowser::FileRecord::extension
std::string extension
Definition: ImFileBrowser.hpp:113
ImGuiFileBrowserFlags_SelectDirectory
Definition: ImFileBrowser.hpp:20
ImGui::FileBrowser
Definition: ImFileBrowser.hpp:31
ImGui::FileBrowser::ScopeGuard::~ScopeGuard
~ScopeGuard()
Definition: ImFileBrowser.hpp:81
ImGui::FileBrowser::operator=
FileBrowser & operator=(const FileBrowser &copyFrom)
Definition: ImFileBrowser.hpp:156
ImGui::FileBrowser::title_
std::string title_
Definition: ImFileBrowser.hpp:92
ImGui::FileBrowser::FileRecord::isDir
bool isDir
Definition: ImFileBrowser.hpp:110
ImGui::FileBrowser::ScopeGuard::ScopeGuard
ScopeGuard(T func)
Definition: ImFileBrowser.hpp:80
ImGui::FileBrowser::closeFlag_
bool closeFlag_
Definition: ImFileBrowser.hpp:96
ImGuiFileBrowserFlags_NoTitleBar
Definition: ImFileBrowser.hpp:23
ImGui::FileBrowser::inputNameBuf_
std::unique_ptr< std::array< char, INPUT_NAME_BUF_SIZE > > inputNameBuf_
Definition: ImFileBrowser.hpp:119
ImGuiFileBrowserFlags_NoModal
Definition: ImFileBrowser.hpp:22
ImGui::FileBrowser::SetTypeFilters
void SetTypeFilters(const std::vector< const char *> &typeFilters)
Definition: ImFileBrowser.hpp:481
ImGui::FileBrowser::Display
void Display()
Definition: ImFileBrowser.hpp:214
ImGui::FileBrowser::INPUT_NAME_BUF_SIZE
static constexpr size_t INPUT_NAME_BUF_SIZE
Definition: ImFileBrowser.hpp:118
ImGui::FileBrowser::Close
void Close()
Definition: ImFileBrowser.hpp:201
ImGui::FileBrowser::pwd_
std::filesystem::path pwd_
Definition: ImFileBrowser.hpp:105
ImGui::FileBrowser::ScopeGuard::func_
std::function< void()> func_
Definition: ImFileBrowser.hpp:75
ImGui::FileBrowser::openNewDirLabel_
std::string openNewDirLabel_
Definition: ImFileBrowser.hpp:121
ImGui::FileBrowser::SetPwdUncatched
void SetPwdUncatched(const std::filesystem::path &pwd)
Definition: ImFileBrowser.hpp:487
ImGui::FileBrowser::selectedFilename_
std::string selectedFilename_
Definition: ImFileBrowser.hpp:106
ImGui::FileBrowser::GetSelected
std::filesystem::path GetSelected() const
Definition: ImFileBrowser.hpp:469
ImGui
Definition: ImFileBrowser.hpp:29
ImGui::FileBrowser::flags_
ImGuiFileBrowserFlags flags_
Definition: ImFileBrowser.hpp:90
ImGui::FileBrowser::ScopeGuard
Definition: ImFileBrowser.hpp:73
ImGuiFileBrowserFlags
int ImGuiFileBrowserFlags
Definition: ImFileBrowser.hpp:16
ImGui::FileBrowser::fileRecords_
std::vector< FileRecord > fileRecords_
Definition: ImFileBrowser.hpp:115
ImGui::FileBrowser::HasSelected
bool HasSelected() const noexcept
Definition: ImFileBrowser.hpp:444
ImGui::FileBrowser::Open
void Open()
Definition: ImFileBrowser.hpp:190
ImGuiFileBrowserFlags_EnterNewFilename
Definition: ImFileBrowser.hpp:21
ImGui::FileBrowser::IsOpened
bool IsOpened() const noexcept
Definition: ImFileBrowser.hpp:209
ImGui::FileBrowser::FileRecord::showName
std::string showName
Definition: ImFileBrowser.hpp:112
ImGui::FileBrowser::openFlag_
bool openFlag_
Definition: ImFileBrowser.hpp:95
ImGui::FileBrowser::isOpened_
bool isOpened_
Definition: ImFileBrowser.hpp:97
ImGui::FileBrowser::ok_
bool ok_
Definition: ImFileBrowser.hpp:98
ImGui::FileBrowser::FileBrowser
FileBrowser(ImGuiFileBrowserFlags flags=0)
Definition: ImFileBrowser.hpp:130
ImGui::FileBrowser::newDirNameBuf_
std::unique_ptr< std::array< char, INPUT_NAME_BUF_SIZE > > newDirNameBuf_
Definition: ImFileBrowser.hpp:122
ImGui::FileBrowser::ClearSelected
void ClearSelected()
Definition: ImFileBrowser.hpp:474