Reworked Open/SaveFileDialog to allow specifying dialog flags
assiduous
2 years ago
29 | 29 | #include <memory> |
30 | 30 | #include "../../Basic/interface/BasicFileSystem.hpp" |
31 | 31 | #include "../../Basic/interface/StandardFile.hpp" |
32 | #include "../../../Primitives/interface/FlagEnum.h" | |
32 | 33 | |
33 | 34 | class WindowsFile : public StandardFile |
34 | 35 | { |
36 | 37 | WindowsFile(const FileOpenAttribs& OpenAttribs); |
37 | 38 | }; |
38 | 39 | |
40 | enum FILE_DIALOG_FLAGS : Diligent::Uint32 | |
41 | { | |
42 | FILE_DIALOG_FLAG_NONE = 0x000, | |
43 | ||
44 | /// Prevents the system from adding a link to the selected file in the file system | |
45 | /// directory that contains the user's most recently used documents. | |
46 | FILE_DIALOG_FLAG_DONT_ADD_TO_RECENT = 0x001, | |
47 | ||
48 | /// Only existing files can be opened | |
49 | FILE_DIALOG_FLAG_FILE_MUST_EXIST = 0x002, | |
50 | ||
51 | /// Restores the current directory to its original value if the user changed the | |
52 | /// directory while searching for files. | |
53 | FILE_DIALOG_FLAG_NO_CHANGE_DIR = 0x004, | |
54 | ||
55 | /// Causes the Save As dialog box to show a message box if the selected file already exists. | |
56 | FILE_DIALOG_FLAG_OVERWRITE_PROMPT = 0x008 | |
57 | }; | |
58 | DEFINE_FLAG_ENUM_OPERATORS(FILE_DIALOG_FLAGS); | |
59 | ||
60 | enum FILE_DIALOG_TYPE : Diligent::Uint32 | |
61 | { | |
62 | FILE_DIALOG_TYPE_OPEN, | |
63 | FILE_DIALOG_TYPE_SAVE | |
64 | }; | |
65 | ||
66 | struct FileDialogAttribs | |
67 | { | |
68 | FILE_DIALOG_TYPE Type = FILE_DIALOG_TYPE_OPEN; | |
69 | FILE_DIALOG_FLAGS Flags = FILE_DIALOG_FLAG_NONE; | |
70 | ||
71 | const char* Title = nullptr; | |
72 | const char* Filter = nullptr; | |
73 | ||
74 | FileDialogAttribs() noexcept {} | |
75 | ||
76 | explicit FileDialogAttribs(FILE_DIALOG_TYPE _Type) noexcept : | |
77 | Type{_Type} | |
78 | { | |
79 | switch (Type) | |
80 | { | |
81 | case FILE_DIALOG_TYPE_OPEN: | |
82 | Flags = FILE_DIALOG_FLAG_DONT_ADD_TO_RECENT | FILE_DIALOG_FLAG_FILE_MUST_EXIST | FILE_DIALOG_FLAG_NO_CHANGE_DIR; | |
83 | break; | |
84 | ||
85 | case FILE_DIALOG_TYPE_SAVE: | |
86 | Flags = FILE_DIALOG_FLAG_DONT_ADD_TO_RECENT | FILE_DIALOG_FLAG_OVERWRITE_PROMPT | FILE_DIALOG_FLAG_NO_CHANGE_DIR; | |
87 | break; | |
88 | } | |
89 | } | |
90 | }; | |
39 | 91 | |
40 | 92 | struct WindowsFileSystem : public BasicFileSystem |
41 | 93 | { |
55 | 107 | |
56 | 108 | static std::vector<std::unique_ptr<FindFileData>> Search(const Diligent::Char* SearchPattern); |
57 | 109 | |
58 | static std::string OpenFileDialog(const char* Title, const char* Filter); | |
59 | ||
60 | static std::string SaveFileDialog(const char* Title, const char* Filter); | |
110 | static std::string FileDialog(const FileDialogAttribs& DialogAttribs); | |
61 | 111 | |
62 | 112 | static std::string GetCurrentDirectory(); |
63 | 113 |
277 | 277 | return SearchRes; |
278 | 278 | } |
279 | 279 | |
280 | std::string WindowsFileSystem::OpenFileDialog(const char* Title, const char* Filter) | |
281 | { | |
282 | std::string FileName; | |
283 | char buffer[1024] = {}; | |
284 | OPENFILENAMEA ofn = {}; | |
285 | ofn.lStructSize = sizeof(ofn); | |
286 | ofn.lpstrFilter = Filter; | |
287 | ofn.lpstrFile = buffer; | |
288 | ofn.nMaxFile = _countof(buffer); | |
289 | ofn.lpstrTitle = Title; | |
290 | ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; | |
291 | if (GetOpenFileNameA(&ofn)) | |
280 | static DWORD FileDialogFlagsToOFNFlags(FILE_DIALOG_FLAGS FileDialogFlags) | |
281 | { | |
282 | DWORD OFNFlags = 0; | |
283 | while (FileDialogFlags != FILE_DIALOG_FLAG_NONE) | |
284 | { | |
285 | auto Flag = FileDialogFlags & ~static_cast<FILE_DIALOG_FLAGS>(static_cast<Uint32>(FileDialogFlags) - 1); | |
286 | switch (Flag) | |
287 | { | |
288 | case FILE_DIALOG_FLAG_DONT_ADD_TO_RECENT: | |
289 | OFNFlags |= OFN_DONTADDTORECENT; | |
290 | break; | |
291 | ||
292 | case FILE_DIALOG_FLAG_FILE_MUST_EXIST: | |
293 | OFNFlags |= OFN_FILEMUSTEXIST; | |
294 | break; | |
295 | ||
296 | case FILE_DIALOG_FLAG_NO_CHANGE_DIR: | |
297 | OFNFlags |= OFN_NOCHANGEDIR; | |
298 | break; | |
299 | ||
300 | case FILE_DIALOG_FLAG_OVERWRITE_PROMPT: | |
301 | OFNFlags |= OFN_OVERWRITEPROMPT; | |
302 | break; | |
303 | ||
304 | default: | |
305 | UNEXPECTED("Unknown file dialog flag (", Flag, ")"); | |
306 | } | |
307 | FileDialogFlags &= ~Flag; | |
308 | } | |
309 | return OFNFlags; | |
310 | } | |
311 | ||
312 | std::string WindowsFileSystem::FileDialog(const FileDialogAttribs& DialogAttribs) | |
313 | { | |
314 | OPENFILENAMEA ofn = {}; | |
315 | ||
316 | char buffer[1024] = {}; | |
317 | ofn.lStructSize = sizeof(ofn); | |
318 | ofn.lpstrFilter = DialogAttribs.Filter; | |
319 | ofn.lpstrFile = buffer; | |
320 | ofn.nMaxFile = _countof(buffer); | |
321 | ofn.lpstrTitle = DialogAttribs.Title; | |
322 | ofn.Flags = FileDialogFlagsToOFNFlags(DialogAttribs.Flags); | |
323 | ||
324 | std::string FileName; | |
325 | if (DialogAttribs.Type == FILE_DIALOG_TYPE_OPEN ? GetOpenFileNameA(&ofn) : GetSaveFileNameA(&ofn)) | |
292 | 326 | { |
293 | 327 | FileName = buffer; |
294 | 328 | } |
295 | 329 | return FileName; |
296 | 330 | } |
297 | ||
298 | std::string WindowsFileSystem::SaveFileDialog(const char* Title, const char* Filter) | |
299 | { | |
300 | std::string FileName; | |
301 | char buffer[1024] = {}; | |
302 | OPENFILENAMEA ofn = {}; | |
303 | ofn.lStructSize = sizeof(ofn); | |
304 | ofn.lpstrFilter = Filter; | |
305 | ofn.lpstrFile = buffer; | |
306 | ofn.nMaxFile = _countof(buffer); | |
307 | ofn.lpstrTitle = Title; | |
308 | ofn.Flags = OFN_DONTADDTORECENT | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; | |
309 | if (GetSaveFileNameA(&ofn)) | |
310 | { | |
311 | FileName = buffer; | |
312 | } | |
313 | return FileName; | |
314 | } | |
315 | ||
316 | 331 | |
317 | 332 | bool WindowsFileSystem::IsDirectory(const Diligent::Char* strPath) |
318 | 333 | { |