99enum class opt : uint8_t {
112 return opt(uint8_t(a) | uint8_t(b));
115 return bool(uint8_t(a) & uint8_t(b));
124 static void verbose(
bool value);
128 explicit settings(
bool resync =
false);
160 static int const default_wait_timeout = 20;
167 std::string
result(
int* exit_code =
nullptr);
173 void start_func(std::function<std::string(
int*)>
const& fun);
174 static BOOL CALLBACK enum_windows_callback(HWND hwnd, LPARAM lParam);
176 void start(
int exit_code);
184 bool ready(
int timeout = default_wait_timeout);
192 std::future<std::string> m_future;
193 std::set<HWND> m_windows;
194 std::condition_variable m_cond;
197#elif __EMSCRIPTEN__ || __NX__
211 dll(std::string
const& name);
214 template <
typename T>
217 proc(dll
const& lib, std::string
const& sym)
218 : m_proc(
reinterpret_cast<T*
>((
void*) ::GetProcAddress(lib.handle, sym.c_str()))) {}
220 operator bool()
const {
return m_proc !=
nullptr; }
221 operator T*()
const {
return m_proc; }
232 class ole32_dll :
public dll {
236 bool is_initialized();
243 class new_style_context {
246 ~new_style_context();
250 ULONG_PTR m_cookie = 0;
257 bool ready(
int timeout = default_wait_timeout)
const;
269 std::string
shell_quote(std::string
const& str)
const;
283 file_dialog(
type in_type, std::string
const& title, std::string
const& default_path =
"",
284 std::vector<std::string>
const& filters = {},
opt options =
opt::none);
291 static int CALLBACK bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData);
292#if PFD_HAS_IFILEDIALOG
293 std::string select_folder_vista(IFileDialog* ifd,
bool force_path);
296 std::wstring m_wtitle;
297 std::wstring m_wdefault_path;
299 std::vector<std::string> m_vector_result;
311 static std::string
home();
346 open_file(std::string
const& title, std::string
const& default_path =
"",
347 std::vector<std::string>
const& filters = {
"All Files",
"*"},
opt options =
opt::none);
349#if defined(__has_cpp_attribute)
350#if __has_cpp_attribute(deprecated)
352 [[deprecated(
"Use pfd::opt::multiselect instead of allow_multiselect")]]
355 open_file(std::string
const& title, std::string
const& default_path,
356 std::vector<std::string>
const& filters,
bool allow_multiselect);
358 std::vector<std::string>
result();
363 save_file(std::string
const& title, std::string
const& default_path =
"",
364 std::vector<std::string>
const& filters = {
"All Files",
"*"},
opt options =
opt::none);
366#if defined(__has_cpp_attribute)
367#if __has_cpp_attribute(deprecated)
369 [[deprecated(
"Use pfd::opt::force_overwrite instead of confirm_overwrite")]]
372 save_file(std::string
const& title, std::string
const& default_path,
373 std::vector<std::string>
const& filters,
bool confirm_overwrite);
380 select_folder(std::string
const& title, std::string
const& default_path =
"",
392#if !defined PFD_SKIP_IMPLEMENTATION
399 static inline std::wstring str2wstr(std::string
const& str) {
400 int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (
int) str.size(),
nullptr, 0);
401 std::wstring ret(len,
'\0');
402 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (
int) str.size(), (LPWSTR) ret.data(),
407 static inline std::string wstr2str(std::wstring
const& str) {
408 int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (
int) str.size(),
nullptr, 0,
nullptr,
410 std::string ret(len,
'\0');
411 WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (
int) str.size(), (LPSTR) ret.data(),
412 (
int) ret.size(),
nullptr,
nullptr);
416 static inline bool is_vista() {
417 OSVERSIONINFOEXW osvi;
418 memset(&osvi, 0,
sizeof(osvi));
419 DWORDLONG
const mask = VerSetConditionMask(
420 VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL),
421 VER_MINORVERSION, VER_GREATER_EQUAL),
422 VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
423 osvi.dwOSVersionInfoSize =
sizeof(osvi);
424 osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA);
425 osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA);
426 osvi.wServicePackMajor = 0;
428 return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
435 static inline bool ends_with(std::string
const& str, std::string
const& suffix) {
436 return suffix.size() <= str.size() &&
437 str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
440 static inline bool starts_with(std::string
const& str, std::string
const& prefix) {
441 return prefix.size() <= str.size() && str.compare(0, prefix.size(), prefix) == 0;
446 static inline bool is_directory(std::string
const& path) {
448 auto attr = GetFileAttributesA(path.c_str());
449 return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
455 return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode);
461 static inline std::string getenv(std::string
const& str) {
465 if (_dupenv_s(&buf, &size, str.c_str()) == 0 && buf) {
466 std::string ret(buf);
472 auto buf = std::getenv(str.c_str());
473 return buf ? buf :
"";
486 auto pfd_verbose = internal::getenv(
"PFD_VERBOSE");
487 auto match_no = std::regex(
"(|0|no|false)", std::regex_constants::icase);
500 auto desktop_name = internal::getenv(
"XDG_SESSION_DESKTOP");
501 if (desktop_name == std::string(
"gnome"))
503 else if (desktop_name == std::string(
"KDE"))
547 return exit_code == 0;
573 return const_cast<bool&
>(
static_cast<settings const*
>(
this)->flags(in_flag));
580 auto user_profile = internal::getenv(
"USERPROFILE");
581 if (user_profile.size() > 0)
return user_profile;
583 HANDLE token =
nullptr;
584 DWORD len = MAX_PATH;
585 char buf[MAX_PATH] = {
'\0'};
586 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
587 dll userenv(
"userenv.dll");
588 dll::proc<
BOOL WINAPI(HANDLE, LPSTR, LPDWORD)> get_user_profile_directory(
589 userenv,
"GetUserProfileDirectoryA");
590 get_user_profile_directory(token, buf, &len);
592 if (*buf)
return buf;
598 auto home = internal::getenv(
"HOME");
602#if defined(_SC_GETPW_R_SIZE_MAX)
603 auto size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
604 if (size_max != -1) len =
size_t(size_max);
606 std::vector<char> buf(len);
607 struct passwd pwd, *result;
608 if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0)
return result->pw_dir;
631 if (m_future.valid()) {
633 auto previous_windows = m_windows;
634 EnumWindows(&enum_windows_callback, (LPARAM)
this);
635 for (
auto hwnd : m_windows)
636 if (previous_windows.find(hwnd) == previous_windows.end()) {
637 SendMessage(hwnd, WM_CLOSE, 0, 0);
639 SendMessage(hwnd, WM_COMMAND, IDNO, 0);
642#elif __EMSCRIPTEN__ || __NX__
653inline BOOL CALLBACK internal::executor::enum_windows_callback(HWND hwnd, LPARAM lParam) {
657 auto tid = GetWindowThreadProcessId(hwnd, &pid);
658 if (tid == that->m_tid) that->m_windows.insert(hwnd);
664inline void internal::executor::start_func(std::function<std::string(
int*)>
const& fun) {
667 auto trampoline = [fun,
this]() {
669 m_tid = GetCurrentThreadId();
670 EnumWindows(&enum_windows_callback, (LPARAM)
this);
672 return fun(&m_exit_code);
675 std::unique_lock<std::mutex> lock(m_mutex);
676 m_future = std::async(std::launch::async, trampoline);
682inline void internal::executor::start(
int exit_code) {
683 m_exit_code = exit_code;
693 if (pipe(in) != 0 || pipe(out) != 0)
return;
696 if (
m_pid < 0)
return;
698 close(in[
m_pid ? 0 : 1]);
699 close(out[
m_pid ? 1 : 0]);
702 dup2(in[0], STDIN_FILENO);
703 dup2(out[1], STDOUT_FILENO);
706 int fd = open(
"/src/null", O_WRONLY);
707 dup2(fd, STDERR_FILENO);
710 std::vector<char*> args;
711 std::transform(command.cbegin(), command.cend(), std::back_inserter(args),
712 [](std::string
const& s) { return const_cast<char*>(s.c_str()); });
713 args.push_back(
nullptr);
715 execvp(args[0], args.data());
721 auto flags = fcntl(
m_fd, F_GETFL);
722 fcntl(
m_fd, F_SETFL, flags | O_NONBLOCK);
736 if (m_future.valid()) {
737 auto status = m_future.wait_for(std::chrono::milliseconds(timeout));
738 if (status != std::future_status::ready) {
743 while (PeekMessage(&msg,
nullptr, 0, 0, PM_REMOVE)) {
744 TranslateMessage(&msg);
745 DispatchMessage(&msg);
752#elif __EMSCRIPTEN__ || __NX__
757 ssize_t received = read(
m_fd, buf, BUFSIZ);
759 m_stdout += std::string(buf, received);
768 pid_t child = waitpid(
m_pid, &status, WNOHANG);
769 if (child !=
m_pid && (child >= 0 || errno != ECHILD)) {
771 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
791inline internal::platform::dll::dll(std::string
const& name)
792 : handle(::LoadLibraryA(name.c_str())) {}
794inline internal::platform::dll::~dll() {
795 if (handle) ::FreeLibrary(handle);
802inline internal::platform::ole32_dll::ole32_dll() : dll(
"ole32.dll") {
805 auto coinit = proc<HRESULT WINAPI(LPVOID, DWORD)>(*
this,
"CoInitializeEx");
806 m_state = coinit(
nullptr, COINIT_MULTITHREADED);
809inline internal::platform::ole32_dll::~ole32_dll() {
810 if (is_initialized()) proc<void WINAPI()>(*
this,
"CoUninitialize")();
813inline bool internal::platform::ole32_dll::is_initialized() {
814 return m_state == S_OK || m_state == S_FALSE;
821inline internal::platform::new_style_context::new_style_context() {
823 static HANDLE hctx = create();
825 if (hctx != INVALID_HANDLE_VALUE) ActivateActCtx(hctx, &m_cookie);
828inline internal::platform::new_style_context::~new_style_context() {
829 DeactivateActCtx(0, m_cookie);
832inline HANDLE internal::platform::new_style_context::create() {
840 dll comdlg32(
"comdlg32.dll");
843 UINT len = ::GetSystemDirectoryA(
nullptr, 0);
844 std::string sys_dir(len,
'\0');
845 ::GetSystemDirectoryA(&sys_dir[0], len);
851 ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
861 return ::CreateActCtxA(&act_ctx);
868 return m_async->ready(timeout);
879 return {
"osascript"};
896 return "yesnocancel";
898 return "retrycancel";
900 return "abortretryignore";
919 return "information";
925inline std::ostream&
operator<<(std::ostream& s, std::vector<std::string>
const& v) {
927 for (
auto& e : v) s << (not_first++ ?
" " :
"") << e;
936 return "'" + std::regex_replace(str, std::regex(
"['\"]"),
"$&$&") +
"'";
943 return "\"" + std::regex_replace(str, std::regex(
"[\\\\\"]"),
"\\$&") +
"\"";
949 return "'" + std::regex_replace(str, std::regex(
"'"),
"'\\''") +
"'";
955 std::string
const& default_path ,
956 std::vector<std::string>
const& filters ,
959 std::string filter_list;
960 std::regex whitespace(
" *");
961 for (
size_t i = 0; i + 1 < filters.size(); i += 2) {
962 filter_list += filters[i] +
'\0';
963 filter_list += std::regex_replace(filters[i + 1], whitespace,
";") +
'\0';
968 [
this, in_type, title, default_path, filter_list, options](
int* exit_code) -> std::string {
970 m_wtitle = internal::str2wstr(title);
971 m_wdefault_path = internal::str2wstr(default_path);
972 auto wfilter_list = internal::str2wstr(filter_list);
982#if PFD_HAS_IFILEDIALOG
986 HRESULT hr = dll::proc<HRESULT WINAPI(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>(
987 ole32,
"CoCreateInstance")(CLSID_FileOpenDialog,
nullptr, CLSCTX_INPROC_SERVER,
991 if (SUCCEEDED(hr))
return select_folder_vista(ifd, options &
opt::force_path);
996 memset(&bi, 0,
sizeof(bi));
998 bi.lpfn = &bffcallback;
999 bi.lParam = (LPARAM)
this;
1002 if (ole32.is_initialized()) bi.ulFlags |= BIF_NEWDIALOGSTYLE;
1003 bi.ulFlags |= BIF_EDITBOX;
1004 bi.ulFlags |= BIF_STATUSTEXT;
1007 auto* list = SHBrowseForFolderW(&bi);
1010 auto buffer =
new wchar_t[MAX_PATH];
1011 SHGetPathFromIDListW(list, buffer);
1012 dll::proc<void WINAPI(LPVOID)>(ole32,
"CoTaskMemFree")(list);
1013 ret = internal::wstr2str(buffer);
1020 memset(&ofn, 0,
sizeof(ofn));
1021 ofn.lStructSize =
sizeof(OPENFILENAMEW);
1022 ofn.hwndOwner = GetActiveWindow();
1024 ofn.lpstrFilter = wfilter_list.c_str();
1026 auto woutput = std::wstring(MAX_PATH * 256, L
'\0');
1027 ofn.lpstrFile = (LPWSTR) woutput.data();
1028 ofn.nMaxFile = (DWORD) woutput.size();
1029 if (!m_wdefault_path.empty()) {
1033 auto path_attr = GetFileAttributesW(m_wdefault_path.c_str());
1034 if (path_attr != INVALID_FILE_ATTRIBUTES && (path_attr & FILE_ATTRIBUTE_DIRECTORY))
1035 ofn.lpstrInitialDir = m_wdefault_path.c_str();
1036 else if (m_wdefault_path.size() <= woutput.size())
1038 StringCchCopyW(ofn.lpstrFile, MAX_PATH * 256 + 1, m_wdefault_path.c_str());
1040 ofn.lpstrFileTitle = (LPWSTR) m_wdefault_path.data();
1041 ofn.nMaxFileTitle = (DWORD) m_wdefault_path.size();
1044 ofn.lpstrTitle = m_wtitle.c_str();
1045 ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER;
1047 dll comdlg32(
"comdlg32.dll");
1050 new_style_context ctx;
1055 dll::proc<
BOOL WINAPI(LPOPENFILENAMEW)> get_save_file_name(comdlg32,
"GetSaveFileNameW");
1056 if (get_save_file_name(&ofn) == 0)
return "";
1057 return internal::wstr2str(woutput.c_str());
1060 ofn.Flags |= OFN_PATHMUSTEXIST;
1062 dll::proc<
BOOL WINAPI(LPOPENFILENAMEW)> get_open_file_name(comdlg32,
"GetOpenFileNameW");
1063 if (get_open_file_name(&ofn) == 0)
return "";
1067 for (
wchar_t const* p = woutput.c_str(); *p;) {
1068 auto filename = internal::wstr2str(p);
1074 prefix = filename +
"/";
1078 m_vector_result.push_back(prefix + filename);
1087 (void) default_path;
1094 std::string script =
"set ret to choose";
1097 script +=
" file name";
1102 if (options &
opt::multiselect) script +=
" with multiple selections allowed";
1105 script +=
" folder";
1109 if (default_path.size()) {
1110 if (in_type ==
type::folder || is_directory(default_path))
1111 script +=
" default location ";
1113 script +=
" default name ";
1121 std::string patterns;
1122 for (
size_t i = 0; i < filters.size() / 2; ++i) patterns +=
" " + filters[2 * i + 1];
1127 std::regex sep(
"\\s+");
1128 std::string filter_list;
1129 bool has_filter =
true;
1130 std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1);
1131 std::sregex_token_iterator end;
1132 for (; iter != end; ++iter) {
1133 auto pat = iter->str();
1134 if (pat ==
"*" || pat ==
"*.*")
1136 else if (internal::starts_with(pat,
"*."))
1140 if (has_filter && filter_list.size() > 0) {
1146 script +=
" of type {\"///\"" + filter_list +
"}";
1151 script +=
"\nset s to \"\"";
1152 script +=
"\nrepeat with i in ret";
1153 script +=
"\n set s to s & (POSIX path of i) & \"\\n\"";
1154 script +=
"\nend repeat";
1155 script +=
"\ncopy s to stdout";
1157 script +=
"\nPOSIX path of ret";
1160 command.push_back(
"-e");
1161 command.push_back(script);
1163 command.push_back(
"--file-selection");
1167 auto filename_arg =
"--filename=" + default_path;
1168 if (in_type !=
type::folder && !ends_with(default_path,
"/") &&
1169 internal::is_directory(default_path))
1170 filename_arg +=
"/";
1171 command.push_back(filename_arg);
1173 command.push_back(
"--title");
1174 command.push_back(title);
1175 command.push_back(
"--separator=\n");
1177 for (
size_t i = 0; i < filters.size() / 2; ++i) {
1178 command.push_back(
"--file-filter");
1179 command.push_back(filters[2 * i] +
"|" + filters[2 * i + 1]);
1182 if (in_type ==
type::save) command.push_back(
"--save");
1183 if (in_type ==
type::folder) command.push_back(
"--directory");
1189 command.push_back(
"--getsavefilename");
1192 command.push_back(
"--getopenfilename");
1195 command.push_back(
"--getexistingdirectory");
1199 command.push_back(
"--multiple");
1200 command.push_back(
"--separate-output");
1203 command.push_back(default_path);
1206 for (
size_t i = 0; i < filters.size() / 2; ++i)
1207 filter += (i == 0 ?
"" :
" | ") + filters[2 * i] +
"(" + filters[2 * i + 1] +
")";
1208 command.push_back(filter);
1210 command.push_back(
"--title");
1211 command.push_back(title);
1216 m_async->start_process(command);
1227 while (!ret.empty() && (ret.back() ==
'\n' || ret.back() ==
'/')) ret.pop_back();
1235 return m_vector_result;
1237 std::vector<std::string> ret;
1238 auto result =
m_async->result();
1241 auto i = result.find(
'\n');
1242 if (i == 0 || i == std::string::npos)
break;
1243 ret.push_back(result.substr(0, i));
1244 result = result.substr(i + 1, result.size());
1252inline int CALLBACK internal::file_dialog::bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData) {
1255 case BFFM_INITIALIZED:
1256 SendMessage(hwnd, BFFM_SETSELECTIONW,
TRUE, (LPARAM) inst->m_wdefault_path.c_str());
1262#if PFD_HAS_IFILEDIALOG
1263inline std::string internal::file_dialog::select_folder_vista(IFileDialog* ifd,
bool force_path) {
1269 dll shell32(
"shell32.dll");
1270 dll::proc<HRESULT WINAPI(PCWSTR, IBindCtx*, REFIID,
void**)> create_item(
1271 shell32,
"SHCreateItemFromParsingName");
1273 if (!create_item)
return "";
1275 auto hr = create_item(m_wdefault_path.c_str(),
nullptr, IID_PPV_ARGS(&folder));
1283 if (SUCCEEDED(hr)) {
1285 ifd->SetFolder(folder);
1287 ifd->SetDefaultFolder(folder);
1292 ifd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM);
1293 ifd->SetTitle(m_wtitle.c_str());
1295 hr = ifd->Show(GetActiveWindow());
1296 if (SUCCEEDED(hr)) {
1298 hr = ifd->GetResult(&item);
1299 if (SUCCEEDED(hr)) {
1300 wchar_t* wname =
nullptr;
1303 if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &wname))) {
1304 result = internal::wstr2str(std::wstring(wname));
1305 dll::proc<void WINAPI(LPVOID)>(ole32_dll(),
"CoTaskMemFree")(wname);
1307 if (SUCCEEDED(item->GetDisplayName(SIGDN_NORMALDISPLAY, &wname))) {
1308 auto name = internal::wstr2str(std::wstring(wname));
1309 dll::proc<void WINAPI(LPVOID)>(ole32_dll(),
"CoTaskMemFree")(wname);
1310 std::cerr <<
"pfd: failed to get path for " << name << std::endl;
1312 std::cerr <<
"pfd: item of unknown type selected" << std::endl;
1337 struct notify_icon_data :
public NOTIFYICONDATAW {
1338 ~notify_icon_data() { Shell_NotifyIconW(NIM_DELETE,
this); }
1341 static std::shared_ptr<notify_icon_data> nid;
1347 nid = std::make_shared<notify_icon_data>();
1350 nid->cbSize = NOTIFYICONDATAW_V2_SIZE;
1351 nid->hWnd =
nullptr;
1362 nid->uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO;
1374 nid->dwInfoFlags = NIIF_WARNING;
1377 nid->dwInfoFlags = NIIF_ERROR;
1380 nid->dwInfoFlags = NIIF_INFO;
1384 ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName,
1385 LONG_PTR lParam) ->
BOOL {
1386 ((NOTIFYICONDATAW*) lParam)->hIcon = ::LoadIcon(GetModuleHandle(
nullptr), lpName);
1390 nid->hIcon = ::LoadIcon(
nullptr, IDI_APPLICATION);
1391 ::EnumResourceNames(
nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR) nid.get());
1393 nid->uTimeout = 5000;
1395 StringCchCopyW(nid->szInfoTitle, ARRAYSIZE(nid->szInfoTitle), internal::str2wstr(title).c_str());
1396 StringCchCopyW(nid->szInfo, ARRAYSIZE(nid->szInfo), internal::str2wstr(
message).c_str());
1399 Shell_NotifyIconW(NIM_ADD, nid.get());
1408 command.push_back(
"-e");
1412 command.push_back(
"--notification");
1413 command.push_back(
"--window-icon");
1415 command.push_back(
"--text");
1416 command.push_back(title +
"\n" +
message);
1418 command.push_back(
"--icon");
1420 command.push_back(
"--title");
1421 command.push_back(title);
1422 command.push_back(
"--passivepopup");
1424 command.push_back(
"5");
1429 m_async->start_process(command);
1440 UINT style = MB_SYSTEMMODAL;
1443 style |= MB_ICONWARNING;
1446 style |= MB_ICONERROR;
1449 style |= MB_ICONQUESTION;
1452 style |= MB_ICONINFORMATION;
1458 style |= MB_OKCANCEL;
1464 style |= MB_YESNOCANCEL;
1467 style |= MB_RETRYCANCEL;
1470 style |= MB_ABORTRETRYIGNORE;
1485 m_async->start_func([text, title, style](
int* exit_code) -> std::string {
1486 auto wtext = internal::str2wstr(text);
1487 auto wtitle = internal::str2wstr(title);
1489 new_style_context ctx;
1490 *exit_code = MessageBoxW(GetActiveWindow(), wtext.c_str(), wtitle.c_str(), style);
1495 std::string full_message;
1498 full_message =
"⚠️";
1511 full_message +=
' ' + title +
"\n\n" + text;
1517 if ($1)
return window.confirm(UTF8ToString($0)) ? 0 : -1;
1518 alert(UTF8ToString($0));
1526 std::string script =
1532 "buttons {\"OK\", \"Cancel\"}"
1533 " default button \"OK\""
1534 " cancel button \"Cancel\"";
1538 "buttons {\"Yes\", \"No\"}"
1539 " default button \"Yes\""
1540 " cancel button \"No\"";
1545 "buttons {\"Yes\", \"No\", \"Cancel\"}"
1546 " default button \"Yes\""
1547 " cancel button \"Cancel\"";
1551 "buttons {\"Retry\", \"Cancel\"}"
1552 " default button \"Retry\""
1553 " cancel button \"Cancel\"";
1557 "buttons {\"Abort\", \"Retry\", \"Ignore\"}"
1558 " default button \"Abort\""
1559 " cancel button \"Retry\"";
1566 " default button \"OK\""
1567 " cancel button \"OK\"";
1573 script +=
" with icon ";
1575#define PFD_OSX_ICON(n) \
1576 "alias ((path to library folder from system domain) as text " \
1577 "& \"CoreServices:CoreTypes.bundle:Contents:Resources:" n ".icns\")"
1583 script +=
"caution";
1594 command.push_back(
"-e");
1595 command.push_back(script);
1599 command.insert(command.end(), {
"--question",
"--cancel-label=Cancel",
"--ok-label=OK"});
1604 command.insert(command.end(),
1605 {
"--question",
"--switch",
"--extra-button=No",
"--extra-button=Yes"});
1608 command.insert(command.end(), {
"--question",
"--switch",
"--extra-button=Cancel",
1609 "--extra-button=No",
"--extra-button=Yes"});
1612 command.insert(command.end(),
1613 {
"--question",
"--switch",
"--extra-button=Cancel",
"--extra-button=Retry"});
1616 command.insert(command.end(), {
"--question",
"--switch",
"--extra-button=Ignore",
1617 "--extra-button=Abort",
"--extra-button=Retry"});
1623 command.push_back(
"--error");
1626 command.push_back(
"--warning");
1629 command.push_back(
"--info");
1634 command.insert(command.end(),
1635 {
"--title", title,
"--width=300",
"--height=0",
1637 "--text", text,
"--icon-name=dialog-" + get_icon_name(_icon)});
1642 command.push_back(
"--error");
1645 command.push_back(
"--sorry");
1648 command.push_back(
"--msgbox");
1652 std::string
flag =
"--";
1656 command.push_back(
flag);
1663 command.push_back(text);
1664 command.push_back(
"--title");
1665 command.push_back(title);
1669 command.insert(command.end(), {
"--yes-label",
"OK",
"--no-label",
"Cancel"});
1674 m_async->start_process(command);
1680 auto ret =
m_async->result(&exit_code);
1684 if (internal::ends_with(ret,
"OK\n"))
return button::ok;
1685 if (internal::ends_with(ret,
"Yes\n"))
return button::yes;
1686 if (internal::ends_with(ret,
"No\n"))
return button::no;
1687 if (internal::ends_with(ret,
"Abort\n"))
return button::abort;
1688 if (internal::ends_with(ret,
"Retry\n"))
return button::retry;
1697 std::vector<std::string>
const& filters ,
1702 std::vector<std::string>
const& filters,
bool allow_multiselect)
1712 std::vector<std::string>
const& filters ,
1717 std::vector<std::string>
const& filters,
bool confirm_overwrite)
1718 :
save_file(title, default_path, filters,
1728 std::string
const& default_path ,