Prechádzať zdrojové kódy

Updates Native File Dialogs lib to enable browsing and selecting of folders, instead of just files.

Areloch 7 rokov pred
rodič
commit
f657f774ce

+ 4 - 1
Engine/lib/nativeFileDialogs/SConstruct

@@ -3,7 +3,8 @@
 #
 # Scons build script -- GCC, Clang, Visual Studio
 # Does not build test
-
+#
+# SCons builds are deprecated -- see README.md for details.
 
 import os
         
@@ -97,3 +98,5 @@ set_warnings(nfd_env)
 
 nfd_env.Append( CPPPATH=['.','./include'] )
 nfd_env.StaticLibrary( get_lib_name('nfd', debug), nfd_files )
+
+print "*** Scons builds are deprecated!  See README.md for details."

+ 1 - 1
Engine/lib/nativeFileDialogs/common.h

@@ -11,7 +11,7 @@
 #define _NFD_COMMON_H
 
 #define NFD_MAX_STRLEN 256
-#define _NFD_UNUSED(x) ((void)x)
+#define _NFD_UNUSED(x) ((void)x) 
 
 void *NFDi_Malloc( size_t bytes );
 void  NFDi_Free( void *ptr );

+ 5 - 0
Engine/lib/nativeFileDialogs/include/nfd.h

@@ -50,6 +50,11 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
                             const nfdchar_t *defaultPath,
                             nfdchar_t **outPath );
 
+
+/* select folder dialog */
+nfdresult_t NFD_PickFolder( const nfdchar_t *defaultPath,
+                            nfdchar_t **outPath);
+
 /* nfd_common.c */
 
 /* get last error -- set when nfdresult_t returns NFD_ERROR */

+ 42 - 1
Engine/lib/nativeFileDialogs/nfd_cocoa.m

@@ -122,7 +122,8 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
                             nfdchar_t **outPath )
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    
+
+    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];    
     NSOpenPanel *dialog = [NSOpenPanel openPanel];
     [dialog setAllowsMultipleSelection:NO];
 
@@ -152,6 +153,7 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
     }
     [pool release];
 
+    [keyWindow makeKeyAndOrderFront:nil];
     return nfdResult;
 }
 
@@ -233,3 +235,42 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
 
     return nfdResult;
 }
+
+nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
+    nfdchar_t **outPath)
+{
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];    
+    NSOpenPanel *dialog = [NSOpenPanel openPanel];
+    [dialog setAllowsMultipleSelection:NO];
+    [dialog setCanChooseDirectories:YES];
+    [dialog setCanCreateDirectories:YES];
+    [dialog setCanChooseFiles:NO];
+
+    // Set the starting directory
+    SetDefaultPath(dialog, defaultPath);
+
+    nfdresult_t nfdResult = NFD_CANCEL;
+    if ( [dialog runModal] == NSModalResponseOK )
+    {
+        NSURL *url = [dialog URL];
+        const char *utf8Path = [[url path] UTF8String];
+
+        // byte count, not char count
+        size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
+
+        *outPath = NFDi_Malloc( len+1 );
+        if ( !*outPath )
+        {
+            [pool release];
+            return NFD_ERROR;
+        }
+        memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
+        nfdResult = NFD_OKAY;
+    }
+    [pool release];
+
+    [keyWindow makeKeyAndOrderFront:nil];
+    return nfdResult;
+}

+ 56 - 7
Engine/lib/nativeFileDialogs/nfd_gtk.c

@@ -47,14 +47,10 @@ static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList )
         if ( NFDi_IsFilterSegmentChar(*p_filterList) )
         {
             char typebufWildcard[NFD_MAX_STRLEN];
-            
             /* add another type to the filter */
-            if (strlen(typebuf) <= 0 || strlen(typebuf) > NFD_MAX_STRLEN-1) 
-            {
-              p_filterList++;
-              continue;
-            }
-
+            assert( strlen(typebuf) > 0 );
+            assert( strlen(typebuf) < NFD_MAX_STRLEN-1 );
+            
             snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf );
             AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN );
             
