11#include " MRFileDialog.h"
2+ #include " MRFileDialogInternal.h"
3+
24#include " MRViewerFwd.h"
35#include " MRColorTheme.h"
46#include " MRCommandLoop.h"
1517#include < clocale>
1618
1719#ifndef _WIN32
18- #ifndef MRVIEWER_NO_GTK
20+ #if defined( __APPLE__ )
21+ #include " MRFileDialogCocoa.h"
22+ #elif !defined( MRVIEWER_NO_GTK )
1923 #include < gtk/gtk.h>
2024 #endif
2125#else
@@ -93,15 +97,8 @@ EMSCRIPTEN_KEEPALIVE void emsFreeFSCallback()
9397namespace
9498{
9599
96- struct FileDialogParameters : MR::FileParameters
97- {
98- bool folderDialog{false }; // open dialog only
99- bool multiselect{true }; // open dialog only
100- bool saveDialog{false }; // true for save dialog, false for open
101- };
102-
103100#if defined( _WIN32 )
104- std::vector<std::filesystem::path> windowsDialog ( const FileDialogParameters& params = {} )
101+ std::vector<std::filesystem::path> windowsDialog ( const MR::detail:: FileDialogParameters& params = {} )
105102{
106103 std::vector<std::filesystem::path> res;
107104 // <SnippetRefCounts>
@@ -236,25 +233,7 @@ std::vector<std::filesystem::path> windowsDialog( const FileDialogParameters& pa
236233}
237234#else
238235#ifndef MRVIEWER_NO_GTK
239- const std::string cLastUsedDirKey = " lastUsedDir" ;
240-
241- std::string getCurrentFolder ( const FileDialogParameters& params )
242- {
243- if ( !params.baseFolder .empty () )
244- return MR::utf8string ( params.baseFolder );
245-
246- auto & cfg = MR::Config::instance ();
247- if ( cfg.hasJsonValue ( cLastUsedDirKey ) )
248- {
249- auto lastUsedDir = cfg.getJsonValue ( cLastUsedDirKey );
250- if ( lastUsedDir.isString () )
251- return lastUsedDir.asString ();
252- }
253-
254- return MR::utf8string ( MR::GetHomeDirectory () );
255- }
256-
257- std::tuple<GtkFileChooserAction, std::string> gtkDialogParameters ( const FileDialogParameters& params )
236+ std::tuple<GtkFileChooserAction, std::string> gtkDialogParameters ( const MR::detail::FileDialogParameters& params )
258237{
259238 if ( params.folderDialog )
260239 return { GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, params.multiselect ? " Open Folders" : " Open Folder" };
@@ -264,7 +243,7 @@ std::tuple<GtkFileChooserAction, std::string> gtkDialogParameters( const FileDia
264243 return { GTK_FILE_CHOOSER_ACTION_OPEN, params.multiselect ? " Open Files" : " Open File" };
265244}
266245
267- std::vector<std::filesystem::path> gtkDialog ( const FileDialogParameters& params = {} )
246+ std::vector<std::filesystem::path> gtkDialog ( const MR::detail:: FileDialogParameters& params = {} )
268247{
269248 // Gtk has a nasty habit of overriding the locale to "".s
270249 std::optional<std::string> localeStr;
@@ -286,20 +265,13 @@ std::vector<std::filesystem::path> gtkDialog( const FileDialogParameters& params
286265 };
287266
288267 auto [action, title] = gtkDialogParameters ( params );
289- #if defined( __APPLE__ )
290- auto * dialog = gtk_file_chooser_native_new ( title.c_str (), NULL , action, params.saveDialog ? " _Save" : " _Open" , " _Cancel" );
291- MR_FINALLY {
292- gtk_native_dialog_destroy ( GTK_NATIVE_DIALOG ( dialog ) );
293- };
294- #else
295268 auto * dialog = gtk_file_chooser_dialog_new ( title.c_str (), NULL , action, NULL , NULL );
296269 MR_FINALLY {
297270 gtk_widget_destroy ( dialog );
298271 };
299272
300273 gtk_dialog_add_button ( GTK_DIALOG ( dialog ), params.saveDialog ? " _Save" : " _Open" , GTK_RESPONSE_ACCEPT );
301274 gtk_dialog_add_button ( GTK_DIALOG ( dialog ), " _Cancel" , GTK_RESPONSE_CANCEL );
302- #endif
303275
304276 auto * chooser = GTK_FILE_CHOOSER ( dialog );
305277
@@ -315,11 +287,9 @@ std::vector<std::filesystem::path> gtkDialog( const FileDialogParameters& params
315287 {
316288 auto nextSeparatorPos = filter.extensions .find ( " ;" , separatorPos );
317289 auto ext = filter.extensions .substr ( separatorPos, nextSeparatorPos - separatorPos );
318- #if defined( __APPLE__ )
319- if ( ext == " *.*" )
320- ext = " *" ;
321- #endif
290+
322291 gtk_file_filter_add_pattern ( fileFilter, ext.c_str () );
292+
323293 if ( nextSeparatorPos == std::string::npos )
324294 break ;
325295 separatorPos = nextSeparatorPos + 1 ;
@@ -328,7 +298,7 @@ std::vector<std::filesystem::path> gtkDialog( const FileDialogParameters& params
328298 gtk_file_chooser_add_filter ( chooser, fileFilter ); // the chooser takes ownership of the filter
329299 }
330300
331- const auto currentFolder = getCurrentFolder ( params );
301+ const auto currentFolder = MR::detail:: getCurrentFolder ( params. baseFolder );
332302 gtk_file_chooser_set_current_folder ( chooser, currentFolder.c_str () );
333303
334304 if ( !params.fileName .empty () )
@@ -367,28 +337,15 @@ std::vector<std::filesystem::path> gtkDialog( const FileDialogParameters& params
367337 results.emplace_back ( std::move ( filepath ) );
368338 }
369339
370- auto & cfg = MR::Config::instance ();
371- cfg.setJsonValue ( cLastUsedDirKey, gtk_file_chooser_get_current_folder ( chooser ) );
340+ MR::detail::setCurrentFolder ( gtk_file_chooser_get_current_folder ( chooser ) );
372341 }
373342 else if ( responseId != GTK_RESPONSE_CANCEL )
374343 {
375344 spdlog::warn ( " GTK dialog failed" );
376345 }
377- #if defined( __APPLE__ )
378- // on macOS the main window remains unfocused after the file dialog is closed
379- MR::CommandLoop::appendCommand ( []
380- {
381- glfwFocusWindow ( MR::Viewer::instance ()->window );
382- } );
383- #endif
384346 };
385- #if defined( __APPLE__ )
386- onResponse ( gtk_native_dialog_run ( GTK_NATIVE_DIALOG ( dialog ) ) );
387- gtk_native_dialog_hide ( GTK_NATIVE_DIALOG ( dialog ) );
388- #else // __APPLE__
389347 onResponse ( gtk_dialog_run ( GTK_DIALOG ( dialog ) ) );
390348 gtk_widget_hide ( dialog );
391- #endif // __APPLE__
392349
393350 return results;
394351}
@@ -422,7 +379,7 @@ namespace MR
422379
423380std::filesystem::path openFileDialog ( const FileParameters& params )
424381{
425- FileDialogParameters parameters{ params };
382+ detail:: FileDialogParameters parameters{ params };
426383 parameters.folderDialog = false ;
427384 parameters.multiselect = false ;
428385 parameters.saveDialog = false ;
@@ -432,6 +389,8 @@ std::filesystem::path openFileDialog( const FileParameters& params )
432389 std::vector<std::filesystem::path> results;
433390#if defined( _WIN32 )
434391 results = windowsDialog ( parameters );
392+ #elif defined( __APPLE__ )
393+ results = detail::runCocoaFileDialog ( parameters );
435394#elif !defined( MRVIEWER_NO_GTK )
436395 results = gtkDialog ( parameters );
437396#endif
@@ -469,7 +428,7 @@ void openFileDialogAsync( std::function<void( const std::filesystem::path& )> ca
469428
470429std::vector<std::filesystem::path> openFilesDialog ( const FileParameters& params )
471430{
472- FileDialogParameters parameters{ params };
431+ detail:: FileDialogParameters parameters{ params };
473432 parameters.folderDialog = false ;
474433 parameters.multiselect = true ;
475434 parameters.saveDialog = false ;
@@ -479,6 +438,8 @@ std::vector<std::filesystem::path> openFilesDialog( const FileParameters& params
479438 std::vector<std::filesystem::path> results;
480439#if defined( _WIN32 )
481440 results = windowsDialog ( parameters );
441+ #elif defined( __APPLE__ )
442+ results = detail::runCocoaFileDialog ( parameters );
482443#elif !defined( MRVIEWER_NO_GTK )
483444 results = gtkDialog ( parameters );
484445#endif
@@ -512,7 +473,7 @@ std::filesystem::path openFolderDialog( std::filesystem::path baseFolder )
512473 // Windows dialog does not support forward slashes between folders
513474 baseFolder.make_preferred ();
514475
515- FileDialogParameters parameters;
476+ detail:: FileDialogParameters parameters;
516477 parameters.baseFolder = baseFolder;
517478 parameters.folderDialog = true ;
518479 parameters.multiselect = false ;
@@ -521,6 +482,8 @@ std::filesystem::path openFolderDialog( std::filesystem::path baseFolder )
521482 std::vector<std::filesystem::path> results;
522483#if defined( _WIN32 )
523484 results = windowsDialog ( parameters );
485+ #elif defined( __APPLE__ )
486+ results = detail::runCocoaFileDialog ( parameters );
524487#elif !defined( MRVIEWER_NO_GTK )
525488 results = gtkDialog ( parameters );
526489#endif
@@ -561,7 +524,7 @@ std::vector<std::filesystem::path> openFoldersDialog( std::filesystem::path base
561524 // Windows dialog does not support forward slashes between folders
562525 baseFolder.make_preferred ();
563526
564- FileDialogParameters parameters;
527+ detail:: FileDialogParameters parameters;
565528 parameters.baseFolder = baseFolder;
566529 parameters.folderDialog = true ;
567530 parameters.multiselect = true ;
@@ -570,6 +533,8 @@ std::vector<std::filesystem::path> openFoldersDialog( std::filesystem::path base
570533 std::vector<std::filesystem::path> results;
571534#if defined( _WIN32 )
572535 results = windowsDialog ( parameters );
536+ #elif defined( __APPLE__ )
537+ results = detail::runCocoaFileDialog ( parameters );
573538#elif !defined( MRVIEWER_NO_GTK )
574539 results = gtkDialog ( parameters );
575540#endif
@@ -580,7 +545,7 @@ std::vector<std::filesystem::path> openFoldersDialog( std::filesystem::path base
580545
581546std::filesystem::path saveFileDialog ( const FileParameters& params /* = {} */ )
582547{
583- FileDialogParameters parameters{ params };
548+ detail:: FileDialogParameters parameters{ params };
584549 parameters.folderDialog = false ;
585550 parameters.multiselect = false ;
586551 parameters.saveDialog = true ;
@@ -590,6 +555,8 @@ std::filesystem::path saveFileDialog( const FileParameters& params /*= {} */ )
590555 std::vector<std::filesystem::path> results;
591556#if defined( _WIN32 )
592557 results = windowsDialog ( parameters );
558+ #elif defined( __APPLE__ )
559+ results = detail::runCocoaFileDialog ( parameters );
593560#elif !defined( MRVIEWER_NO_GTK )
594561 results = gtkDialog ( parameters );
595562#endif
0 commit comments