1#ifdef MAYAFLUX_PLATFORM_WINDOWS
7#include <shobjidl_core.h>
9#ifndef WIN32_LEAN_AND_MEAN
10#define WIN32_LEAN_AND_MEAN
27 std::wstring to_wide(
const std::string& s)
32 const int len = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1,
nullptr, 0);
33 std::wstring result(len - 1, L
'\0');
34 MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, result.data(), len);
41 std::string to_narrow(
const std::wstring& ws)
46 const int len = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1,
nullptr, 0,
nullptr,
nullptr);
47 std::string result(len - 1,
'\0');
48 WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, result.data(), len,
nullptr,
nullptr);
58 void build_filter_specs(
59 const std::vector<SystemFileFilter>& filters,
60 std::vector<std::wstring>& names,
61 std::vector<std::wstring>& patterns,
62 std::vector<COMDLG_FILTERSPEC>& specs)
64 names.reserve(filters.size());
65 patterns.reserve(filters.size());
66 specs.reserve(filters.size());
68 for (
const auto& f : filters) {
69 names.push_back(to_wide(f.name));
72 for (
size_t i = 0; i < f.extensions.size(); ++i) {
76 pattern += (f.extensions[i] ==
"*") ? L
"*.*" :
L"*." + to_wide(f.extensions[i]);
78 patterns.push_back(std::move(pattern));
80 specs.push_back({ names.back().c_str(), patterns.back().c_str() });
93 const std::vector<SystemFileFilter>& filters,
94 const std::filesystem::path& start_dir,
95 const std::string& suggested_name)
97 HRESULT hr = CoInitializeEx(
nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
100 "COMBackend: CoInitializeEx failed: 0x{:08X}",
static_cast<uint32_t
>(hr));
105 IFileDialog* dialog =
nullptr;
106 const CLSID clsid = is_save ? CLSID_FileSaveDialog : CLSID_FileOpenDialog;
107 const IID iid = is_save ? IID_IFileSaveDialog : IID_IFileOpenDialog;
109 hr = CoCreateInstance(clsid,
nullptr, CLSCTX_ALL, iid,
110 reinterpret_cast<void**
>(&dialog));
112 if (FAILED(hr) || !dialog) {
114 "COMBackend: CoCreateInstance failed: 0x{:08X}",
static_cast<uint32_t
>(hr));
120 std::vector<std::wstring> names, pattern_strings;
121 std::vector<COMDLG_FILTERSPEC> specs;
122 build_filter_specs(filters, names, pattern_strings, specs);
123 if (!specs.empty()) {
124 dialog->SetFileTypes(
static_cast<UINT
>(specs.size()), specs.data());
127 if (is_save && !suggested_name.empty()) {
128 dialog->SetFileName(to_wide(suggested_name).c_str());
131 if (!start_dir.empty()) {
132 IShellItem* folder =
nullptr;
133 hr = SHCreateItemFromParsingName(start_dir.wstring().c_str(),
nullptr,
134 IID_IShellItem,
reinterpret_cast<void**
>(&folder));
135 if (SUCCEEDED(hr) && folder) {
136 dialog->SetFolder(folder);
141 hr = dialog->Show(
nullptr);
143 if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
152 "COMBackend: dialog Show failed: 0x{:08X}",
static_cast<uint32_t
>(hr));
159 IShellItem* result =
nullptr;
160 hr = dialog->GetResult(&result);
162 if (FAILED(hr) || !result) {
169 PWSTR path_raw =
nullptr;
170 hr = result->GetDisplayName(SIGDN_FILESYSPATH, &path_raw);
174 if (FAILED(hr) || !path_raw) {
180 std::filesystem::path chosen_path(path_raw);
181 CoTaskMemFree(path_raw);
184 callback(std::move(chosen_path));
193bool COMBackend::initialize()
198 m_initialized =
true;
200 "COMBackend initialized");
204void COMBackend::shutdown()
206 if (!m_initialized) {
209 m_initialized =
false;
211 "COMBackend shutdown");
218void COMBackend::open_file(
220 std::vector<SystemFileFilter> filters,
221 std::filesystem::path start_dir)
223 invoke_dialog(
false, std::move(callback), filters, start_dir, {});
226void COMBackend::save_file(
228 std::string suggested_name,
229 std::vector<SystemFileFilter> filters,
230 std::filesystem::path start_dir)
232 invoke_dialog(
true, std::move(callback), filters, start_dir, suggested_name);
235void COMBackend::invoke_dialog(
238 const std::vector<SystemFileFilter>& filters,
239 const std::filesystem::path& start_dir,
240 const std::string& suggested_name)
242 if (!m_initialized) {
247 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, double interval_seconds, Vruta::ProcessingToken token)
Creates a generative algorithm that produces values based on a pattern function.