Files
armorpaint/base/sources/libs/nfd.m
T

278 lines
7.5 KiB
Objective-C
Raw Normal View History

2025-03-11 15:17:26 +01:00
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// https://github.com/mlabbe/nativefiledialog
2024-11-10 22:11:29 +01:00
#include <AppKit/AppKit.h>
#include "nfd.h"
2025-03-11 15:17:26 +01:00
static NSArray *BuildAllowedFileTypes( const char *filterList ) {
2025-08-07 21:40:13 +02:00
// 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' )
{
*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];
2024-11-10 22:11:29 +01:00
// [buildFilterList release];
2025-08-07 21:40:13 +02:00
return returnArray;
2024-11-10 22:11:29 +01:00
}
2025-03-11 15:17:26 +01:00
static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList ) {
2025-08-07 21:40:13 +02:00
if ( !filterList || strlen(filterList) == 0 )
return;
NSArray *allowedFileTypes = BuildAllowedFileTypes( filterList );
if ( [allowedFileTypes count] != 0 )
{
[dialog setAllowedFileTypes:allowedFileTypes];
}
2024-11-10 22:11:29 +01:00
}
2025-03-11 15:17:26 +01:00
static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath ) {
2025-08-07 21:40:13 +02:00
if ( !defaultPath || strlen(defaultPath) == 0 )
return;
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath];
NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES];
[dialog setDirectoryURL:url];
2024-11-10 22:11:29 +01:00
}
/* fixme: pathset should be pathSet */
2025-03-11 15:17:26 +01:00
static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) {
2025-08-07 21:40:13 +02:00
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;
2024-11-10 22:11:29 +01:00
}
nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList,
2025-08-07 21:40:13 +02:00
const nfdchar_t *defaultPath,
nfdchar_t **outPath ) {
2024-11-10 22:11:29 +01:00
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2025-08-07 21:40:13 +02:00
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
NSOpenPanel *dialog = [NSOpenPanel openPanel];
[dialog setAllowsMultipleSelection:NO];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// Build the filter list
AddFilterListToDialog(dialog, filterList);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// Set the starting directory
SetDefaultPath(dialog, defaultPath);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
nfdresult_t nfdResult = NFD_CANCEL;
if ( [dialog runModal] == NSModalResponseOK )
{
NSURL *url = [dialog URL];
const char *utf8Path = [[url path] UTF8String];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// byte count, not char count
size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
*outPath = NFDi_Malloc( len+1 );
if ( !*outPath )
{
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return NFD_ERROR;
}
memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
nfdResult = NFD_OKAY;
}
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return nfdResult;
2024-11-10 22:11:29 +01:00
}
nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
2025-08-07 21:40:13 +02:00
const nfdchar_t *defaultPath,
nfdpathset_t *outPaths ) {
2024-11-10 22:11:29 +01:00
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2025-08-07 21:40:13 +02:00
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
2025-03-11 15:17:26 +01:00
2025-08-07 21:40:13 +02:00
NSOpenPanel *dialog = [NSOpenPanel openPanel];
[dialog setAllowsMultipleSelection:YES];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// Build the fiter list.
AddFilterListToDialog(dialog, filterList);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// Set the starting directory
SetDefaultPath(dialog, defaultPath);
2025-03-11 15:17:26 +01:00
2025-08-07 21:40:13 +02:00
nfdresult_t nfdResult = NFD_CANCEL;
if ( [dialog runModal] == NSModalResponseOK )
{
NSArray *urls = [dialog URLs];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
if ( [urls count] == 0 )
{
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return NFD_CANCEL;
}
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
if ( AllocPathSet( urls, outPaths ) == NFD_ERROR )
{
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return NFD_ERROR;
}
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
nfdResult = NFD_OKAY;
}
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return nfdResult;
2024-11-10 22:11:29 +01:00
}
nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
2025-08-07 21:40:13 +02:00
const nfdchar_t *defaultPath,
nfdchar_t **outPath ) {
2024-11-10 22:11:29 +01:00
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2025-08-07 21:40:13 +02:00
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
2025-03-11 15:17:26 +01:00
2025-08-07 21:40:13 +02:00
NSSavePanel *dialog = [NSSavePanel savePanel];
[dialog setExtensionHidden:NO];
2025-03-11 15:17:26 +01:00
2025-08-07 21:40:13 +02:00
// Build the filter list.
AddFilterListToDialog(dialog, filterList);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// Set the starting directory
SetDefaultPath(dialog, defaultPath);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
nfdresult_t nfdResult = NFD_CANCEL;
if ( [dialog runModal] == NSModalResponseOK )
{
NSURL *url = [dialog URL];
const char *utf8Path = [[url path] UTF8String];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
2025-03-11 15:17:26 +01:00
2025-08-07 21:40:13 +02:00
*outPath = NFDi_Malloc( byteLen );
if ( !*outPath )
{
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return NFD_ERROR;
}
memcpy( *outPath, utf8Path, byteLen );
nfdResult = NFD_OKAY;
}
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return nfdResult;
2024-11-10 22:11:29 +01:00
}
nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
2025-08-07 21:40:13 +02:00
nfdchar_t **outPath) {
2024-11-10 22:11:29 +01:00
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2025-08-07 21:40:13 +02:00
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
NSOpenPanel *dialog = [NSOpenPanel openPanel];
[dialog setAllowsMultipleSelection:NO];
[dialog setCanChooseDirectories:YES];
[dialog setCanCreateDirectories:YES];
[dialog setCanChooseFiles:NO];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// Set the starting directory
SetDefaultPath(dialog, defaultPath);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
nfdresult_t nfdResult = NFD_CANCEL;
if ( [dialog runModal] == NSModalResponseOK )
{
NSURL *url = [dialog URL];
const char *utf8Path = [[url path] UTF8String];
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
// byte count, not char count
size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
2024-11-10 22:11:29 +01:00
2025-08-07 21:40:13 +02:00
*outPath = NFDi_Malloc( len+1 );
if ( !*outPath )
{
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return NFD_ERROR;
}
memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
nfdResult = NFD_OKAY;
}
2024-11-10 22:11:29 +01:00
// [pool release];
2025-08-07 21:40:13 +02:00
[keyWindow makeKeyAndOrderFront:nil];
return nfdResult;
2024-11-10 22:11:29 +01:00
}