| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "Utility/BsEditorUtility.h"
- #include "Threading/BsAsyncOp.h"
- #include "CoreThread/BsCoreThread.h"
- #include "String/BsUnicode.h"
- #include "Private/Win32/BsWin32Window.h"
- #include <ShObjIdl.h>
- using namespace std::placeholders;
- namespace bs
- {
- void addFiltersToDialog(IFileDialog* fileDialog, const String& filterList)
- {
- const wchar_t EMPTY_WSTR[] = L"";
- if (filterList.empty())
- return;
- WString wideFilterList = UTF8::toWide(filterList);
- Vector<WString> filters = StringUtil::split(wideFilterList, L";");
- UINT32 numFilters = (UINT32)filters.size();
- if (numFilters == 0)
- return;
- COMDLG_FILTERSPEC* specList = bs_newN<COMDLG_FILTERSPEC>(numFilters);
- for (size_t i = 0; i < numFilters; ++i)
- {
- specList[i].pszName = EMPTY_WSTR;
- specList[i].pszSpec = filters[i].c_str();
- }
- fileDialog->SetFileTypes(numFilters, specList);
- bs_deleteN(specList, numFilters);
- }
- void setDefaultPath(IFileDialog* dialog, const Path& defaultPath)
- {
- WString pathStr = UTF8::toWide(defaultPath.toString());
- const wchar_t* defaultPathW = pathStr.c_str();
- IShellItem* folder;
- HRESULT result = SHCreateItemFromParsingName(defaultPathW, NULL, IID_PPV_ARGS(&folder));
- // Valid non results.
- if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE))
- return;
- if (!SUCCEEDED(result))
- return;
- dialog->SetFolder(folder);
- folder->Release();
- }
- void getPaths(IShellItemArray* shellItems, Vector<Path>& paths)
- {
- DWORD numShellItems;
- shellItems->GetCount(&numShellItems);
- for (DWORD i = 0; i < numShellItems; ++i)
- {
- IShellItem* shellItem = nullptr;
- shellItems->GetItemAt(i, &shellItem);
- SFGAOF attribs;
- shellItem->GetAttributes(SFGAO_FILESYSTEM, &attribs);
- if (!(attribs & SFGAO_FILESYSTEM))
- continue;
- LPWSTR name;
- shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name);
- paths.push_back((Path)UTF8::fromWide(WString(name)));
- CoTaskMemFree(name);
- }
- }
- void openBrowseDialogCore(FileDialogType type, const Path& defaultPath, const String& filterList,
- Vector<Path>& paths, AsyncOp& returnValue)
- {
- // Init COM library.
- CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- IFileDialog* fileDialog = nullptr;
- UINT32 dialogType = ((UINT32)type & (UINT32)FileDialogType::TypeMask);
- bool isOpenDialog = dialogType == (UINT32)FileDialogType::OpenFile || dialogType == (UINT32)FileDialogType::OpenFolder;
- // Create dialog
- IID classId = isOpenDialog ? CLSID_FileOpenDialog : CLSID_FileSaveDialog;
- CoCreateInstance(classId, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fileDialog));
- addFiltersToDialog(fileDialog, filterList);
- setDefaultPath(fileDialog, defaultPath);
- // Apply multiselect flags
- bool isMultiselect = false;
- if (isOpenDialog)
- {
- if (dialogType == (UINT32)FileDialogType::OpenFile)
- {
- if (((UINT32)type & (UINT32)FileDialogType::Multiselect) != 0)
- {
- DWORD dwFlags;
- fileDialog->GetOptions(&dwFlags);
- fileDialog->SetOptions(dwFlags | FOS_ALLOWMULTISELECT);
- isMultiselect = true;
- }
- }
- else
- {
- DWORD dwFlags;
- fileDialog->GetOptions(&dwFlags);
- fileDialog->SetOptions(dwFlags | FOS_PICKFOLDERS);
- }
- }
- // Show the dialog
- bool finalResult = false;
- // Need to enable all windows, otherwise when the browse dialog closes the active window will become some
- // background window
- Win32Window::_enableAllWindows();
- if (SUCCEEDED(fileDialog->Show(nullptr)))
- {
- if (isMultiselect)
- {
- // Get file names
- IFileOpenDialog* fileOpenDialog;
- fileDialog->QueryInterface(IID_IFileOpenDialog, (void**)&fileOpenDialog);
-
- IShellItemArray* shellItems = nullptr;
- fileOpenDialog->GetResults(&shellItems);
- getPaths(shellItems, paths);
- shellItems->Release();
- fileOpenDialog->Release();
- }
- else
- {
- // Get the file name
- IShellItem* shellItem = nullptr;
- fileDialog->GetResult(&shellItem);
- LPWSTR filePath = nullptr;
- shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
- paths.push_back((Path)UTF8::fromWide(WString(filePath)));
- CoTaskMemFree(filePath);
- shellItem->Release();
- }
- finalResult = true;
- }
- // Restore modal window state (before we enabled all windows)
- Win32Window::_restoreModalWindows();
- CoUninitialize();
- returnValue._completeOperation(finalResult);
- }
- bool EditorUtility::openBrowseDialog(FileDialogType type, const Path& defaultPath, const String& filterList,
- Vector<Path>& paths)
- {
- AsyncOp returnValue = gCoreThread().queueReturnCommand(std::bind(&openBrowseDialogCore, type,
- std::cref(defaultPath), std::cref(filterList), std::ref(paths), _1),
- CTQF_InternalQueue | CTQF_BlockUntilComplete);
- return any_cast<bool>(returnValue.getGenericReturnValue());
- }
- }
|