yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
file_dialog_nfd.cc
Go to the documentation of this file.
1// Windows and Linux implementation of FileDialogWrapper using
2// nativefiledialog-extended
3#include <nfd.h>
4
5#include <filesystem>
6#include <string>
7#include <vector>
8
9#include "util/file_util.h"
10
11namespace yaze {
12namespace util {
13
15 const FileDialogOptions& options) {
16 // NFD requires init before use; on Linux this is where the GTK backend runs
17 // gtk_init_check(). Skipping it crashes ("Can't create a GtkStyleContext
18 // without a display connection"). Mirrors the macOS impl in file_dialog.mm.
19 if (NFD_Init() != NFD_OKAY) {
20 return "";
21 }
22 nfdchar_t* outPath = nullptr;
23 const nfdfilteritem_t* filter_list = nullptr;
24 size_t filter_count = 0;
25 std::vector<nfdfilteritem_t> filter_items;
26 std::vector<std::string> filter_names;
27 std::vector<std::string> filter_specs;
28
29 if (!options.filters.empty()) {
30 filter_items.reserve(options.filters.size());
31 filter_names.reserve(options.filters.size());
32 filter_specs.reserve(options.filters.size());
33
34 for (const auto& filter : options.filters) {
35 std::string label = filter.label.empty() ? "Files" : filter.label;
36 std::string spec = filter.spec.empty() ? "*" : filter.spec;
37 filter_names.push_back(label);
38 filter_specs.push_back(spec);
39 filter_items.push_back(
40 {filter_names.back().c_str(), filter_specs.back().c_str()});
41 }
42
43 filter_list = filter_items.data();
44 filter_count = filter_items.size();
45 }
46
47 nfdresult_t result =
48 NFD_OpenDialog(&outPath, filter_list, filter_count, nullptr);
49
50 if (result == NFD_OKAY) {
51 std::string path(outPath);
52 NFD_FreePath(outPath);
53 NFD_Quit();
54 return path;
55 }
56
57 NFD_Quit();
58 return "";
59}
60
64
66 const FileDialogOptions& options,
67 std::function<void(const std::string&)> callback) {
68 if (!callback) {
69 return;
70 }
71 callback(ShowOpenFileDialog(options));
72}
73
75 if (NFD_Init() != NFD_OKAY) {
76 return "";
77 }
78 nfdchar_t* outPath = nullptr;
79 nfdresult_t result = NFD_PickFolder(&outPath, nullptr);
80
81 if (result == NFD_OKAY) {
82 std::string path(outPath);
83 NFD_FreePath(outPath);
84 NFD_Quit();
85 return path;
86 }
87
88 NFD_Quit();
89 return "";
90}
91
93 const std::string& default_name, const std::string& default_extension) {
94 if (auto result = ConsumeSaveFileDialogResultForTesting()) {
95 return *result;
96 }
97 if (NFD_Init() != NFD_OKAY) {
98 return "";
99 }
100 nfdchar_t* outPath = nullptr;
101 nfdfilteritem_t filterItem[1] = {
102 {default_extension.empty() ? "All Files" : default_extension.c_str(),
103 default_extension.empty() ? "*" : default_extension.c_str()}};
104
105 nfdresult_t result = NFD_SaveDialog(
106 &outPath, default_extension.empty() ? nullptr : filterItem,
107 default_extension.empty() ? 0 : 1, nullptr, default_name.c_str());
108
109 if (result == NFD_OKAY) {
110 std::string path(outPath);
111 NFD_FreePath(outPath);
112 NFD_Quit();
113 return path;
114 }
115
116 NFD_Quit();
117 return "";
118}
119
121 const std::string& folder_path) {
122 std::vector<std::string> subdirs;
123
124 try {
125 for (const auto& entry : std::filesystem::directory_iterator(folder_path)) {
126 if (entry.is_directory()) {
127 subdirs.push_back(entry.path().string());
128 }
129 }
130 } catch (...) {
131 // Return empty vector on error
132 }
133
134 return subdirs;
135}
136
137std::vector<std::string> FileDialogWrapper::GetFilesInFolder(
138 const std::string& folder_path) {
139 std::vector<std::string> files;
140
141 try {
142 for (const auto& entry : std::filesystem::directory_iterator(folder_path)) {
143 if (entry.is_regular_file()) {
144 files.push_back(entry.path().string());
145 }
146 }
147 } catch (...) {
148 // Return empty vector on error
149 }
150
151 return files;
152}
153
154// Delegate to main implementations
158
162
164 const std::string& default_name, const std::string& default_extension) {
165 return ShowSaveFileDialog(default_name, default_extension);
166}
167
169 const std::string& default_name, const std::string& default_extension) {
170 return ShowSaveFileDialog(default_name, default_extension);
171}
172
176
180
181} // namespace util
182} // namespace yaze
static void ShowOpenFileDialogAsync(const FileDialogOptions &options, std::function< void(const std::string &)> callback)
static std::string ShowSaveFileDialogBespoke(const std::string &default_name="", const std::string &default_extension="")
static std::string ShowOpenFileDialogBespoke()
static std::string ShowSaveFileDialogNFD(const std::string &default_name="", const std::string &default_extension="")
static std::string ShowOpenFolderDialogNFD()
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::optional< std::string > ConsumeSaveFileDialogResultForTesting()
Definition file_util.cc:44
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
static std::string ShowOpenFolderDialog()
ShowOpenFolderDialog opens a file dialog and returns the selected folder path. Uses global feature fl...
static std::vector< std::string > GetFilesInFolder(const std::string &folder_path)
static std::vector< std::string > GetSubdirectoriesInFolder(const std::string &folder_path)
static std::string ShowOpenFolderDialogBespoke()
static std::string ShowOpenFileDialogNFD()
std::vector< FileDialogFilter > filters
Definition file_util.h:18