Merge commit '6e9eb898f5c6e241591d4953ae0b36668cd59f94' as 'external/nfd'

This commit is contained in:
SimoZ64
2025-05-04 00:37:23 +02:00
48 changed files with 8052 additions and 0 deletions

46
external/nfd/test/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,46 @@
if(${NFD_BUILD_TESTS})
set(TEST_LIST
test_opendialog.c
test_opendialog_cpp.cpp
test_opendialog_native.c
test_opendialog_with.c
test_opendialog_native_with.c
test_opendialogmultiple.c
test_opendialogmultiple_cpp.cpp
test_opendialogmultiple_native.c
test_opendialogmultiple_enum.c
test_opendialogmultiple_enum_native.c
test_pickfolder.c
test_pickfolder_cpp.cpp
test_pickfolder_native.c
test_pickfolder_with.c
test_pickfolder_native_with.c
test_pickfoldermultiple.c
test_pickfoldermultiple_native.c
test_savedialog.c
test_savedialog_native.c
test_savedialog_with.c
test_savedialog_native_with.c)
foreach (TEST ${TEST_LIST})
string(REPLACE "." "_" CLEAN_TEST_NAME ${TEST})
add_executable(${CLEAN_TEST_NAME}
${TEST})
target_link_libraries(${CLEAN_TEST_NAME}
PRIVATE nfd)
endforeach()
endif()
if(${NFD_BUILD_SDL2_TESTS})
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2 SDL2_ttf)
if(WIN32)
add_executable(test_sdl2 WIN32 test_sdl.c test_sdl.manifest)
else()
add_executable(test_sdl2 test_sdl.c)
endif()
target_link_libraries(test_sdl2 PRIVATE nfd)
target_include_directories(test_sdl2 PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(test_sdl2 PRIVATE ${SDL2_LINK_LIBRARIES})
target_compile_options(test_sdl2 PUBLIC ${SDL2_CFLAGS_OTHER})
endif()

36
external/nfd/test/test_opendialog.c vendored Normal file
View File

@@ -0,0 +1,36 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
// show the dialog
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 2, NULL);
if (result == NFD_OKAY) {
puts("Success!");
puts(outPath);
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,29 @@
#include <iostream>
#include "nfd.hpp"
/* this test should compile on all supported platforms */
/* this demonstrates the thin C++ wrapper */
int main() {
// initialize NFD
NFD::Guard nfdGuard;
// auto-freeing memory
NFD::UniquePath outPath;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
// show the dialog
nfdresult_t result = NFD::OpenDialog(outPath, filterItem, 2);
if (result == NFD_OKAY) {
std::cout << "Success!" << std::endl << outPath.get() << std::endl;
} else if (result == NFD_CANCEL) {
std::cout << "User pressed cancel." << std::endl;
} else {
std::cout << "Error: " << NFD::GetError() << std::endl;
}
// NFD::Guard will automatically quit NFD.
return 0;
}

View File

@@ -0,0 +1,49 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// prepare filters for the dialog
#ifdef _WIN32
nfdfilteritem_t filterItem[2] = {{L"Source code", L"c,cpp,cc"}, {L"Headers", L"h,hpp"}};
#else
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
#endif
// show the dialog
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 2, NULL);
if (result == NFD_OKAY) {
puts("Success!");
#ifdef _WIN32
#ifdef _MSC_VER
_putws(outPath);
#else
fputws(outPath, stdin);
#endif
#else
puts(outPath);
#endif
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,52 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// prepare filters for the dialog
#ifdef _WIN32
nfdfilteritem_t filterItem[2] = {{L"Source code", L"c,cpp,cc"}, {L"Headers", L"h,hpp"}};
#else
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
#endif
// show the dialog
nfdopendialognargs_t args = {0};
args.filterList = filterItem;
args.filterCount = 2;
nfdresult_t result = NFD_OpenDialogN_With(&outPath, &args);
if (result == NFD_OKAY) {
puts("Success!");
#ifdef _WIN32
#ifdef _MSC_VER
_putws(outPath);
#else
fputws(outPath, stdin);
#endif
#else
puts(outPath);
#endif
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,39 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
// show the dialog
nfdopendialogu8args_t args = {0};
args.filterList = filterItem;
args.filterCount = 2;
nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY) {
puts("Success!");
puts(outPath);
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,50 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
const nfdpathset_t* outPaths;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
// show the dialog
nfdresult_t result = NFD_OpenDialogMultiple(&outPaths, filterItem, 2, NULL);
if (result == NFD_OKAY) {
puts("Success!");
nfdpathsetsize_t numPaths;
NFD_PathSet_GetCount(outPaths, &numPaths);
nfdpathsetsize_t i;
for (i = 0; i < numPaths; ++i) {
nfdchar_t* path;
NFD_PathSet_GetPath(outPaths, i, &path);
printf("Path %i: %s\n", (int)i, path);
// remember to free the pathset path with NFD_PathSet_FreePath (not NFD_FreePath!)
NFD_PathSet_FreePath(path);
}
// remember to free the pathset memory (since NFD_OKAY is returned)
NFD_PathSet_Free(outPaths);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,40 @@
#include "nfd.hpp"
#include <iostream>
/* this test should compile on all supported platforms */
/* this demonstrates the thin C++ wrapper */
int main() {
// initialize NFD
NFD::Guard nfdGuard;
// auto-freeing memory
NFD::UniquePathSet outPaths;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
// show the dialog
nfdresult_t result = NFD::OpenDialogMultiple(outPaths, filterItem, 2);
if (result == NFD_OKAY) {
std::cout << "Success!" << std::endl;
nfdpathsetsize_t numPaths;
NFD::PathSet::Count(outPaths, numPaths);
nfdpathsetsize_t i;
for (i = 0; i < numPaths; ++i) {
NFD::UniquePathSetPath path;
NFD::PathSet::GetPath(outPaths, i, path);
std::cout << "Path " << i << ": " << path.get() << std::endl;
}
} else if (result == NFD_CANCEL) {
std::cout << "User pressed cancel." << std::endl;
} else {
std::cout << "Error: " << NFD::GetError() << std::endl;
}
// NFD::Guard will automatically quit NFD.
return 0;
}

View File

@@ -0,0 +1,53 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
const nfdpathset_t* outPaths;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
// show the dialog
nfdresult_t result = NFD_OpenDialogMultiple(&outPaths, filterItem, 2, NULL);
if (result == NFD_OKAY) {
puts("Success!");
// declare enumerator (not a pointer)
nfdpathsetenum_t enumerator;
NFD_PathSet_GetEnum(outPaths, &enumerator);
nfdchar_t* path;
unsigned i = 0;
while (NFD_PathSet_EnumNext(&enumerator, &path) && path) {
printf("Path %u: %s\n", i++, path);
// remember to free the pathset path with NFD_PathSet_FreePath (not NFD_FreePath!)
NFD_PathSet_FreePath(path);
}
// remember to free the pathset enumerator memory (before freeing the pathset)
NFD_PathSet_FreeEnum(&enumerator);
// remember to free the pathset memory (since NFD_OKAY is returned)
NFD_PathSet_Free(outPaths);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,62 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
const nfdpathset_t* outPaths;
// prepare filters for the dialog
#ifdef _WIN32
nfdfilteritem_t filterItem[2] = {{L"Source code", L"c,cpp,cc"}, {L"Headers", L"h,hpp"}};
#else
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
#endif
// show the dialog
nfdresult_t result = NFD_OpenDialogMultiple(&outPaths, filterItem, 2, NULL);
if (result == NFD_OKAY) {
puts("Success!");
// declare enumerator (not a pointer)
nfdpathsetenum_t enumerator;
NFD_PathSet_GetEnum(outPaths, &enumerator);
nfdchar_t* path;
unsigned i = 0;
while (NFD_PathSet_EnumNext(&enumerator, &path) && path) {
#ifdef _WIN32
wprintf(L"Path %u: %s\n", i++, path);
#else
printf("Path %u: %s\n", i++, path);
#endif
// remember to free the pathset path with NFD_PathSet_FreePath (not NFD_FreePath!)
NFD_PathSet_FreePath(path);
}
// remember to free the pathset enumerator memory (before freeing the pathset)
NFD_PathSet_FreeEnum(&enumerator);
// remember to free the pathset memory (since NFD_OKAY is returned)
NFD_PathSet_Free(outPaths);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,59 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
const nfdpathset_t* outPaths;
// prepare filters for the dialog
#ifdef _WIN32
nfdfilteritem_t filterItem[2] = {{L"Source code", L"c,cpp,cc"}, {L"Headers", L"h,hpp"}};
#else
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
#endif
// show the dialog
nfdresult_t result = NFD_OpenDialogMultiple(&outPaths, filterItem, 2, NULL);
if (result == NFD_OKAY) {
puts("Success!");
nfdpathsetsize_t numPaths;
NFD_PathSet_GetCount(outPaths, &numPaths);
nfdpathsetsize_t i;
for (i = 0; i < numPaths; ++i) {
nfdchar_t* path;
NFD_PathSet_GetPath(outPaths, i, &path);
#ifdef _WIN32
wprintf(L"Path %i: %s\n", (int)i, path);
#else
printf("Path %i: %s\n", (int)i, path);
#endif
// remember to free the pathset path with NFD_PathSet_FreePath (not NFD_FreePath!)
NFD_PathSet_FreePath(path);
}
// remember to free the pathset memory (since NFD_OKAY is returned)
NFD_PathSet_Free(outPaths);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

33
external/nfd/test/test_pickfolder.c vendored Normal file
View File

@@ -0,0 +1,33 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// show the dialog
nfdresult_t result = NFD_PickFolder(&outPath, NULL);
if (result == NFD_OKAY) {
puts("Success!");
puts(outPath);
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,27 @@
#include "nfd.hpp"
#include <iostream>
/* this test should compile on all supported platforms */
/* this demonstrates the thin C++ wrapper */
int main() {
// initialize NFD
NFD::Guard nfdGuard;
// auto-freeing memory
NFD::UniquePath outPath;
// show the dialog
nfdresult_t result = NFD::PickFolder(outPath);
if (result == NFD_OKAY) {
std::cout << "Success!" << std::endl << outPath.get() << std::endl;
} else if (result == NFD_CANCEL) {
std::cout << "User pressed cancel." << std::endl;
} else {
std::cout << "Error: " << NFD::GetError() << std::endl;
}
// NFD::Guard will automatically quit NFD.
return 0;
}

View File

@@ -0,0 +1,42 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// show the dialog
nfdresult_t result = NFD_PickFolder(&outPath, NULL);
if (result == NFD_OKAY) {
puts("Success!");
#ifdef _WIN32
#ifdef _MSC_VER
_putws(outPath);
#else
fputws(outPath, stdin);
#endif
#else
puts(outPath);
#endif
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,43 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// show the dialog
nfdpickfoldernargs_t args = {0};
nfdresult_t result = NFD_PickFolderN_With(&outPath, &args);
if (result == NFD_OKAY) {
puts("Success!");
#ifdef _WIN32
#ifdef _MSC_VER
_putws(outPath);
#else
fputws(outPath, stdin);
#endif
#else
puts(outPath);
#endif
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,34 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* outPath;
// show the dialog
nfdpickfolderu8args_t args = {0};
nfdresult_t result = NFD_PickFolderU8_With(&outPath, &args);
if (result == NFD_OKAY) {
puts("Success!");
puts(outPath);
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,47 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
const nfdpathset_t* outPaths;
// show the dialog
nfdresult_t result = NFD_PickFolderMultiple(&outPaths, NULL);
if (result == NFD_OKAY) {
puts("Success!");
nfdpathsetsize_t numPaths;
NFD_PathSet_GetCount(outPaths, &numPaths);
nfdpathsetsize_t i;
for (i = 0; i < numPaths; ++i) {
nfdchar_t* path;
NFD_PathSet_GetPath(outPaths, i, &path);
printf("Path %i: %s\n", (int)i, path);
// remember to free the pathset path with NFD_PathSet_FreePath (not NFD_FreePath!)
NFD_PathSet_FreePath(path);
}
// remember to free the pathset memory (since NFD_OKAY is returned)
NFD_PathSet_Free(outPaths);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,52 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
const nfdpathset_t* outPaths;
// show the dialog
nfdresult_t result = NFD_PickFolderMultiple(&outPaths, NULL);
if (result == NFD_OKAY) {
puts("Success!");
nfdpathsetsize_t numPaths;
NFD_PathSet_GetCount(outPaths, &numPaths);
nfdpathsetsize_t i;
for (i = 0; i < numPaths; ++i) {
nfdchar_t* path;
NFD_PathSet_GetPath(outPaths, i, &path);
#ifdef _WIN32
wprintf(L"Path %i: %s\n", (int)i, path);
#else
printf("Path %i: %s\n", (int)i, path);
#endif
// remember to free the pathset path with NFD_PathSet_FreePath (not NFD_FreePath!)
NFD_PathSet_FreePath(path);
}
// remember to free the pathset memory (since NFD_OKAY is returned)
NFD_PathSet_Free(outPaths);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

36
external/nfd/test/test_savedialog.c vendored Normal file
View File

@@ -0,0 +1,36 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* savePath;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Header", "h,hpp"}};
// show the dialog
nfdresult_t result = NFD_SaveDialog(&savePath, filterItem, 2, NULL, "Untitled.c");
if (result == NFD_OKAY) {
puts("Success!");
puts(savePath);
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(savePath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,55 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* savePath;
// prepare filters for the dialog
#ifdef _WIN32
nfdfilteritem_t filterItem[2] = {{L"Source code", L"c,cpp,cc"}, {L"Headers", L"h,hpp"}};
#else
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
#endif
#ifdef _WIN32
const wchar_t* defaultPath = L"Untitled.c";
#else
const char* defaultPath = "Untitled.c";
#endif
// show the dialog
nfdresult_t result = NFD_SaveDialog(&savePath, filterItem, 2, NULL, defaultPath);
if (result == NFD_OKAY) {
puts("Success!");
#ifdef _WIN32
#ifdef _MSC_VER
_putws(savePath);
#else
fputws(savePath, stdin);
#endif
#else
puts(savePath);
#endif
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(savePath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,59 @@
#define NFD_NATIVE
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* savePath;
// prepare filters for the dialog
#ifdef _WIN32
nfdfilteritem_t filterItem[2] = {{L"Source code", L"c,cpp,cc"}, {L"Headers", L"h,hpp"}};
#else
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Headers", "h,hpp"}};
#endif
#ifdef _WIN32
const wchar_t* defaultPath = L"Untitled.c";
#else
const char* defaultPath = "Untitled.c";
#endif
// show the dialog
nfdsavedialognargs_t args = {0};
args.filterList = filterItem;
args.filterCount = 2;
args.defaultName = defaultPath;
nfdresult_t result = NFD_SaveDialogN_With(&savePath, &args);
if (result == NFD_OKAY) {
puts("Success!");
#ifdef _WIN32
#ifdef _MSC_VER
_putws(savePath);
#else
fputws(savePath, stdin);
#endif
#else
puts(savePath);
#endif
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(savePath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

View File

@@ -0,0 +1,40 @@
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
/* this test should compile on all supported platforms */
int main(void) {
// initialize NFD
// either call NFD_Init at the start of your program and NFD_Quit at the end of your program,
// or before/after every time you want to show a file dialog.
NFD_Init();
nfdchar_t* savePath;
// prepare filters for the dialog
nfdfilteritem_t filterItem[2] = {{"Source code", "c,cpp,cc"}, {"Header", "h,hpp"}};
// show the dialog
nfdsavedialogu8args_t args = {0};
args.filterList = filterItem;
args.filterCount = 2;
args.defaultName = "Untitled.c";
nfdresult_t result = NFD_SaveDialogU8_With(&savePath, &args);
if (result == NFD_OKAY) {
puts("Success!");
puts(savePath);
// remember to free the memory (since NFD_OKAY is returned)
NFD_FreePath(savePath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
// Quit NFD
NFD_Quit();
return 0;
}

414
external/nfd/test/test_sdl.c vendored Normal file
View File

@@ -0,0 +1,414 @@
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include <SDL_ttf.h>
#include <nfd.h>
#include <nfd_sdl2.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
// Small program meant to demonstrate and test nfd_sdl2.h with SDL2. Note that it quits immediately
// when it encounters an error, without calling the opposite destroy/quit function. A real-world
// application should call destroy/quit appropriately.
void show_error(const char* message, SDL_Window* window) {
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", message, window) != 0) {
printf("SDL_ShowSimpleMessageBox failed: %s\n", SDL_GetError());
return;
}
}
void show_path(const char* path, SDL_Window* window) {
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Success", path, window) != 0) {
printf("SDL_ShowSimpleMessageBox failed: %s\n", SDL_GetError());
return;
}
}
void show_paths(const nfdpathset_t* paths, SDL_Window* window) {
size_t num_chars = 0;
nfdpathsetsize_t num_paths;
if (NFD_PathSet_GetCount(paths, &num_paths) != NFD_OKAY) {
printf("NFD_PathSet_GetCount failed: %s\n", NFD_GetError());
return;
}
nfdpathsetsize_t i;
for (i = 0; i != num_paths; ++i) {
char* path;
if (NFD_PathSet_GetPathU8(paths, i, &path) != NFD_OKAY) {
printf("NFD_PathSet_GetPathU8 failed: %s\n", NFD_GetError());
return;
}
num_chars += strlen(path) + 1;
NFD_PathSet_FreePathU8(path);
}
// We should never return NFD_OKAY with zero paths, but GCC doesn't know this and will emit a
// warning that we're trying to malloc with size zero if we write the following line.
if (!num_paths) num_chars = 1;
char* message = malloc(num_chars);
message[0] = '\0';
for (i = 0; i != num_paths; ++i) {
if (i != 0) {
strcat(message, "\n");
}
char* path;
if (NFD_PathSet_GetPathU8(paths, i, &path) != NFD_OKAY) {
printf("NFD_PathSet_GetPathU8 failed: %s\n", NFD_GetError());
free(message);
return;
}
strcat(message, path);
NFD_PathSet_FreePathU8(path);
}
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Success", message, window) != 0) {
printf("SDL_ShowSimpleMessageBox failed: %s\n", SDL_GetError());
free(message);
return;
}
free(message);
}
void set_native_window(SDL_Window* sdlWindow, nfdwindowhandle_t* nativeWindow) {
if (!NFD_GetNativeWindowFromSDLWindow(sdlWindow, nativeWindow)) {
printf("NFD_GetNativeWindowFromSDLWindow failed: %s\n", SDL_GetError());
}
}
void opendialog_handler(SDL_Window* window) {
char* path;
nfdopendialogu8args_t args = {0};
set_native_window(window, &args.parentWindow);
const nfdresult_t res = NFD_OpenDialogU8_With(&path, &args);
switch (res) {
case NFD_OKAY:
show_path(path, window);
NFD_FreePathU8(path);
break;
case NFD_ERROR:
show_error(NFD_GetError(), window);
break;
default:
break;
}
}
void opendialogmultiple_handler(SDL_Window* window) {
const nfdpathset_t* paths;
nfdopendialogu8args_t args = {0};
set_native_window(window, &args.parentWindow);
const nfdresult_t res = NFD_OpenDialogMultipleU8_With(&paths, &args);
switch (res) {
case NFD_OKAY:
show_paths(paths, window);
NFD_PathSet_Free(paths);
break;
case NFD_ERROR:
show_error(NFD_GetError(), window);
break;
default:
break;
}
}
void savedialog_handler(SDL_Window* window) {
char* path;
nfdsavedialogu8args_t args = {0};
set_native_window(window, &args.parentWindow);
const nfdresult_t res = NFD_SaveDialogU8_With(&path, &args);
switch (res) {
case NFD_OKAY:
show_path(path, window);
NFD_FreePathU8(path);
break;
case NFD_ERROR:
show_error(NFD_GetError(), window);
break;
default:
break;
}
}
void pickfolder_handler(SDL_Window* window) {
char* path;
nfdpickfolderu8args_t args = {0};
set_native_window(window, &args.parentWindow);
const nfdresult_t res = NFD_PickFolderU8_With(&path, &args);
switch (res) {
case NFD_OKAY:
show_path(path, window);
NFD_FreePathU8(path);
break;
case NFD_ERROR:
show_error(NFD_GetError(), window);
break;
default:
break;
}
}
void pickfoldermultiple_handler(SDL_Window* window) {
const nfdpathset_t* paths;
nfdpickfolderu8args_t args = {0};
set_native_window(window, &args.parentWindow);
const nfdresult_t res = NFD_PickFolderMultipleU8_With(&paths, &args);
switch (res) {
case NFD_OKAY:
show_paths(paths, window);
NFD_PathSet_Free(paths);
break;
case NFD_ERROR:
show_error(NFD_GetError(), window);
break;
default:
break;
}
}
#if defined(_WIN32)
const char font_file[] = "C:\\Windows\\Fonts\\calibri.ttf";
#elif defined(__APPLE__)
const char font_file[] = "/System/Library/Fonts/SFNS.ttf";
#else
const char font_file[] = "/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf";
#endif
#define NUM_STATES 3
#define NUM_BUTTONS 5
const char* button_text[NUM_BUTTONS] = {"Open File",
"Open Files",
"Save File",
"Select Folder",
"Select Folders"};
const int BUTTON_WIDTH = 400;
const int BUTTON_HEIGHT = 40;
void (*button_handler[NUM_BUTTONS])(SDL_Window*) = {&opendialog_handler,
&opendialogmultiple_handler,
&savedialog_handler,
&pickfolder_handler,
&pickfoldermultiple_handler};
#ifdef _WIN32
int WINAPI WinMain(void)
#else
int main(void)
#endif
{
#ifdef _WIN32
// Enable DPI awareness on Windows
SDL_SetHint("SDL_HINT_WINDOWS_DPI_AWARENESS", "permonitorv2");
SDL_SetHint("SDL_HINT_WINDOWS_DPI_SCALING", "1");
#endif
// initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("SDL_Init failed: %s\n", SDL_GetError());
return 0;
}
// initialize SDL_ttf
if (TTF_Init() != 0) {
printf("TTF_Init failed: %s\n", TTF_GetError());
return 0;
}
// initialize NFD
if (NFD_Init() != NFD_OKAY) {
printf("NFD_Init failed: %s\n", NFD_GetError());
return 0;
}
// create window
SDL_Window* const window = SDL_CreateWindow("Welcome",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
BUTTON_WIDTH,
BUTTON_HEIGHT * NUM_BUTTONS,
SDL_WINDOW_ALLOW_HIGHDPI);
if (!window) {
printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
return 0;
}
// create renderer
SDL_Renderer* const renderer =
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (!renderer) {
printf("SDL_CreateRenderer failed: %s\n", SDL_GetError());
return 0;
}
// prepare the buttons and handlers
SDL_Texture* textures_normal[NUM_BUTTONS][NUM_STATES];
TTF_Font* const font = TTF_OpenFont(font_file, 20);
if (!font) {
printf("TTF_OpenFont failed: %s\n", TTF_GetError());
return 0;
}
const SDL_Color back_color[NUM_STATES] = {{0, 0, 0, SDL_ALPHA_OPAQUE},
{51, 51, 51, SDL_ALPHA_OPAQUE},
{102, 102, 102, SDL_ALPHA_OPAQUE}};
const SDL_Color text_color = {255, 255, 255, SDL_ALPHA_OPAQUE};
const uint8_t text_alpha[NUM_STATES] = {153, 204, 255};
for (size_t i = 0; i != NUM_BUTTONS; ++i) {
SDL_Surface* const text_surface = TTF_RenderUTF8_Blended(font, button_text[i], text_color);
if (!text_surface) {
printf("TTF_RenderUTF8_Blended failed: %s\n", TTF_GetError());
return 0;
}
if (SDL_SetSurfaceBlendMode(text_surface, SDL_BLENDMODE_BLEND) != 0) {
printf("SDL_SetSurfaceBlendMode failed: %s\n", SDL_GetError());
return 0;
}
for (size_t j = 0; j != NUM_STATES; ++j) {
SDL_Surface* button_surface =
SDL_CreateRGBSurface(0, BUTTON_WIDTH, BUTTON_HEIGHT, 32, 0, 0, 0, 0);
if (!button_surface) {
printf("SDL_CreateRGBSurface failed: %s\n", SDL_GetError());
return 0;
}
if (SDL_FillRect(button_surface,
NULL,
SDL_MapRGBA(button_surface->format,
back_color[j].r,
back_color[j].g,
back_color[j].b,
back_color[j].a)) != 0) {
printf("SDL_FillRect failed: %s\n", SDL_GetError());
return 0;
}
SDL_SetSurfaceAlphaMod(text_surface, text_alpha[j]);
SDL_Rect dstrect = {(BUTTON_WIDTH - text_surface->w) / 2,
(BUTTON_HEIGHT - text_surface->h) / 2,
text_surface->w,
text_surface->h};
if (SDL_BlitSurface(text_surface, NULL, button_surface, &dstrect) != 0) {
printf("SDL_BlitSurface failed: %s\n", SDL_GetError());
return 0;
}
SDL_Texture* const texture = SDL_CreateTextureFromSurface(renderer, button_surface);
if (!texture) {
printf("SDL_CreateTextureFromSurface failed: %s\n", SDL_GetError());
return 0;
}
SDL_FreeSurface(button_surface);
textures_normal[i][j] = texture;
}
SDL_FreeSurface(text_surface);
}
TTF_CloseFont(font);
// event loop
bool quit = false;
size_t button_index = (size_t)-1;
bool pressed = false;
do {
// render
for (size_t i = 0; i != NUM_BUTTONS; ++i) {
const SDL_Rect rect = {0, (int)i * BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT};
SDL_RenderCopy(
renderer, textures_normal[i][button_index == i ? pressed ? 2 : 1 : 0], NULL, &rect);
}
SDL_RenderPresent(renderer);
// process events
SDL_Event event;
if (SDL_WaitEvent(&event) == 0) {
printf("SDL_WaitEvent failed: %s\n", SDL_GetError());
return 0;
}
do {
switch (event.type) {
case SDL_QUIT: {
quit = true;
break;
}
case SDL_WINDOWEVENT: {
switch (event.window.event) {
case SDL_WINDOWEVENT_CLOSE:
quit = true;
break;
case SDL_WINDOWEVENT_LEAVE:
button_index = (size_t)-1;
break;
}
break;
}
case SDL_MOUSEMOTION: {
if (event.motion.x < 0 || event.motion.x >= BUTTON_WIDTH ||
event.motion.y < 0) {
button_index = (size_t)-1;
break;
}
const int index = event.motion.y / BUTTON_HEIGHT;
if (index < 0 || index >= NUM_BUTTONS) {
button_index = (size_t)-1;
break;
}
button_index = index;
pressed = event.motion.state & SDL_BUTTON(1);
break;
}
case SDL_MOUSEBUTTONDOWN: {
if (event.button.button == 1) {
pressed = true;
}
break;
}
case SDL_MOUSEBUTTONUP: {
if (event.button.button == 1) {
pressed = false;
if (button_index != (size_t)-1) {
(*button_handler[button_index])(window);
}
}
break;
}
}
} while (SDL_PollEvent(&event) != 0);
} while (!quit);
// destroy textures
for (size_t i = 0; i != NUM_BUTTONS; ++i) {
for (size_t j = 0; j != NUM_STATES; ++j) {
SDL_DestroyTexture(textures_normal[i][j]);
}
}
// destroy renderer
SDL_DestroyRenderer(renderer);
// destroy window
SDL_DestroyWindow(window);
// quit NFD
NFD_Quit();
// quit SDL_ttf
TTF_Quit();
// quit SDL
SDL_Quit();
return 0;
}

29
external/nfd/test/test_sdl.manifest vendored Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="CompanyName.ProductName.YourApp"
type="win32"
/>
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
<description>Example application for NFDe.</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>