1#ifdef MAYAFLUX_PLATFORM_WINDOWS
8#include <shobjidl_core.h>
21 std::wstring to_wide(
const std::string& s)
26 const int len = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1,
nullptr, 0);
27 std::wstring result(len - 1, L
'\0');
28 MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, result.data(), len);
35 std::string to_narrow(
const std::wstring& ws)
40 const int len = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1,
nullptr, 0,
nullptr,
nullptr);
41 std::string result(len - 1,
'\0');
42 WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, result.data(), len,
nullptr,
nullptr);
52 void build_filter_specs(
53 const std::vector<SystemFileFilter>& filters,
54 std::vector<std::wstring>& names,
55 std::vector<std::wstring>& patterns,
56 std::vector<COMDLG_FILTERSPEC>& specs)
58 names.reserve(filters.size());
59 patterns.reserve(filters.size());
60 specs.reserve(filters.size());
62 for (
const auto& f : filters) {
63 names.push_back(to_wide(f.name));
66 for (
size_t i = 0; i < f.extensions.size(); ++i) {
70 pattern += (f.extensions[i] ==
"*") ? L
"*.*" :
L"*." + to_wide(f.extensions[i]);
72 patterns.push_back(std::move(pattern));
74 specs.push_back({ names.back().c_str(), patterns.back().c_str() });
87 const std::vector<SystemFileFilter>& filters,
88 const std::filesystem::path& start_dir,
89 const std::string& suggested_name)
91 HRESULT hr = CoInitializeEx(
nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
94 "COMBackend: CoInitializeEx failed: 0x{:08X}",
static_cast<uint32_t
>(hr));
99 IFileDialog* dialog =
nullptr;
100 const CLSID clsid = is_save ? CLSID_FileSaveDialog : CLSID_FileOpenDialog;
101 const IID iid = is_save ? IID_IFileSaveDialog : IID_IFileOpenDialog;
103 hr = CoCreateInstance(clsid,
nullptr, CLSCTX_ALL, iid,
104 reinterpret_cast<void**
>(&dialog));
106 if (FAILED(hr) || !dialog) {
108 "COMBackend: CoCreateInstance failed: 0x{:08X}",
static_cast<uint32_t
>(hr));
114 std::vector<std::wstring> names, pattern_strings;
115 std::vector<COMDLG_FILTERSPEC> specs;
116 build_filter_specs(filters, names, pattern_strings, specs);
117 if (!specs.empty()) {
118 dialog->SetFileTypes(
static_cast<UINT
>(specs.size()), specs.data());
121 if (is_save && !suggested_name.empty()) {
122 dialog->SetFileName(to_wide(suggested_name).c_str());
125 if (!start_dir.empty()) {
126 IShellItem* folder =
nullptr;
127 hr = SHCreateItemFromParsingName(start_dir.wstring().c_str(),
nullptr,
128 IID_IShellItem,
reinterpret_cast<void**
>(&folder));
129 if (SUCCEEDED(hr) && folder) {
130 dialog->SetFolder(folder);
135 hr = dialog->Show(
nullptr);
137 if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
146 "COMBackend: dialog Show failed: 0x{:08X}",
static_cast<uint32_t
>(hr));
153 IShellItem* result =
nullptr;
154 hr = dialog->GetResult(&result);
156 if (FAILED(hr) || !result) {
163 PWSTR path_raw =
nullptr;
164 hr = result->GetDisplayName(SIGDN_FILESYSPATH, &path_raw);
168 if (FAILED(hr) || !path_raw) {
174 std::filesystem::path chosen_path(path_raw);
175 CoTaskMemFree(path_raw);
187bool COMBackend::initialize()
192 m_initialized =
true;
194 "COMBackend initialized");
198void COMBackend::shutdown()
200 if (!m_initialized) {
203 m_initialized =
false;
205 "COMBackend shutdown");
212void COMBackend::open_file(
214 std::vector<SystemFileFilter> filters,
215 std::filesystem::path start_dir)
217 invoke_dialog(
false, std::move(
callback), filters, start_dir, {});
220void COMBackend::save_file(
222 std::string suggested_name,
223 std::vector<SystemFileFilter> filters,
224 std::filesystem::path start_dir)
226 invoke_dialog(
true, std::move(
callback), filters, start_dir, suggested_name);
229void COMBackend::invoke_dialog(
232 const std::vector<SystemFileFilter>& filters,
233 const std::filesystem::path& start_dir,
234 const std::string& suggested_name)
236 if (!m_initialized) {
241 std::thread(run_dialog, is_save, std::move(
callback), filters, start_dir, suggested_name).detach();
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
@ BackendError
Platform backend failed to open or communicate.
@ Cancelled
User dismissed the dialog without completing it.
std::function< void(FileDialogResult)> FileDialogCallback
Callback type for all file dialog operations.
@ API
API calls from external code.
@ Core
Core engine, backend, subsystems.
std::shared_ptr< Vruta::Routine > pattern(std::function< std::any(uint64_t)> pattern_func, std::function< void(std::any)> callback, std::function< bool(uint64_t)> ready, Vruta::ProcessingToken token)
The std::any, uint64_t form of the condition driven pattern.