@@ -297,6 +293,59 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
     /* Build the filter list */    
     AddFiltersToDialog(dialog, filterList);
 
+    /* Set the default path */
+    SetDefaultPath(dialog, defaultPath);
+    
+    result = NFD_CANCEL;    
+    if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
+    {
+        char *filename;
+        filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) );
+        
+        {
+            size_t len = strlen(filename);
+            *outPath = NFDi_Malloc( len + 1 );
+            memcpy( *outPath, filename, len + 1 );
+            if ( !*outPath )
+            {
+                g_free( filename );
+                gtk_widget_destroy(dialog);
+                return NFD_ERROR;
+            }
+        }
+        g_free(filename);
+
+        result = NFD_OKAY;
+    }
+
+    WaitForCleanup();
+    gtk_widget_destroy(dialog);
+    WaitForCleanup();
+    
+    return result;
+}
+
+nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
+    nfdchar_t **outPath)
+{
+    GtkWidget *dialog;
+    nfdresult_t result;
+
+    if (!gtk_init_check(NULL, NULL))
+    {
+        NFDi_SetError(INIT_FAIL_MSG);
+        return NFD_ERROR;
+    }
+
+    dialog = gtk_file_chooser_dialog_new( "Select folder",
+                                          NULL,
+                                          GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                                          "_Cancel", GTK_RESPONSE_CANCEL,
+                                          "_Select", GTK_RESPONSE_ACCEPT,
+                                          NULL ); 
+    gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE );
+
+
     /* Set the default path */
     SetDefaultPath(dialog, defaultPath);
     

+ 138 - 3
Engine/lib/nativeFileDialogs/nfd_win.cpp

@@ -9,13 +9,17 @@
 #define UNICODE
 #endif
 
+#ifdef __MINGW32__
+// Explicitly setting NTDDI version, this is necessary for the MinGW compiler
+#define NTDDI_VERSION NTDDI_VISTA
+#define _WIN32_WINNT _WIN32_WINNT_VISTA
+#endif
 
 #include <wchar.h>
 #include <stdio.h>
 #include <assert.h>
 #include <windows.h>
 #include <ShObjIdl.h>
-
 #include "nfd_common.h"
 
 
@@ -359,14 +363,15 @@ nfdresult_t NFD_OpenDialog( const char *filterList,
     HRESULT result = ::CoInitializeEx(NULL,
                                       ::COINIT_APARTMENTTHREADED |
                                       ::COINIT_DISABLE_OLE1DDE );
+
+    ::IFileOpenDialog *fileOpenDialog(NULL);
+
     if ( !SUCCEEDED(result))
     {
         NFDi_SetError("Could not initialize COM.");
         goto end;
     }
 
-    ::IFileOpenDialog *fileOpenDialog(NULL);
-
     // Create dialog
     result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL,
                                 CLSCTX_ALL, ::IID_IFileOpenDialog,
@@ -616,3 +621,133 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
         
     return nfdResult;
 }
