diff --git a/Makefile b/Makefile index a20d52e..c420ba4 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,36 @@ -#default: -# g++ ../main.cpp -o main.exe -O2 -Wall -Wno-missing-braces -Wno-narrowing -std=c++20 -I ../ -I ../include/ -L ../lib/ -I ../include/nfd_src -lnfd -lole32 -luuid -lraylib -lopengl32 -lgdi32 -lwinmm && ../build/main.exe - -#debug: -# g++ -g3 ../main.cpp -o main.exe -O2 -Wall -Wno-missing-braces -Wno-narrowing -std=c++20 -I ../ -I ../include/ -L ../lib/ -lraylib -lopengl32 -lgdi32 -lwinmm - -#final: -# g++ ../main.cpp -o main.exe -Ofast -Wall -Wno-missing-braces -Wno-narrowing -std=c++20 -I ../ -I ../include/ -L ../lib/ -I ../include/nfd_src -lnfd -lole32 -luuid -lraylib -lopengl32 -lgdi32 -lwinmm -static -static-libgcc -static-libstdc++ -Wl,--subsystem,windows && ../build/main.exe - # NFD just add -I ../include/nfd_src -lnfd -lole32 -luuid # nfd_src contains the .h files and remember to add nfd.lib into lib folder, contains implementations for nfd.h files + +# Get OS +PLATFORM_OS ?= WINDOWS +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! + # ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS = WINDOWS + else + UNAMEOS = $(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS = LINUX + endif + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),OpenBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),NetBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),DragonFly) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS = OSX + endif + endif +endif + SRCEXTS := cpp c HDREXTS := hpp h @@ -17,18 +39,31 @@ REMOVE := - rm CC := g++ BIN := ./build OBJ := ./build/obj -INCLUDE := ./src ./include ./include/nfd_src ./src/ui ./export/assets +INCLUDE := ./src ./include ./src/ui ./export/assets SRC := ./src SRCS := $(wildcard $(SRC)/*.cpp) $(wildcard $(SRC)/ui/*.cpp) OBJS := $(patsubst $(SRC)/%.cpp,$(OBJ)/%.o,$(SRCS)) + +ifeq ($(PLATFORM_OS),WINDOWS) EXE := main.exe +else +EXE := main +endif + WARNINGS := -Wno-missing-braces -Wno-narrowing -Wno-sign-compare -Wno-char-subscripts CFLAGS := -O2 -Wall -std=c++20 $(WARNINGS) LDFLAGS := -std=c++20 -L ./lib -LDLIBS := -licon -lnfd -lole32 -luuid -lraylib -lopengl32 -lgdi32 -lwinmm + +ifeq ($(PLATFORM_OS),WINDOWS) +LDLIBS := -licon -lraylib -lopengl32 -lgdi32 -lwinmm +endif +ifeq ($(PLATFORM_OS),LINUX) +LDLIBS := -lraylib -lGL -lc -lm -lpthread -ldl -lrt -lX11 +endif + IFLAGS := $(foreach dir,$(INCLUDE),-I $(dir)/) -.PHONY: all run clean debug default info export +.PHONY: all run clean debug release default info export all: $(EXE) @@ -36,11 +71,15 @@ all: $(EXE) default: all run debug: CFLAGS+=-g3 - -debug: clean - debug: all +release: LDLIBS+=-static -static-libgcc -static-libstdc++ +ifeq ($(PLATFORM_OS),WINDOWS) # how to remove console for linux? +release: LDLIBS+=-Wl,--subsystem,windows +endif +release: all run + +# quick TODO: add export linux support export: g++ ./export/exporter.cpp -o ./export/exporter.exe -O2 -Wall -Wno-sign-compare -std=c++20 -I ./include -I ./export/assets -L ./lib -lraylib -lopengl32 -lgdi32 -lwinmm && ./export/exporter.exe diff --git a/build/obj/nfd_wrapper.o b/build/obj/nfd_wrapper.o deleted file mode 100644 index e7923fe..0000000 Binary files a/build/obj/nfd_wrapper.o and /dev/null differ diff --git a/data/user_data.json b/data/user_data.json index 350b4d9..c7a4fcc 100644 --- a/data/user_data.json +++ b/data/user_data.json @@ -18,8 +18,8 @@ } ], "punctuation": 1, - "test time": 30, + "test time": 5, "numbers": 0, - "dictionary": "english doubleletter", + "dictionary": "english", "custom time": 12 } diff --git a/include/nfd_src/common.h b/include/nfd_src/common.h deleted file mode 100644 index 7745d32..0000000 --- a/include/nfd_src/common.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - Native File Dialog - - Internal, common across platforms - - http://www.frogtoss.com/labs - */ - - -#ifndef _NFD_COMMON_H -#define _NFD_COMMON_H - -#define NFD_MAX_STRLEN 256 -#define _NFD_UNUSED(x) ((void)x) - -void *NFDi_Malloc( size_t bytes ); -void NFDi_Free( void *ptr ); -void NFDi_SetError( const char *msg ); -void NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); - -#endif diff --git a/include/nfd_src/nfd.h b/include/nfd_src/nfd.h deleted file mode 100644 index 74c9274..0000000 --- a/include/nfd_src/nfd.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - Native File Dialog - - User API - - http://www.frogtoss.com/labs - */ - - -#ifndef _NFD_H -#define _NFD_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* denotes UTF-8 char */ -typedef char nfdchar_t; - -/* opaque data structure -- see NFD_PathSet_* */ -typedef struct { - nfdchar_t *buf; - size_t *indices; /* byte offsets into buf */ - size_t count; /* number of indices into buf */ -}nfdpathset_t; - -typedef enum { - NFD_ERROR, /* programmatic error */ - NFD_OKAY, /* user pressed okay, or successful return */ - NFD_CANCEL /* user pressed cancel */ -}nfdresult_t; - - -/* nfd_.c */ - -/* single file open dialog */ -nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ); - -/* multiple file open dialog */ -nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ); - -/* save dialog */ -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 */ -const char *NFD_GetError( void ); -/* get the number of entries stored in pathSet */ -size_t NFD_PathSet_GetCount( const nfdpathset_t *pathSet ); -/* Get the UTF-8 path at offset index */ -nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathSet, size_t index ); -/* Free the pathSet */ -void NFD_PathSet_Free( nfdpathset_t *pathSet ); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/nfd_src/nfd_cocoa.m b/include/nfd_src/nfd_cocoa.m deleted file mode 100644 index 776152d..0000000 --- a/include/nfd_src/nfd_cocoa.m +++ /dev/null @@ -1,286 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs - */ - -#include -#include "nfd.h" -#include "nfd_common.h" - -static NSArray *BuildAllowedFileTypes( const char *filterList ) -{ - // Commas and semicolons are the same thing on this platform - - NSMutableArray *buildFilterList = [[NSMutableArray alloc] init]; - - char typebuf[NFD_MAX_STRLEN] = {0}; - - size_t filterListLen = strlen(filterList); - char *p_typebuf = typebuf; - for ( size_t i = 0; i < filterListLen+1; ++i ) - { - if ( filterList[i] == ',' || filterList[i] == ';' || filterList[i] == '\0' ) - { - if (filterList[i] != '\0') - ++p_typebuf; - *p_typebuf = '\0'; - - NSString *thisType = [NSString stringWithUTF8String: typebuf]; - [buildFilterList addObject:thisType]; - p_typebuf = typebuf; - *p_typebuf = '\0'; - } - else - { - *p_typebuf = filterList[i]; - ++p_typebuf; - - } - } - - NSArray *returnArray = [NSArray arrayWithArray:buildFilterList]; - - [buildFilterList release]; - return returnArray; -} - -static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList ) -{ - if ( !filterList || strlen(filterList) == 0 ) - return; - - NSArray *allowedFileTypes = BuildAllowedFileTypes( filterList ); - if ( [allowedFileTypes count] != 0 ) - { - [dialog setAllowedFileTypes:allowedFileTypes]; - } -} - -static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath ) -{ - if ( !defaultPath || strlen(defaultPath) == 0 ) - return; - - NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath]; - NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES]; - [dialog setDirectoryURL:url]; -} - - -/* fixme: pathset should be pathSet */ -static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) -{ - assert(pathset); - assert([urls count]); - - pathset->count = (size_t)[urls count]; - pathset->indices = NFDi_Malloc( sizeof(size_t)*pathset->count ); - if ( !pathset->indices ) - { - return NFD_ERROR; - } - - // count the total space needed for buf - size_t bufsize = 0; - for ( NSURL *url in urls ) - { - NSString *path = [url path]; - bufsize += [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - } - - pathset->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufsize ); - if ( !pathset->buf ) - { - return NFD_ERROR; - } - - // fill buf - nfdchar_t *p_buf = pathset->buf; - size_t count = 0; - for ( NSURL *url in urls ) - { - NSString *path = [url path]; - const nfdchar_t *utf8Path = [path UTF8String]; - size_t byteLen = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - memcpy( p_buf, utf8Path, byteLen ); - - ptrdiff_t index = p_buf - pathset->buf; - assert( index >= 0 ); - pathset->indices[count] = (size_t)index; - - p_buf += byteLen; - ++count; - } - - return NFD_OKAY; -} - -/* public */ - - -nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; - NSOpenPanel *dialog = [NSOpenPanel openPanel]; - [dialog setAllowsMultipleSelection:NO]; - - // Build the filter list - AddFilterListToDialog(dialog, filterList); - - // 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]; - [keyWindow makeKeyAndOrderFront:nil]; - return NFD_ERROR; - } - memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ - nfdResult = NFD_OKAY; - } - [pool release]; - - [keyWindow makeKeyAndOrderFront:nil]; - return nfdResult; -} - - -nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; - - NSOpenPanel *dialog = [NSOpenPanel openPanel]; - [dialog setAllowsMultipleSelection:YES]; - - // Build the fiter list. - AddFilterListToDialog(dialog, filterList); - - // Set the starting directory - SetDefaultPath(dialog, defaultPath); - - nfdresult_t nfdResult = NFD_CANCEL; - if ( [dialog runModal] == NSModalResponseOK ) - { - NSArray *urls = [dialog URLs]; - - if ( [urls count] == 0 ) - { - [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; - return NFD_CANCEL; - } - - if ( AllocPathSet( urls, outPaths ) == NFD_ERROR ) - { - [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; - return NFD_ERROR; - } - - nfdResult = NFD_OKAY; - } - [pool release]; - - [keyWindow makeKeyAndOrderFront:nil]; - return nfdResult; -} - - -nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; - - NSSavePanel *dialog = [NSSavePanel savePanel]; - [dialog setExtensionHidden:NO]; - - // Build the filter list. - AddFilterListToDialog(dialog, filterList); - - // 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]; - - size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - - *outPath = NFDi_Malloc( byteLen ); - if ( !*outPath ) - { - [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; - return NFD_ERROR; - } - memcpy( *outPath, utf8Path, byteLen ); - nfdResult = NFD_OKAY; - } - - [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; - 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]; - [keyWindow makeKeyAndOrderFront:nil]; - return NFD_ERROR; - } - memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ - nfdResult = NFD_OKAY; - } - [pool release]; - - [keyWindow makeKeyAndOrderFront:nil]; - return nfdResult; -} diff --git a/include/nfd_src/nfd_common.c b/include/nfd_src/nfd_common.c deleted file mode 100644 index 55517f5..0000000 --- a/include/nfd_src/nfd_common.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs - */ - -#include -#include -#include -#include "nfd_common.h" - -static char g_errorstr[NFD_MAX_STRLEN] = {0}; - -/* public routines */ - -const char *NFD_GetError( void ) -{ - return g_errorstr; -} - -size_t NFD_PathSet_GetCount( const nfdpathset_t *pathset ) -{ - assert(pathset); - return pathset->count; -} - -nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathset, size_t num ) -{ - assert(pathset); - assert(num < pathset->count); - - return pathset->buf + pathset->indices[num]; -} - -void NFD_PathSet_Free( nfdpathset_t *pathset ) -{ - assert(pathset); - NFDi_Free( pathset->indices ); - NFDi_Free( pathset->buf ); -} - -/* internal routines */ - -void *NFDi_Malloc( size_t bytes ) -{ - void *ptr = malloc(bytes); - if ( !ptr ) - NFDi_SetError("NFDi_Malloc failed."); - - return ptr; -} - -void NFDi_Free( void *ptr ) -{ - assert(ptr); - free(ptr); -} - -void NFDi_SetError( const char *msg ) -{ - int bTruncate = NFDi_SafeStrncpy( g_errorstr, msg, NFD_MAX_STRLEN ); - assert( !bTruncate ); _NFD_UNUSED(bTruncate); -} - - -int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ) -{ - size_t n = maxCopy; - char *d = dst; - - assert( src ); - assert( dst ); - - while ( n > 0 && *src != '\0' ) - { - *d++ = *src++; - --n; - } - - /* Truncation case - - terminate string and return true */ - if ( n == 0 ) - { - dst[maxCopy-1] = '\0'; - return 1; - } - - /* No truncation. Append a single NULL and return. */ - *d = '\0'; - return 0; -} - - -/* adapted from microutf8 */ -int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ) -{ - /* This function doesn't properly check validity of UTF-8 character - sequence, it is supposed to use only with valid UTF-8 strings. */ - - int32_t character_count = 0; - int32_t i = 0; /* Counter used to iterate over string. */ - nfdchar_t maybe_bom[4]; - - /* If there is UTF-8 BOM ignore it. */ - if (strlen(str) > 2) - { - strncpy(maybe_bom, str, 3); - maybe_bom[3] = 0; - if (strcmp(maybe_bom, (nfdchar_t*)NFD_UTF8_BOM) == 0) - i += 3; - } - - while(str[i]) - { - if (str[i] >> 7 == 0) - { - /* If bit pattern begins with 0 we have ascii character. */ - ++character_count; - } - else if (str[i] >> 6 == 3) - { - /* If bit pattern begins with 11 it is beginning of UTF-8 byte sequence. */ - ++character_count; - } - else if (str[i] >> 6 == 2) - ; /* If bit pattern begins with 10 it is middle of utf-8 byte sequence. */ - else - { - /* In any other case this is not valid UTF-8. */ - return -1; - } - ++i; - } - - return character_count; -} - -int NFDi_IsFilterSegmentChar( char ch ) -{ - return (ch==','||ch==';'||ch=='\0'); -} - diff --git a/include/nfd_src/nfd_common.h b/include/nfd_src/nfd_common.h deleted file mode 100644 index 1a9ab16..0000000 --- a/include/nfd_src/nfd_common.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Native File Dialog - - Internal, common across platforms - - http://www.frogtoss.com/labs - */ - - -#ifndef _NFD_COMMON_H -#define _NFD_COMMON_H - -#include "nfd.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NFD_MAX_STRLEN 256 -#define _NFD_UNUSED(x) ((void)x) - -#define NFD_UTF8_BOM "\xEF\xBB\xBF" - - -void *NFDi_Malloc( size_t bytes ); -void NFDi_Free( void *ptr ); -void NFDi_SetError( const char *msg ); -int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); -int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ); -int NFDi_IsFilterSegmentChar( char ch ); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/include/nfd_src/nfd_gtk.c b/include/nfd_src/nfd_gtk.c deleted file mode 100644 index 7a9958e..0000000 --- a/include/nfd_src/nfd_gtk.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs -*/ - -#include -#include -#include -#include -#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 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( "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; -} diff --git a/include/nfd_src/nfd_win.cpp b/include/nfd_src/nfd_win.cpp deleted file mode 100644 index 949da2b..0000000 --- a/include/nfd_src/nfd_win.cpp +++ /dev/null @@ -1,762 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs - */ - - -#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 - -#define _CRTDBG_MAP_ALLOC -#include -#include - -/* only locally define UNICODE in this compilation unit */ -#ifndef UNICODE -#define UNICODE -#endif - -#include -#include -#include -#include -#include -#include "nfd_common.h" - - -#define COM_INITFLAGS ::COINIT_APARTMENTTHREADED | ::COINIT_DISABLE_OLE1DDE - -static BOOL COMIsInitialized(HRESULT coResult) -{ - if (coResult == RPC_E_CHANGED_MODE) - { - // If COM was previously initialized with different init flags, - // NFD still needs to operate. Eat this warning. - return TRUE; - } - - return SUCCEEDED(coResult); -} - -static HRESULT COMInit(void) -{ - return ::CoInitializeEx(NULL, COM_INITFLAGS); -} - -static void COMUninit(HRESULT coResult) -{ - // do not uninitialize if RPC_E_CHANGED_MODE occurred -- this - // case does not refcount COM. - if (SUCCEEDED(coResult)) - ::CoUninitialize(); -} - -// allocs the space in outPath -- call free() -static void CopyWCharToNFDChar( const wchar_t *inStr, nfdchar_t **outStr ) -{ - int inStrCharacterCount = static_cast(wcslen(inStr)); - int bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, - inStr, inStrCharacterCount, - NULL, 0, NULL, NULL ); - assert( bytesNeeded ); - bytesNeeded += 1; - - *outStr = (nfdchar_t*)NFDi_Malloc( bytesNeeded ); - if ( !*outStr ) - return; - - int bytesWritten = WideCharToMultiByte( CP_UTF8, 0, - inStr, -1, - *outStr, bytesNeeded, - NULL, NULL ); - assert( bytesWritten ); _NFD_UNUSED( bytesWritten ); -} - -/* includes NULL terminator byte in return */ -static size_t GetUTF8ByteCountForWChar( const wchar_t *str ) -{ - size_t bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, - str, -1, - NULL, 0, NULL, NULL ); - assert( bytesNeeded ); - return bytesNeeded+1; -} - -// write to outPtr -- no free() necessary. -static int CopyWCharToExistingNFDCharBuffer( const wchar_t *inStr, nfdchar_t *outPtr ) -{ - int bytesNeeded = static_cast(GetUTF8ByteCountForWChar( inStr )); - - /* invocation copies null term */ - int bytesWritten = WideCharToMultiByte( CP_UTF8, 0, - inStr, -1, - outPtr, bytesNeeded, - NULL, 0 ); - assert( bytesWritten ); - - return bytesWritten; - -} - - -// allocs the space in outStr -- call free() -static void CopyNFDCharToWChar( const nfdchar_t *inStr, wchar_t **outStr ) -{ - int inStrByteCount = static_cast(strlen(inStr)); - int charsNeeded = MultiByteToWideChar(CP_UTF8, 0, - inStr, inStrByteCount, - NULL, 0 ); - assert( charsNeeded ); - assert( !*outStr ); - charsNeeded += 1; // terminator - - *outStr = (wchar_t*)NFDi_Malloc( charsNeeded * sizeof(wchar_t) ); - if ( !*outStr ) - return; - - int ret = MultiByteToWideChar(CP_UTF8, 0, - inStr, inStrByteCount, - *outStr, charsNeeded); - (*outStr)[charsNeeded-1] = '\0'; - -#ifdef _DEBUG - int inStrCharacterCount = static_cast(NFDi_UTF8_Strlen(inStr)); - assert( ret == inStrCharacterCount ); -#else - _NFD_UNUSED(ret); -#endif -} - - -/* ext is in format "jpg", no wildcards or separators */ -static int AppendExtensionToSpecBuf( const char *ext, char *specBuf, size_t specBufLen ) -{ - const char SEP[] = ";"; - assert( specBufLen > strlen(ext)+3 ); - - if ( strlen(specBuf) > 0 ) - { - strncat( specBuf, SEP, specBufLen - strlen(specBuf) - 1 ); - specBufLen += strlen(SEP); - } - - char extWildcard[NFD_MAX_STRLEN]; - int bytesWritten = sprintf_s( extWildcard, NFD_MAX_STRLEN, "*.%s", ext ); - assert( bytesWritten == (int)(strlen(ext)+2) ); - _NFD_UNUSED(bytesWritten); - - strncat( specBuf, extWildcard, specBufLen - strlen(specBuf) - 1 ); - - return NFD_OKAY; -} - -static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char *filterList ) -{ - const wchar_t WILDCARD[] = L"*.*"; - - if ( !filterList || strlen(filterList) == 0 ) - return NFD_OKAY; - - // Count rows to alloc - UINT filterCount = 1; /* guaranteed to have one filter on a correct, non-empty parse */ - const char *p_filterList; - for ( p_filterList = filterList; *p_filterList; ++p_filterList ) - { - if ( *p_filterList == ';' ) - ++filterCount; - } - - assert(filterCount); - if ( !filterCount ) - { - NFDi_SetError("Error parsing filters."); - return NFD_ERROR; - } - - /* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */ - COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * ((size_t)filterCount + 1) ); - if ( !specList ) - { - return NFD_ERROR; - } - for (UINT i = 0; i < filterCount+1; ++i ) - { - specList[i].pszName = NULL; - specList[i].pszSpec = NULL; - } - - size_t specIdx = 0; - p_filterList = filterList; - char typebuf[NFD_MAX_STRLEN] = {0}; /* one per comma or semicolon */ - char *p_typebuf = typebuf; - - char specbuf[NFD_MAX_STRLEN] = {0}; /* one per semicolon */ - - while ( 1 ) - { - if ( NFDi_IsFilterSegmentChar(*p_filterList) ) - { - /* append a type to the specbuf (pending filter) */ - AppendExtensionToSpecBuf( typebuf, specbuf, NFD_MAX_STRLEN ); - - p_typebuf = typebuf; - memset( typebuf, 0, sizeof(char)*NFD_MAX_STRLEN ); - } - - if ( *p_filterList == ';' || *p_filterList == '\0' ) - { - /* end of filter -- add it to specList */ - - CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszName ); - CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec ); - - memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN ); - ++specIdx; - if ( specIdx == filterCount ) - break; - } - - if ( !NFDi_IsFilterSegmentChar( *p_filterList )) - { - *p_typebuf = *p_filterList; - ++p_typebuf; - } - - ++p_filterList; - } - - /* Add wildcard */ - specList[specIdx].pszSpec = WILDCARD; - specList[specIdx].pszName = WILDCARD; - - fileOpenDialog->SetFileTypes( filterCount+1, specList ); - - /* free speclist */ - for ( size_t i = 0; i < filterCount; ++i ) - { - NFDi_Free( (void*)specList[i].pszSpec ); - } - NFDi_Free( specList ); - - return NFD_OKAY; -} - -static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *pathSet ) -{ - const char ERRORMSG[] = "Error allocating pathset."; - - assert(shellItems); - assert(pathSet); - - // How many items in shellItems? - DWORD numShellItems; - HRESULT result = shellItems->GetCount(&numShellItems); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError(ERRORMSG); - return NFD_ERROR; - } - - pathSet->count = static_cast(numShellItems); - assert( pathSet->count > 0 ); - - pathSet->indices = (size_t*)NFDi_Malloc( sizeof(size_t)*pathSet->count ); - if ( !pathSet->indices ) - { - return NFD_ERROR; - } - - /* count the total bytes needed for buf */ - size_t bufSize = 0; - for ( DWORD i = 0; i < numShellItems; ++i ) - { - ::IShellItem *shellItem; - result = shellItems->GetItemAt(i, &shellItem); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError(ERRORMSG); - return NFD_ERROR; - } - - // Confirm SFGAO_FILESYSTEM is true for this shellitem, or ignore it. - SFGAOF attribs; - result = shellItem->GetAttributes( SFGAO_FILESYSTEM, &attribs ); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError(ERRORMSG); - return NFD_ERROR; - } - if ( !(attribs & SFGAO_FILESYSTEM) ) - continue; - - LPWSTR name; - shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); - - // Calculate length of name with UTF-8 encoding - bufSize += GetUTF8ByteCountForWChar( name ); - - CoTaskMemFree(name); - } - - assert(bufSize); - - pathSet->buf = (nfdchar_t*)NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); - memset( pathSet->buf, 0, sizeof(nfdchar_t) * bufSize ); - - /* fill buf */ - nfdchar_t *p_buf = pathSet->buf; - for (DWORD i = 0; i < numShellItems; ++i ) - { - ::IShellItem *shellItem; - result = shellItems->GetItemAt(i, &shellItem); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError(ERRORMSG); - return NFD_ERROR; - } - - // Confirm SFGAO_FILESYSTEM is true for this shellitem, or ignore it. - SFGAOF attribs; - result = shellItem->GetAttributes( SFGAO_FILESYSTEM, &attribs ); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError(ERRORMSG); - return NFD_ERROR; - } - if ( !(attribs & SFGAO_FILESYSTEM) ) - continue; - - LPWSTR name; - shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); - - int bytesWritten = CopyWCharToExistingNFDCharBuffer(name, p_buf); - CoTaskMemFree(name); - - ptrdiff_t index = p_buf - pathSet->buf; - assert( index >= 0 ); - pathSet->indices[i] = static_cast(index); - - p_buf += bytesWritten; - } - - return NFD_OKAY; -} - - -static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath ) -{ - if ( !defaultPath || strlen(defaultPath) == 0 ) - return NFD_OKAY; - - wchar_t *defaultPathW = {0}; - CopyNFDCharToWChar( defaultPath, &defaultPathW ); - - IShellItem *folder; - HRESULT result = SHCreateItemFromParsingName( defaultPathW, NULL, IID_PPV_ARGS(&folder) ); - - // Valid non results. - if ( result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE) ) - { - NFDi_Free( defaultPathW ); - return NFD_OKAY; - } - - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Error creating ShellItem"); - NFDi_Free( defaultPathW ); - return NFD_ERROR; - } - - // Could also call SetDefaultFolder(), but this guarantees defaultPath -- more consistency across API. - dialog->SetFolder( folder ); - - NFDi_Free( defaultPathW ); - folder->Release(); - - return NFD_OKAY; -} - -/* public */ - - -nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - nfdresult_t nfdResult = NFD_ERROR; - - - HRESULT coResult = COMInit(); - if (!COMIsInitialized(coResult)) - { - NFDi_SetError("Could not initialize COM."); - return nfdResult; - } - - // Create dialog - ::IFileOpenDialog *fileOpenDialog(NULL); - HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, - CLSCTX_ALL, ::IID_IFileOpenDialog, - reinterpret_cast(&fileOpenDialog) ); - - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not create dialog."); - goto end; - } - - // Build the filter list - if ( !AddFiltersToDialog( fileOpenDialog, filterList ) ) - { - goto end; - } - - // Set the default path - if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) - { - goto end; - } - - // Show the dialog. - result = fileOpenDialog->Show(NULL); - if ( SUCCEEDED(result) ) - { - // Get the file name - ::IShellItem *shellItem(NULL); - result = fileOpenDialog->GetResult(&shellItem); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not get shell item from dialog."); - goto end; - } - wchar_t *filePath(NULL); - result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not get file path for selected."); - shellItem->Release(); - goto end; - } - - CopyWCharToNFDChar( filePath, outPath ); - CoTaskMemFree(filePath); - if ( !*outPath ) - { - /* error is malloc-based, error message would be redundant */ - shellItem->Release(); - goto end; - } - - nfdResult = NFD_OKAY; - shellItem->Release(); - } - else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) - { - nfdResult = NFD_CANCEL; - } - else - { - NFDi_SetError("File dialog box show failed."); - nfdResult = NFD_ERROR; - } - -end: - if (fileOpenDialog) - fileOpenDialog->Release(); - - COMUninit(coResult); - - return nfdResult; -} - -nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) -{ - nfdresult_t nfdResult = NFD_ERROR; - - - HRESULT coResult = COMInit(); - if (!COMIsInitialized(coResult)) - { - NFDi_SetError("Could not initialize COM."); - return nfdResult; - } - - // Create dialog - ::IFileOpenDialog *fileOpenDialog(NULL); - HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, - CLSCTX_ALL, ::IID_IFileOpenDialog, - reinterpret_cast(&fileOpenDialog) ); - - if ( !SUCCEEDED(result) ) - { - fileOpenDialog = NULL; - NFDi_SetError("Could not create dialog."); - goto end; - } - - // Build the filter list - if ( !AddFiltersToDialog( fileOpenDialog, filterList ) ) - { - goto end; - } - - // Set the default path - if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) - { - goto end; - } - - // Set a flag for multiple options - DWORD dwFlags; - result = fileOpenDialog->GetOptions(&dwFlags); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not get options."); - goto end; - } - result = fileOpenDialog->SetOptions(dwFlags | FOS_ALLOWMULTISELECT); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not set options."); - goto end; - } - - // Show the dialog. - result = fileOpenDialog->Show(NULL); - if ( SUCCEEDED(result) ) - { - IShellItemArray *shellItems; - result = fileOpenDialog->GetResults( &shellItems ); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not get shell items."); - goto end; - } - - if ( AllocPathSet( shellItems, outPaths ) == NFD_ERROR ) - { - shellItems->Release(); - goto end; - } - - shellItems->Release(); - nfdResult = NFD_OKAY; - } - else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) - { - nfdResult = NFD_CANCEL; - } - else - { - NFDi_SetError("File dialog box show failed."); - nfdResult = NFD_ERROR; - } - -end: - if ( fileOpenDialog ) - fileOpenDialog->Release(); - - COMUninit(coResult); - - return nfdResult; -} - -nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - nfdresult_t nfdResult = NFD_ERROR; - - HRESULT coResult = COMInit(); - if (!COMIsInitialized(coResult)) - { - NFDi_SetError("Could not initialize COM."); - return nfdResult; - } - - // Create dialog - ::IFileSaveDialog *fileSaveDialog(NULL); - HRESULT result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL, - CLSCTX_ALL, ::IID_IFileSaveDialog, - reinterpret_cast(&fileSaveDialog) ); - - if ( !SUCCEEDED(result) ) - { - fileSaveDialog = NULL; - NFDi_SetError("Could not create dialog."); - goto end; - } - - // Build the filter list - if ( !AddFiltersToDialog( fileSaveDialog, filterList ) ) - { - goto end; - } - - // Set the default path - if ( !SetDefaultPath( fileSaveDialog, defaultPath ) ) - { - goto end; - } - - // Show the dialog. - result = fileSaveDialog->Show(NULL); - if ( SUCCEEDED(result) ) - { - // Get the file name - ::IShellItem *shellItem; - result = fileSaveDialog->GetResult(&shellItem); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not get shell item from dialog."); - goto end; - } - wchar_t *filePath(NULL); - result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); - if ( !SUCCEEDED(result) ) - { - shellItem->Release(); - NFDi_SetError("Could not get file path for selected."); - goto end; - } - - CopyWCharToNFDChar( filePath, outPath ); - CoTaskMemFree(filePath); - if ( !*outPath ) - { - /* error is malloc-based, error message would be redundant */ - shellItem->Release(); - goto end; - } - - nfdResult = NFD_OKAY; - shellItem->Release(); - } - else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) - { - nfdResult = NFD_CANCEL; - } - else - { - NFDi_SetError("File dialog box show failed."); - nfdResult = NFD_ERROR; - } - -end: - if ( fileSaveDialog ) - fileSaveDialog->Release(); - - COMUninit(coResult); - - return nfdResult; -} - - - -nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, - nfdchar_t **outPath) -{ - nfdresult_t nfdResult = NFD_ERROR; - DWORD dwOptions = 0; - - HRESULT coResult = COMInit(); - if (!COMIsInitialized(coResult)) - { - NFDi_SetError("CoInitializeEx failed."); - return nfdResult; - } - - // Create dialog - ::IFileOpenDialog *fileDialog(NULL); - HRESULT result = CoCreateInstance(CLSID_FileOpenDialog, - NULL, - CLSCTX_ALL, - IID_PPV_ARGS(&fileDialog)); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("CoCreateInstance for CLSID_FileOpenDialog failed."); - goto end; - } - - // Set the default path - if (SetDefaultPath(fileDialog, defaultPath) != NFD_OKAY) - { - NFDi_SetError("SetDefaultPath failed."); - goto end; - } - - // Get the dialogs options - if (!SUCCEEDED(fileDialog->GetOptions(&dwOptions))) - { - NFDi_SetError("GetOptions for IFileDialog failed."); - goto end; - } - - // Add in FOS_PICKFOLDERS which hides files and only allows selection of folders - if (!SUCCEEDED(fileDialog->SetOptions(dwOptions | FOS_PICKFOLDERS))) - { - NFDi_SetError("SetOptions for IFileDialog failed."); - goto end; - } - - // Show the dialog to the user - result = fileDialog->Show(NULL); - if ( SUCCEEDED(result) ) - { - // Get the folder name - ::IShellItem *shellItem(NULL); - - result = fileDialog->GetResult(&shellItem); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("Could not get file path for selected."); - shellItem->Release(); - goto end; - } - - wchar_t *path = NULL; - result = shellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path); - if ( !SUCCEEDED(result) ) - { - NFDi_SetError("GetDisplayName for IShellItem failed."); - shellItem->Release(); - goto end; - } - - CopyWCharToNFDChar(path, outPath); - CoTaskMemFree(path); - if ( !*outPath ) - { - shellItem->Release(); - goto end; - } - - nfdResult = NFD_OKAY; - shellItem->Release(); - } - else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED) ) - { - nfdResult = NFD_CANCEL; - } - else - { - NFDi_SetError("Show for IFileDialog failed."); - nfdResult = NFD_ERROR; - } - - end: - - if (fileDialog) - fileDialog->Release(); - - COMUninit(coResult); - - return nfdResult; -} diff --git a/include/nfd_src/nfd_zenity.c b/include/nfd_src/nfd_zenity.c deleted file mode 100644 index 5f93133..0000000 --- a/include/nfd_src/nfd_zenity.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs -*/ - -#include -#include -#include -#include "nfd.h" -#include "nfd_common.h" - -#define SIMPLE_EXEC_IMPLEMENTATION -#include "simple_exec.h" - - -const char NO_ZENITY_MSG[] = "zenity not installed"; - - -static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize ) -{ - size_t len = strlen(filterName); - if( len > 0 ) - strncat( filterName, " *.", bufsize - len - 1 ); - else - strncat( filterName, "--file-filter=*.", bufsize - len - 1 ); - - len = strlen(filterName); - strncat( filterName, typebuf, bufsize - len - 1 ); -} - -static void AddFiltersToCommandArgs(char** commandArgs, int commandArgsLen, const char *filterList ) -{ - char typebuf[NFD_MAX_STRLEN] = {0}; - const char *p_filterList = filterList; - char *p_typebuf = typebuf; - char filterName[NFD_MAX_STRLEN] = {0}; - int i; - - if ( !filterList || strlen(filterList) == 0 ) - return; - - 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 ); - - 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 */ - - for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++); - - commandArgs[i] = strdup(filterName); - - filterName[0] = '\0'; - - if ( *p_filterList == '\0' ) - break; - } - - if ( !NFDi_IsFilterSegmentChar( *p_filterList ) ) - { - *p_typebuf = *p_filterList; - p_typebuf++; - } - - p_filterList++; - } - - /* always append a wildcard option to the end*/ - - for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++); - - commandArgs[i] = strdup("--file-filter=*.*"); -} - -static nfdresult_t ZenityCommon(char** command, int commandLen, const char* defaultPath, const char* filterList, char** stdOut) -{ - if(defaultPath != NULL) - { - char* prefix = "--filename="; - int len = strlen(prefix) + strlen(defaultPath) + 1; - - char* tmp = (char*) calloc(len, 1); - strcat(tmp, prefix); - strcat(tmp, defaultPath); - - int i; - for(i = 0; command[i] != NULL && i < commandLen; i++); - - command[i] = tmp; - } - - AddFiltersToCommandArgs(command, commandLen, filterList); - - int byteCount = 0; - int exitCode = 0; - int processInvokeError = runCommandArray(stdOut, &byteCount, &exitCode, 0, command); - - for(int i = 0; command[i] != NULL && i < commandLen; i++) - free(command[i]); - - nfdresult_t result = NFD_OKAY; - - if(processInvokeError == COMMAND_NOT_FOUND) - { - NFDi_SetError(NO_ZENITY_MSG); - result = NFD_ERROR; - } - else - { - if(exitCode == 1) - result = NFD_CANCEL; - } - - return result; -} - - -static nfdresult_t AllocPathSet(char* zenityList, nfdpathset_t *pathSet ) -{ - assert(zenityList); - assert(pathSet); - - size_t len = strlen(zenityList) + 1; - pathSet->buf = NFDi_Malloc(len); - - int numEntries = 1; - - for(size_t i = 0; i < len; i++) - { - char ch = zenityList[i]; - - if(ch == '|') - { - numEntries++; - ch = '\0'; - } - - pathSet->buf[i] = ch; - } - - pathSet->count = numEntries; - assert( pathSet->count > 0 ); - - pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); - - int entry = 0; - pathSet->indices[0] = 0; - for(size_t i = 0; i < len; i++) - { - char ch = zenityList[i]; - - if(ch == '|') - { - entry++; - pathSet->indices[entry] = i + 1; - } - } - - return NFD_OKAY; -} - -/* public */ - -nfdresult_t NFD_OpenDialog( const char *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - int commandLen = 100; - char* command[commandLen]; - memset(command, 0, commandLen * sizeof(char*)); - - command[0] = strdup("zenity"); - command[1] = strdup("--file-selection"); - command[2] = strdup("--title=Open File"); - - char* stdOut = NULL; - nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); - - if(stdOut != NULL) - { - size_t len = strlen(stdOut); - *outPath = NFDi_Malloc(len); - memcpy(*outPath, stdOut, len); - (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator - free(stdOut); - } - else - { - *outPath = NULL; - } - - return result; -} - - -nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) -{ - int commandLen = 100; - char* command[commandLen]; - memset(command, 0, commandLen * sizeof(char*)); - - command[0] = strdup("zenity"); - command[1] = strdup("--file-selection"); - command[2] = strdup("--title=Open Files"); - command[3] = strdup("--multiple"); - - char* stdOut = NULL; - nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); - - if(stdOut != NULL) - { - size_t len = strlen(stdOut); - stdOut[len-1] = '\0'; // remove trailing newline - - if ( AllocPathSet( stdOut, outPaths ) == NFD_ERROR ) - result = NFD_ERROR; - - free(stdOut); - } - else - { - result = NFD_ERROR; - } - - return result; -} - -nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - int commandLen = 100; - char* command[commandLen]; - memset(command, 0, commandLen * sizeof(char*)); - - command[0] = strdup("zenity"); - command[1] = strdup("--file-selection"); - command[2] = strdup("--title=Save File"); - command[3] = strdup("--save"); - - char* stdOut = NULL; - nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut); - - if(stdOut != NULL) - { - size_t len = strlen(stdOut); - *outPath = NFDi_Malloc(len); - memcpy(*outPath, stdOut, len); - (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator - free(stdOut); - } - else - { - *outPath = NULL; - } - - return result; -} - -nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, - nfdchar_t **outPath) -{ - int commandLen = 100; - char* command[commandLen]; - memset(command, 0, commandLen * sizeof(char*)); - - command[0] = strdup("zenity"); - command[1] = strdup("--file-selection"); - command[2] = strdup("--directory"); - command[3] = strdup("--title=Select folder"); - - char* stdOut = NULL; - nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut); - - if(stdOut != NULL) - { - size_t len = strlen(stdOut); - *outPath = NFDi_Malloc(len); - memcpy(*outPath, stdOut, len); - (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator - free(stdOut); - } - else - { - *outPath = NULL; - } - - return result; -} diff --git a/include/nfd_src/simple_exec.h b/include/nfd_src/simple_exec.h deleted file mode 100644 index 6308dfe..0000000 --- a/include/nfd_src/simple_exec.h +++ /dev/null @@ -1,218 +0,0 @@ -// copied from: https://github.com/wheybags/simple_exec/blob/5a74c507c4ce1b2bb166177ead4cca7cfa23cb35/simple_exec.h - -// simple_exec.h, single header library to run external programs + retrieve their status code and output (unix only for now) -// -// do this: -// #define SIMPLE_EXEC_IMPLEMENTATION -// before you include this file in *one* C or C++ file to create the implementation. -// i.e. it should look like this: -// #define SIMPLE_EXEC_IMPLEMENTATION -// #include "simple_exec.h" - -#ifndef SIMPLE_EXEC_H -#define SIMPLE_EXEC_H - -int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...); -int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs); - -#endif // SIMPLE_EXEC_H - -#ifdef SIMPLE_EXEC_IMPLEMENTATION - -#include -#include -#include -#include -#include -#include -#include -#include - -#define release_assert(exp) { if (!(exp)) { abort(); } } - -enum PIPE_FILE_DESCRIPTORS -{ - READ_FD = 0, - WRITE_FD = 1 -}; - -enum RUN_COMMAND_ERROR -{ - COMMAND_RAN_OK = 0, - COMMAND_NOT_FOUND = 1 -}; - -int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs) -{ - // adapted from: https://stackoverflow.com/a/479103 - - int bufferSize = 256; - char buffer[bufferSize + 1]; - - int dataReadFromChildDefaultSize = bufferSize * 5; - int dataReadFromChildSize = dataReadFromChildDefaultSize; - int dataReadFromChildUsed = 0; - char* dataReadFromChild = (char*)malloc(dataReadFromChildSize); - - - int parentToChild[2]; - release_assert(pipe(parentToChild) == 0); - - int childToParent[2]; - release_assert(pipe(childToParent) == 0); - - int errPipe[2]; - release_assert(pipe(errPipe) == 0); - - pid_t pid; - switch( pid = fork() ) - { - case -1: - { - release_assert(0 && "Fork failed"); - break; - } - - case 0: // child - { - release_assert(dup2(parentToChild[READ_FD ], STDIN_FILENO ) != -1); - release_assert(dup2(childToParent[WRITE_FD], STDOUT_FILENO) != -1); - - if(includeStdErr) - { - release_assert(dup2(childToParent[WRITE_FD], STDERR_FILENO) != -1); - } - else - { - int devNull = open("/dev/null", O_WRONLY); - release_assert(dup2(devNull, STDERR_FILENO) != -1); - } - - // unused - release_assert(close(parentToChild[WRITE_FD]) == 0); - release_assert(close(childToParent[READ_FD ]) == 0); - release_assert(close(errPipe[READ_FD]) == 0); - - const char* command = allArgs[0]; - execvp(command, allArgs); - - char err = 1; - ssize_t result = write(errPipe[WRITE_FD], &err, 1); - release_assert(result != -1); - - close(errPipe[WRITE_FD]); - close(parentToChild[READ_FD]); - close(childToParent[WRITE_FD]); - - exit(0); - } - - - default: // parent - { - // unused - release_assert(close(parentToChild[READ_FD]) == 0); - release_assert(close(childToParent[WRITE_FD]) == 0); - release_assert(close(errPipe[WRITE_FD]) == 0); - - while(1) - { - ssize_t bytesRead = 0; - switch(bytesRead = read(childToParent[READ_FD], buffer, bufferSize)) - { - case 0: // End-of-File, or non-blocking read. - { - int status = 0; - release_assert(waitpid(pid, &status, 0) == pid); - - // done with these now - release_assert(close(parentToChild[WRITE_FD]) == 0); - release_assert(close(childToParent[READ_FD]) == 0); - - char errChar = 0; - ssize_t result = read(errPipe[READ_FD], &errChar, 1); - release_assert(result != -1); - close(errPipe[READ_FD]); - - if(errChar) - { - free(dataReadFromChild); - return COMMAND_NOT_FOUND; - } - - // free any un-needed memory with realloc + add a null terminator for convenience - dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildUsed + 1); - dataReadFromChild[dataReadFromChildUsed] = '\0'; - - if(stdOut != NULL) - *stdOut = dataReadFromChild; - else - free(dataReadFromChild); - - if(stdOutByteCount != NULL) - *stdOutByteCount = dataReadFromChildUsed; - if(returnCode != NULL) - *returnCode = WEXITSTATUS(status); - - return COMMAND_RAN_OK; - } - case -1: - { - release_assert(0 && "read() failed"); - break; - } - - default: - { - if(dataReadFromChildUsed + bytesRead + 1 >= dataReadFromChildSize) - { - dataReadFromChildSize += dataReadFromChildDefaultSize; - dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildSize); - } - - memcpy(dataReadFromChild + dataReadFromChildUsed, buffer, bytesRead); - dataReadFromChildUsed += bytesRead; - break; - } - } - } - } - } -} - -int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...) -{ - va_list vl; - va_start(vl, command); - - char* currArg = NULL; - - int allArgsInitialSize = 16; - int allArgsSize = allArgsInitialSize; - char** allArgs = (char**)malloc(sizeof(char*) * allArgsSize); - allArgs[0] = command; - - int i = 1; - do - { - currArg = va_arg(vl, char*); - allArgs[i] = currArg; - - i++; - - if(i >= allArgsSize) - { - allArgsSize += allArgsInitialSize; - allArgs = (char**)realloc(allArgs, sizeof(char*) * allArgsSize); - } - - } while(currArg != NULL); - - va_end(vl); - - int retval = runCommandArray(stdOut, stdOutByteCount, returnCode, includeStdErr, allArgs); - free(allArgs); - return retval; -} - -#endif //SIMPLE_EXEC_IMPLEMENTATION diff --git a/include/raylibcustom.h b/include/raylibcustom.h index 090be15..c6b296b 100644 --- a/include/raylibcustom.h +++ b/include/raylibcustom.h @@ -13,7 +13,9 @@ #include #include #include -#include +#include +#include +#include using namespace std; #define sgn(x) (((x)>0) - ((x)<0)) diff --git a/lib/nfd.lib b/lib/nfd.lib deleted file mode 100644 index 2285341..0000000 Binary files a/lib/nfd.lib and /dev/null differ diff --git a/main.exe b/main.exe index f570eaa..09456d4 100644 Binary files a/main.exe and b/main.exe differ diff --git a/src/FileExplorer.cpp b/src/FileExplorer.cpp index 62e3f02..0e4f330 100644 --- a/src/FileExplorer.cpp +++ b/src/FileExplorer.cpp @@ -1,8 +1,17 @@ #include "FileExplorer.h" + +#ifdef _WIN32 #include #include +#elif __linux__ +// ??? +#elif __APPLE__ || __MACH__ +// ??? +#endif void open_path(std::string path) { + #ifdef _WIN32 ShellExecuteA(NULL, "open", path.c_str(), NULL, NULL, SW_SHOWDEFAULT); + #endif } diff --git a/src/Utils.cpp b/src/Utils.cpp index 80dd8db..090f22f 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,4 +1,3 @@ -#include #include #include "RobotoMono.h" #include "Utils.h" diff --git a/src/main.cpp b/src/main.cpp index 75c61b2..65c695d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,6 @@ #include "raylibcustom.h" #include #include -#include "nfd_wrapper.h" #include "globals.h" #include "Theme.h" #include "ResourceInit.h" @@ -43,7 +42,7 @@ #include "UIAlloc.h" #include "Button.h" #include "ObjectMacros.h" -#include "StopWatch.h" +#include "Stopwatch.h" #include "ShaderEmbed.h" #include "WordList.h" #include "TextGeneration.h" diff --git a/src/nfd_wrapper.cpp b/src/nfd_wrapper.cpp deleted file mode 100644 index e67f3d6..0000000 --- a/src/nfd_wrapper.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "nfd_wrapper.h" -std::string select_file(std::string filter) -{ - nfdchar_t *outPath = NULL; - nfdresult_t result = NFD_OpenDialog( filter.c_str(), NULL, &outPath ); - if ( result == NFD_OKAY ) - { - return std::string(outPath); - } - else if ( result == NFD_CANCEL ) - { - return "!C"; - } - else - { - return "!E:" + std::string(NFD_GetError()); - } -} - -// defualt path not working -std::string select_file(std::string default_path, std::string filter) -{ - nfdchar_t *outPath = NULL; - nfdresult_t result = NFD_OpenDialog( filter.c_str(), default_path.c_str(), &outPath ); - if ( result == NFD_OKAY ) - { - return std::string(outPath); - } - else if ( result == NFD_CANCEL ) - { - return "!C"; - } - else - { - return "!E:" + std::string(NFD_GetError()); - } -} diff --git a/src/nfd_wrapper.h b/src/nfd_wrapper.h deleted file mode 100644 index 8a069aa..0000000 --- a/src/nfd_wrapper.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include -#include "nfd.h" -std::string select_file(std::string filter); -std::string select_file(std::string default_path, std::string filter); \ No newline at end of file