1// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2
3#include "smnativefiledialog.hh"
4#include "smwindow.hh"
5
6#import <Cocoa/Cocoa.h>
7
8using std::string;
9
10namespace SpectMorph
11{
12
13class MacFileDialog : public NativeFileDialog
14{
15  enum class State {
16    null,
17    ok,
18    fail
19  } state = State::null;
20
21  string selected_filename;
22public:
23  MacFileDialog (PuglNativeWindow win_id, bool open, const string& title, const FileDialogFormats& formats)
24  {
25    NSString* titleString = [[NSString alloc]
26                             initWithBytes:title.c_str()
27                             length:title.size()
28                             encoding:NSUTF8StringEncoding];
29
30    NSMutableArray *file_types_array = [NSMutableArray new];
31
32    // NSOpenPanel doesn't support multiple filters
33    //  -> we use only the extensions of the first format
34    //  -> to make this usable on macOS, the first format should contain all supported file extensions
35    for (auto extension : formats.formats[0].exts)
36      {
37        [file_types_array addObject:[NSString stringWithUTF8String:extension.c_str()]];
38      }
39
40    if (open)
41      {
42        NSOpenPanel *panel = [NSOpenPanel openPanel];
43
44        [panel setCanChooseFiles:YES];
45        [panel setCanChooseDirectories:NO];
46        [panel setAllowsMultipleSelection:NO];
47        [panel setTitle:titleString];
48        [panel setAllowedFileTypes:file_types_array];
49
50        [panel beginWithCompletionHandler:^(NSInteger result) {
51          state = State::fail;
52
53          if (result == NSModalResponseOK)
54            {
55              for (NSURL *url in [panel URLs])
56                {
57                  if (![url isFileURL]) continue;
58
59                  state = State::ok;
60                  selected_filename = [url.path UTF8String];
61                  break;
62                }
63            }
64        }];
65      }
66    else
67      {
68        NSSavePanel *panel = [NSSavePanel savePanel];
69
70        [panel setTitle:titleString];
71        [panel setAllowedFileTypes:file_types_array];
72
73        [panel beginWithCompletionHandler:^(NSInteger result) {
74          state = State::fail;
75
76          if (result == NSModalResponseOK)
77            {
78              NSURL* url = [panel URL];
79              if ([url isFileURL])
80                {
81                  state = State::ok;
82                  selected_filename = [url.path UTF8String];
83                }
84            }
85        }];
86      }
87  }
88  void
89  process_events() override
90  {
91    if (state == State::ok)
92      {
93        signal_file_selected (selected_filename);
94        state = State::null;
95      }
96    else if (state == State::fail)
97      {
98        signal_file_selected ("");
99        state = State::null;
100      }
101  }
102};
103
104NativeFileDialog *
105NativeFileDialog::create (Window *window, bool open, const string& title, const FileDialogFormats& formats)
106{
107  return new MacFileDialog (window->native_window(), open, title, formats);
108}
109
110}
111
112