+
+class AutoCoInit
+{
+public:
+    AutoCoInit()
+    {
+        mResult = ::CoInitializeEx(NULL,
+            ::COINIT_APARTMENTTHREADED |
+            ::COINIT_DISABLE_OLE1DDE);
+    }
+
+    ~AutoCoInit()
+    {
+        if (SUCCEEDED(mResult))
+        {
+            ::CoUninitialize();
+        }
+    }
+
+    HRESULT Result() const { return mResult; }
+private:
+    HRESULT mResult;
+};
+
+// VS2010 hasn't got a copy of CComPtr - this was first added in the 2003 SDK, so we make our own small CComPtr instead
+template<class T>
+class ComPtr
+{
+public:
+    ComPtr() : mPtr(NULL) { }
+    ~ComPtr()
+    {
+        if (mPtr)
+        {
+            mPtr->Release();
+        }
+    }
+
+    T* Ptr() const { return mPtr; }
+    T** operator&() { return &mPtr; }
+    T* operator->() const { return mPtr; }
+private:
+    // Don't allow copy or assignment
+    ComPtr(const ComPtr&);
+    ComPtr& operator = (const ComPtr&) const;
+    T* mPtr;
+};
+
+nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
+    nfdchar_t **outPath)
+{
+    // Init COM
+    AutoCoInit autoCoInit;
+    if (!SUCCEEDED(autoCoInit.Result()))
+    {
+        NFDi_SetError("CoInitializeEx failed.");
+        return NFD_ERROR;
+    }
+
+    // Create the file dialog COM object
+    ComPtr<IFileDialog> pFileDialog;
+    if (!SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog,
+                                    NULL,
+                                    CLSCTX_ALL,
+                                    IID_PPV_ARGS(&pFileDialog))))
+    {
+        NFDi_SetError("CoCreateInstance for CLSID_FileOpenDialog failed.");
+        return NFD_ERROR;
+    }
+
+    // Set the default path
+    if (SetDefaultPath(pFileDialog.Ptr(), defaultPath) != NFD_OKAY)
+    {
+        NFDi_SetError("SetDefaultPath failed.");
+        return NFD_ERROR;
+    }
+
+    // Get the dialogs options
+    DWORD dwOptions = 0;
+    if (!SUCCEEDED(pFileDialog->GetOptions(&dwOptions)))
+    {
+        NFDi_SetError("GetOptions for IFileDialog failed.");
+        return NFD_ERROR;
+    }
+
+    // Add in FOS_PICKFOLDERS which hides files and only allows selection of folders
+    if (!SUCCEEDED(pFileDialog->SetOptions(dwOptions | FOS_PICKFOLDERS)))
+    {
+        NFDi_SetError("SetOptions for IFileDialog failed.");
+        return NFD_ERROR;
+    }
+
+    // Show the dialog to the user
+    const HRESULT result = pFileDialog->Show(NULL);
+    if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED))
+    {
+        return NFD_CANCEL;
+    }
+    else if (!SUCCEEDED(result))
+    {
+        NFDi_SetError("Show for IFileDialog failed.");
+        return NFD_ERROR;
+    }
+
+    // Get the shell item result
+    ComPtr<IShellItem> pShellItem;
+    if (!SUCCEEDED(pFileDialog->GetResult(&pShellItem)))
+    {
+        return NFD_OKAY;
+    }
+
+    // Finally get the path
+    wchar_t *path = NULL;
+    if (!SUCCEEDED(pShellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path)))
+    {
+        NFDi_SetError("GetDisplayName for IShellItem failed.");
+        return NFD_ERROR;
+    }
+
+    // Convert string
+    CopyWCharToNFDChar(path, outPath);
+    CoTaskMemFree(path);
+    if (!*outPath)
+    {
+        // error is malloc-based, error message would be redundant
+        return NFD_ERROR;
+    }
+
+    return NFD_OKAY;
+}

+ 4 - 2
Engine/source/platform/nativeDialogs/fileDialog.cpp

@@ -252,12 +252,14 @@ bool FileDialog::Execute()
    rootDir.replace("/", "\\");
 #endif
 
-   if (mData.mStyle & FileDialogData::FDS_OPEN)
+   if (mData.mStyle & FileDialogData::FDS_OPEN && !(mData.mStyle & FileDialogData::FDS_BROWSEFOLDER))
       result = NFD_OpenDialog(strippedFilters.c_str(), defaultPath.c_str(), &outPath);
-   else if (mData.mStyle & FileDialogData::FDS_SAVE)
+   else if (mData.mStyle & FileDialogData::FDS_SAVE && !(mData.mStyle & FileDialogData::FDS_BROWSEFOLDER))
       result = NFD_SaveDialog(strippedFilters.c_str(), defaultPath.c_str(), &outPath);
    else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES)
       result = NFD_OpenDialogMultiple(strippedFilters.c_str(), defaultPath.c_str(), &pathSet);
+   else if (mData.mStyle & FileDialogData::FDS_BROWSEFOLDER)
+	   result = NFD_PickFolder(defaultPath.c_str(), &outPath);
 
    if (result == NFD_CANCEL)
    {