yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
file_dialog.mm
Go to the documentation of this file.
1#include "util/file_util.h"
2
3#include <iostream>
4#include <string>
5#include <vector>
6
7#include "app/core/features.h"
8
9#if defined(YAZE_ENABLE_NFD) && YAZE_ENABLE_NFD
10#include <nfd.h>
11#endif
12
13#if defined(__APPLE__) && defined(__MACH__)
14/* Apple OSX and iOS (Darwin). */
15#include <Foundation/Foundation.h>
16#include <TargetConditionals.h>
17
18#import <CoreText/CoreText.h>
19
20#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1
21/* iOS in Xcode simulator */
22#import <UIKit/UIKit.h>
23#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
24
26
27namespace {
28static std::string selectedFile;
29
30void ShowOpenFileDialogImpl(void (^completionHandler)(std::string)) {
31 AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
32 [appDelegate PresentDocumentPickerWithCompletionHandler:^(NSString *filePath) {
33 selectedFile = std::string([filePath UTF8String]);
34 completionHandler(selectedFile);
35 }];
36}
37
38std::string ShowOpenFileDialogSync() {
39 __block std::string result;
40
41 ShowOpenFileDialogImpl(^(std::string filePath) {
42 result = filePath;
43 });
44
45 return result;
46}
47} // namespace
48
49std::string yaze::util::FileDialogWrapper::ShowOpenFileDialog() { return ShowOpenFileDialogSync(); }
50
52
54 const std::string &folder) {
55 return {};
56}
57
59 const std::string &folder) {
60 return {};
61}
62
64 NSBundle* bundle = [NSBundle mainBundle];
65 NSString* resourceDirectoryPath = [bundle bundlePath];
66 NSString* path = [resourceDirectoryPath stringByAppendingString:@"/"];
67 return [path UTF8String];
68}
69
70#elif TARGET_OS_MAC == 1
71/* macOS */
72
73#import <Cocoa/Cocoa.h>
74#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
75
77 NSOpenPanel* openPanel = [NSOpenPanel openPanel];
78 [openPanel setCanChooseFiles:YES];
79 [openPanel setCanChooseDirectories:NO];
80 [openPanel setAllowsMultipleSelection:NO];
81
82 if ([openPanel runModal] == NSModalResponseOK) {
83 NSURL* url = [[openPanel URLs] objectAtIndex:0];
84 NSString* path = [url path];
85 return std::string([path UTF8String]);
86 }
87
88 return "";
89}
90
91std::string yaze::util::FileDialogWrapper::ShowSaveFileDialogBespoke(const std::string& default_name,
92 const std::string& default_extension) {
93 NSSavePanel* savePanel = [NSSavePanel savePanel];
94
95 if (!default_name.empty()) {
96 [savePanel setNameFieldStringValue:[NSString stringWithUTF8String:default_name.c_str()]];
97 }
98
99 if (!default_extension.empty()) {
100 NSString* ext = [NSString stringWithUTF8String:default_extension.c_str()];
101 [savePanel setAllowedFileTypes:@[ext]];
102 }
103
104 if ([savePanel runModal] == NSModalResponseOK) {
105 NSURL* url = [savePanel URL];
106 NSString* path = [url path];
107 return std::string([path UTF8String]);
108 }
109
110 return "";
111}
112
113// Global feature flag-based dispatch methods
115 if (core::FeatureFlags::get().kUseNativeFileDialog) {
116 return ShowOpenFileDialogNFD();
117 } else {
118 return ShowOpenFileDialogBespoke();
119 }
120}
121
123 if (core::FeatureFlags::get().kUseNativeFileDialog) {
124 return ShowOpenFolderDialogNFD();
125 } else {
126 return ShowOpenFolderDialogBespoke();
127 }
128}
129
130std::string yaze::util::FileDialogWrapper::ShowSaveFileDialog(const std::string& default_name,
131 const std::string& default_extension) {
132 if (core::FeatureFlags::get().kUseNativeFileDialog) {
133 return ShowSaveFileDialogNFD(default_name, default_extension);
134 } else {
135 return ShowSaveFileDialogBespoke(default_name, default_extension);
136 }
137}
138
139// NFD implementation for macOS (fallback to bespoke if NFD not available)
141#if defined(YAZE_ENABLE_NFD) && YAZE_ENABLE_NFD
142 NFD_Init();
143 nfdu8char_t *out_path = NULL;
144 nfdu8filteritem_t filters[1] = {{"Rom File", "sfc,smc"}};
145 nfdopendialogu8args_t args = {0};
146 args.filterList = filters;
147 args.filterCount = 1;
148
149 nfdresult_t result = NFD_OpenDialogU8_With(&out_path, &args);
150 if (result == NFD_OKAY) {
151 std::string file_path(out_path);
152 NFD_FreePath(out_path);
153 NFD_Quit();
154 return file_path;
155 } else if (result == NFD_CANCEL) {
156 NFD_Quit();
157 return "";
158 }
159 NFD_Quit();
160 return "";
161#else
162 // NFD not compiled in, use bespoke
163 return ShowOpenFileDialogBespoke();
164#endif
165}
166
168#if defined(YAZE_ENABLE_NFD) && YAZE_ENABLE_NFD
169 NFD_Init();
170 nfdu8char_t *out_path = NULL;
171 nfdresult_t result = NFD_PickFolderU8(&out_path, NULL);
172
173 if (result == NFD_OKAY) {
174 std::string folder_path(out_path);
175 NFD_FreePath(out_path);
176 NFD_Quit();
177 return folder_path;
178 } else if (result == NFD_CANCEL) {
179 NFD_Quit();
180 return "";
181 }
182 NFD_Quit();
183 return "";
184#else
185 // NFD not compiled in, use bespoke
186 return ShowOpenFolderDialogBespoke();
187#endif
188}
189
190std::string yaze::util::FileDialogWrapper::ShowSaveFileDialogNFD(const std::string& default_name,
191 const std::string& default_extension) {
192#if defined(YAZE_ENABLE_NFD) && YAZE_ENABLE_NFD
193 NFD_Init();
194 nfdu8char_t *out_path = NULL;
195
196 nfdsavedialogu8args_t args = {0};
197 if (!default_extension.empty()) {
198 // Create filter for the save dialog
199 static nfdu8filteritem_t filters[3] = {
200 {"Theme File", "theme"},
201 {"Project File", "yaze"},
202 {"ROM File", "sfc,smc"}
203 };
204
205 if (default_extension == "theme") {
206 args.filterList = &filters[0];
207 args.filterCount = 1;
208 } else if (default_extension == "yaze") {
209 args.filterList = &filters[1];
210 args.filterCount = 1;
211 } else if (default_extension == "sfc" || default_extension == "smc") {
212 args.filterList = &filters[2];
213 args.filterCount = 1;
214 }
215 }
216
217 if (!default_name.empty()) {
218 args.defaultName = default_name.c_str();
219 }
220
221 nfdresult_t result = NFD_SaveDialogU8_With(&out_path, &args);
222 if (result == NFD_OKAY) {
223 std::string file_path(out_path);
224 NFD_FreePath(out_path);
225 NFD_Quit();
226 return file_path;
227 } else if (result == NFD_CANCEL) {
228 NFD_Quit();
229 return "";
230 }
231 NFD_Quit();
232 return "";
233#else
234 // NFD not compiled in, use bespoke
235 return ShowSaveFileDialogBespoke(default_name, default_extension);
236#endif
237}
238
240 NSOpenPanel* openPanel = [NSOpenPanel openPanel];
241 [openPanel setCanChooseFiles:NO];
242 [openPanel setCanChooseDirectories:YES];
243 [openPanel setAllowsMultipleSelection:NO];
244
245 if ([openPanel runModal] == NSModalResponseOK) {
246 NSURL* url = [[openPanel URLs] objectAtIndex:0];
247 NSString* path = [url path];
248 return std::string([path UTF8String]);
249 }
250
251 return "";
252}
253
255 const std::string& folder) {
256 std::vector<std::string> filenames;
257 NSFileManager* fileManager = [NSFileManager defaultManager];
258 NSDirectoryEnumerator* enumerator =
259 [fileManager enumeratorAtPath:[NSString stringWithUTF8String:folder.c_str()]];
260 NSString* file;
261 while (file = [enumerator nextObject]) {
262 if ([file hasPrefix:@"."]) {
263 continue;
264 }
265 filenames.push_back(std::string([file UTF8String]));
266 }
267 return filenames;
268}
269
271 const std::string& folder) {
272 std::vector<std::string> subdirectories;
273 NSFileManager* fileManager = [NSFileManager defaultManager];
274 NSDirectoryEnumerator* enumerator =
275 [fileManager enumeratorAtPath:[NSString stringWithUTF8String:folder.c_str()]];
276 NSString* file;
277 while (file = [enumerator nextObject]) {
278 if ([file hasPrefix:@"."]) {
279 continue;
280 }
281 BOOL isDirectory;
282 NSString* path =
283 [NSString stringWithFormat:@"%@/%@", [NSString stringWithUTF8String:folder.c_str()], file];
284 [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
285 if (isDirectory) {
286 subdirectories.push_back(std::string([file UTF8String]));
287 }
288 }
289 return subdirectories;
290}
291
293 NSBundle* bundle = [NSBundle mainBundle];
294 NSString* resourceDirectoryPath = [bundle bundlePath];
295 NSString* path = [resourceDirectoryPath stringByAppendingString:@"/"];
296 return [path UTF8String];
297}
298
299#else
300// Unsupported platform
301#endif // TARGET_OS_MAC
302
303#endif // __APPLE__ && __MACH__
static Flags & get()
Definition features.h:79
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::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::string GetBundleResourcePath()
GetBundleResourcePath returns the path to the bundle resource directory. Specific to MacOS.