mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-10 18:51:46 +00:00
65d6ef7ef4
https://github.com/mlabbe/nativefiledialog.git 5cfe5002eb0fac1e49777a17dec70134147931e2
380 lines
10 KiB
C
Executable File
380 lines
10 KiB
C
Executable File
/*
|
|
Native File Dialog
|
|
|
|
http://www.frogtoss.com/labs
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <gtk/gtk.h>
|
|
#include "nfd.h"
|
|
#include "nfd_common.h"
|
|
|
|
|
|
const char INIT_FAIL_MSG[] = "gtk_init_check failed to initilaize GTK+";
|
|
|
|
|
|
static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize )
|
|
{
|
|
const char SEP[] = ", ";
|
|
|
|
size_t len = strlen(filterName);
|
|
if ( len != 0 )
|
|
{
|
|
strncat( filterName, SEP, bufsize - len - 1 );
|
|
len += strlen(SEP);
|
|
}
|
|
|
|
strncat( filterName, typebuf, bufsize - len - 1 );
|
|
}
|
|
|
|
static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList )
|
|
{
|
|
GtkFileFilter *filter;
|
|
char typebuf[NFD_MAX_STRLEN] = {0};
|
|
const char *p_filterList = filterList;
|
|
char *p_typebuf = typebuf;
|
|
char filterName[NFD_MAX_STRLEN] = {0};
|
|
|
|
if ( !filterList || strlen(filterList) == 0 )
|
|
return;
|
|
|
|
filter = gtk_file_filter_new();
|
|
while ( 1 )
|
|
{
|
|
|
|
if ( NFDi_IsFilterSegmentChar(*p_filterList) )
|
|
{
|
|
char typebufWildcard[NFD_MAX_STRLEN];
|
|
/* add another type to the filter */
|
|
assert( strlen(typebuf) > 0 );
|
|
assert( strlen(typebuf) < NFD_MAX_STRLEN-1 );
|
|
|
|
snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf );
|
|
AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN );
|
|
|
|
gtk_file_filter_add_pattern( filter, typebufWildcard );
|
|
|
|
p_typebuf = typebuf;
|
|
memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN );
|
|
}
|
|
|
|
if ( *p_filterList == ';' || *p_filterList == '\0' )
|
|
{
|
|
/* end of filter -- add it to the dialog */
|
|
|
|
gtk_file_filter_set_name( filter, filterName );
|
|
gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter );
|
|
|
|
filterName[0] = '\0';
|
|
|
|
if ( *p_filterList == '\0' )
|
|
break;
|
|
|
|
filter = gtk_file_filter_new();
|
|
}
|
|
|
|
if ( !NFDi_IsFilterSegmentChar( *p_filterList ) )
|
|
{
|
|
*p_typebuf = *p_filterList;
|
|
p_typebuf++;
|
|
}
|
|
|
|
p_filterList++;
|
|
}
|
|
|
|
/* always append a wildcard option to the end*/
|
|
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name( filter, "*.*" );
|
|
gtk_file_filter_add_pattern( filter, "*" );
|
|
gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter );
|
|
}
|
|
|
|
static void SetDefaultPath( GtkWidget *dialog, const char *defaultPath )
|
|
{
|
|
if ( !defaultPath || strlen(defaultPath) == 0 )
|
|
return;
|
|
|
|
/* GTK+ manual recommends not specifically setting the default path.
|
|
We do it anyway in order to be consistent across platforms.
|
|
|
|
If consistency with the native OS is preferred, this is the line
|
|
to comment out. -ml */
|
|
gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), defaultPath );
|
|
}
|
|
|
|
static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet )
|
|
{
|
|
size_t bufSize = 0;
|
|
GSList *node;
|
|
nfdchar_t *p_buf;
|
|
size_t count = 0;
|
|
|
|
assert(fileList);
|
|
assert(pathSet);
|
|
|
|
pathSet->count = (size_t)g_slist_length( fileList );
|
|
assert( pathSet->count > 0 );
|
|
|
|
pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count );
|
|
if ( !pathSet->indices )
|
|
{
|
|
return NFD_ERROR;
|
|
}
|
|
|
|
/* count the total space needed for buf */
|
|
for ( node = fileList; node; node = node->next )
|
|
{
|
|
assert(node->data);
|
|
bufSize += strlen( (const gchar*)node->data ) + 1;
|
|
}
|
|
|
|
pathSet->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufSize );
|
|
|
|
/* fill buf */
|
|
p_buf = pathSet->buf;
|
|
for ( node = fileList; node; node = node->next )
|
|
{
|
|
nfdchar_t *path = (nfdchar_t*)(node->data);
|
|
size_t byteLen = strlen(path)+1;
|
|
ptrdiff_t index;
|
|
|
|
memcpy( p_buf, path, byteLen );
|
|
g_free(node->data);
|
|
|
|
index = p_buf - pathSet->buf;
|
|
assert( index >= 0 );
|
|
pathSet->indices[count] = (size_t)index;
|
|
|
|
p_buf += byteLen;
|
|
++count;
|
|
}
|
|
|
|
g_slist_free( fileList );
|
|
|
|
return NFD_OKAY;
|
|
}
|
|
|
|
static void WaitForCleanup(void)
|
|
{
|
|
while (gtk_events_pending())
|
|
gtk_main_iteration();
|
|
}
|
|
|
|
/* public */
|
|
|
|
nfdresult_t NFD_OpenDialog( const char *filterList,
|
|
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( "Open File",
|
|
NULL,
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
|
"_Open", GTK_RESPONSE_ACCEPT,
|
|
NULL );
|
|
|
|
/* 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_OpenDialogMultiple( const nfdchar_t *filterList,
|
|
const nfdchar_t *defaultPath,
|
|
nfdpathset_t *outPaths )
|
|
{
|
|
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( "Open Files",
|
|
NULL,
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
|
"_Open", GTK_RESPONSE_ACCEPT,
|
|
NULL );
|
|
gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(dialog), TRUE );
|
|
|
|
/* 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 )
|
|
{
|
|
GSList *fileList = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER(dialog) );
|
|
if ( AllocPathSet( fileList, outPaths ) == NFD_ERROR )
|
|
{
|
|
gtk_widget_destroy(dialog);
|
|
return NFD_ERROR;
|
|
}
|
|
|
|
result = NFD_OKAY;
|
|
}
|
|
|
|
WaitForCleanup();
|
|
gtk_widget_destroy(dialog);
|
|
WaitForCleanup();
|
|
|
|
return result;
|
|
}
|
|
|
|
nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
|
|
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( "Save File",
|
|
NULL,
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
|
"_Save", GTK_RESPONSE_ACCEPT,
|
|
NULL );
|
|
gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE );
|
|
|
|
/* 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);
|
|
|
|
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;
|
|
}
|