feat: add some dialog code which can not work now.
- add common file dialog showcase code but all of them are not work now.
This commit is contained in:
parent
84228b5f8c
commit
a9059013f0
|
@ -69,9 +69,219 @@ namespace YYCC::DialogHelper {
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region FileDialog
|
#pragma region File Dialog
|
||||||
|
|
||||||
|
bool FileDialog::Generate(WinFileDialog& win_result) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Windows Dialog Code
|
||||||
|
|
||||||
|
enum class CommonFileDialogType {
|
||||||
|
OpenFile,
|
||||||
|
OpenMultipleFiles,
|
||||||
|
SaveFile,
|
||||||
|
OpenFolder
|
||||||
|
};
|
||||||
|
|
||||||
|
using SmartFileDialogPtr = std::unique_ptr<IFileDialog, std::function<void(IFileDialog*)>>;
|
||||||
|
|
||||||
|
template<CommonFileDialogType EDialogType>
|
||||||
|
bool CommonFileDialog(const FileDialog& params, std::vector<std::string>& ret) {
|
||||||
|
// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog
|
||||||
|
// prepare result variable
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
// create file dialog instance
|
||||||
|
// fetch dialog CLSID first
|
||||||
|
CLSID dialog_clsid;
|
||||||
|
switch (EDialogType) {
|
||||||
|
case CommonFileDialogType::OpenFile:
|
||||||
|
case CommonFileDialogType::OpenMultipleFiles:
|
||||||
|
case CommonFileDialogType::OpenFolder:
|
||||||
|
dialog_clsid = CLSID_FileOpenDialog;
|
||||||
|
break;
|
||||||
|
case CommonFileDialogType::SaveFile:
|
||||||
|
dialog_clsid = CLSID_FileSaveDialog;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// create raw dialog pointer
|
||||||
|
IFileDialog* _pfd = nullptr;
|
||||||
|
hr = CoCreateInstance(
|
||||||
|
dialog_clsid,
|
||||||
|
NULL,
|
||||||
|
CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&_pfd)
|
||||||
|
);
|
||||||
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
// create memory-safe dialog pointer
|
||||||
|
SmartFileDialogPtr pfd(
|
||||||
|
_pfd,
|
||||||
|
[](IFileDialog* instance) -> void {
|
||||||
|
if (instance != nullptr)
|
||||||
|
instance->Release();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// set options for dialog
|
||||||
|
// before setting, always get the options first in order.
|
||||||
|
// not to override existing options.
|
||||||
|
DWORD dwFlags;
|
||||||
|
hr = pfd->GetOptions(&dwFlags);
|
||||||
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
// modify options
|
||||||
|
switch (EDialogType) {
|
||||||
|
// We want user only can pick file system files: FOS_FORCEFILESYSTEM.
|
||||||
|
// Open dialog default: FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR
|
||||||
|
// Save dialog default: FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR
|
||||||
|
// Pick folder: FOS_PICKFOLDERS
|
||||||
|
case CommonFileDialogType::OpenFile:
|
||||||
|
dwFlags |= FOS_FORCEFILESYSTEM;
|
||||||
|
dwFlags |= FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
|
||||||
|
break;
|
||||||
|
case CommonFileDialogType::OpenMultipleFiles:
|
||||||
|
dwFlags |= FOS_FORCEFILESYSTEM;
|
||||||
|
dwFlags |= FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
|
||||||
|
dwFlags |= FOS_ALLOWMULTISELECT;
|
||||||
|
break;
|
||||||
|
case CommonFileDialogType::SaveFile:
|
||||||
|
dwFlags |= FOS_FORCEFILESYSTEM;
|
||||||
|
dwFlags |= FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
|
||||||
|
break;
|
||||||
|
case CommonFileDialogType::OpenFolder:
|
||||||
|
dwFlags |= FOS_FORCEFILESYSTEM;
|
||||||
|
dwFlags |= FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
|
||||||
|
dwFlags |= FOS_PICKFOLDERS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// set folder dialog options
|
||||||
|
hr = pfd->SetOptions(dwFlags);
|
||||||
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
|
// set title
|
||||||
|
std::wstring wtitle, winit_filename, winit_directory;
|
||||||
|
if (params.GetTitle() != nullptr) {
|
||||||
|
EncodingHelper::UTF8ToWchar(params.GetTitle(), wtitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set file types and default file index when we picking file
|
||||||
|
WinFileFilters win_file_filters;
|
||||||
|
if constexpr (EDialogType != CommonFileDialogType::OpenFolder) {
|
||||||
|
// generate data from user specified file filters
|
||||||
|
const auto& file_filters = params.GetFileTypes();
|
||||||
|
if (!file_filters.Generate(win_file_filters))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// set file types list
|
||||||
|
hr = pfd->SetFileTypes(win_file_filters.GetFilterCount(), win_file_filters.GetFilterSpecs());
|
||||||
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
|
// set default file type index
|
||||||
|
// Windows order this is 1-based index.
|
||||||
|
// We plus 1 for it because we used is 0-based index.
|
||||||
|
hr = pfd->SetFileTypeIndex(params.GetDefaultFileTypeIndex() + 1);
|
||||||
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoCreate the File Open Dialog object.
|
||||||
|
IFileDialog* pfd = NULL;
|
||||||
|
HRESULT hr = CoCreateInstance(
|
||||||
|
CLSID_FileOpenDialog,
|
||||||
|
NULL,
|
||||||
|
CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&pfd)
|
||||||
|
);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// Set the options on the dialog.
|
||||||
|
DWORD dwFlags;
|
||||||
|
|
||||||
|
// Before setting, always get the options first in order
|
||||||
|
// not to override existing options.
|
||||||
|
hr = pfd->GetOptions(&dwFlags);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// In this case, get shell items only for file system items.
|
||||||
|
hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// Set the file types to display only.
|
||||||
|
// Notice that this is a 1-based array.
|
||||||
|
hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// Set the selected file type index to Word Docs for this example.
|
||||||
|
hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// Set the default extension to be ".doc" file.
|
||||||
|
hr = pfd->SetDefaultExtension(L"doc;docx");
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// Show the dialog
|
||||||
|
hr = pfd->Show(NULL);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// Obtain the result once the user clicks
|
||||||
|
// the 'Open' button.
|
||||||
|
// The result is an IShellItem object.
|
||||||
|
IShellItem* psiResult;
|
||||||
|
hr = pfd->GetResult(&psiResult);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// We are just going to print out the
|
||||||
|
// name of the file for sample sake.
|
||||||
|
PWSTR pszFilePath = NULL;
|
||||||
|
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
|
||||||
|
&pszFilePath);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
TaskDialog(NULL,
|
||||||
|
NULL,
|
||||||
|
L"CommonFileDialogApp",
|
||||||
|
pszFilePath,
|
||||||
|
NULL,
|
||||||
|
TDCBF_OK_BUTTON,
|
||||||
|
TD_INFORMATION_ICON,
|
||||||
|
NULL);
|
||||||
|
CoTaskMemFree(pszFilePath);
|
||||||
|
}
|
||||||
|
psiResult->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pfd->Release();
|
||||||
|
}
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Wrapper Functions
|
||||||
|
|
||||||
|
bool OpenFileDialog(const FileDialog& params, std::string& ret) {
|
||||||
|
std::vector<std::string> cache;
|
||||||
|
bool isok = CommonFileDialog<CommonFileDialogType::OpenFile>(params, cache);
|
||||||
|
if (isok) ret = cache.front();
|
||||||
|
return isok;
|
||||||
|
}
|
||||||
|
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<std::string>& ret) {
|
||||||
|
return CommonFileDialog<CommonFileDialogType::OpenMultipleFiles>(params, ret);
|
||||||
|
}
|
||||||
|
bool SaveFileDialog(const FileDialog& params, std::string& ret) {
|
||||||
|
std::vector<std::string> cache;
|
||||||
|
bool isok = CommonFileDialog<CommonFileDialogType::SaveFile>(params, cache);
|
||||||
|
if (isok) ret = cache.front();
|
||||||
|
return isok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenFolderDialog(const FileDialog& params, std::string& ret) {
|
||||||
|
std::vector<std::string> cache;
|
||||||
|
bool isok = CommonFileDialog<CommonFileDialogType::OpenFolder>(params, cache);
|
||||||
|
if (isok) ret = cache.front();
|
||||||
|
return isok;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace YYCC::DialogHelper {
|
||||||
*/
|
*/
|
||||||
class FileFilters {
|
class FileFilters {
|
||||||
public:
|
public:
|
||||||
FileFilters() : m_Filters(){}
|
FileFilters() : m_Filters() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a filter pair in file types list.
|
* @brief Add a filter pair in file types list.
|
||||||
|
@ -86,6 +86,39 @@ namespace YYCC::DialogHelper {
|
||||||
std::vector<FilterPair> m_Filters;
|
std::vector<FilterPair> m_Filters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WinFileDialog {
|
||||||
|
friend class FileDialog;
|
||||||
|
public:
|
||||||
|
WinFileDialog() :
|
||||||
|
m_WinOwner(NULL),
|
||||||
|
m_WinFileTypes(), m_WinDefaultFileTypeIndex(0u),
|
||||||
|
m_HasTitle(false), m_HasInitFileName(false), m_WinTitle(), m_WinInitFileName(),
|
||||||
|
m_WinInitDirectory(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool HasOwner() const { return m_WinOwner != NULL; }
|
||||||
|
HWND GetOwner() const { return m_WinOwner; }
|
||||||
|
|
||||||
|
bool HasTitle() const { return !m_WinTitle.empty(); }
|
||||||
|
const wchar_t* GetTitle() const { return m_WinTitle.c_str(); }
|
||||||
|
bool HasInitFileName() const { return !m_WinInitFileName.empty(); }
|
||||||
|
const wchar_t* GetInitFileName() const { return m_WinInitFileName.c_str(); }
|
||||||
|
bool HasInitDirectory() const { return m_WinInitDirectory != nullptr;}
|
||||||
|
const IShellItem* GetInitDirectory() const { return m_WinInitDirectory.get(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HWND m_WinOwner;
|
||||||
|
|
||||||
|
WinFileFilters m_WinFileTypes;
|
||||||
|
UINT m_WinDefaultFileTypeIndex;
|
||||||
|
|
||||||
|
bool m_HasTitle, m_HasInitFileName;
|
||||||
|
std::wstring m_WinTitle, m_WinInitFileName;
|
||||||
|
|
||||||
|
using SmartShellItem = std::unique_ptr<IShellItem, std::function<void(IShellItem*)>>;
|
||||||
|
SmartShellItem m_WinInitDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
class FileDialog {
|
class FileDialog {
|
||||||
public:
|
public:
|
||||||
FileDialog() :
|
FileDialog() :
|
||||||
|
@ -95,52 +128,38 @@ namespace YYCC::DialogHelper {
|
||||||
m_InitFileName(), m_InitDirectory() {}
|
m_InitFileName(), m_InitDirectory() {}
|
||||||
|
|
||||||
void SetOwner(HWND owner) { m_Owner = owner; }
|
void SetOwner(HWND owner) { m_Owner = owner; }
|
||||||
HWND GetOwner() const { return m_Owner; }
|
|
||||||
|
|
||||||
void SetTitle(const char* title) {
|
void SetTitle(const char* title) {
|
||||||
if (title == nullptr) m_Title.clear();
|
if (m_HasTitle = title != nullptr)
|
||||||
else m_Title = title;
|
m_Title = title;
|
||||||
}
|
}
|
||||||
const char* GetTitle() const {
|
FileFilters& ConfigreFileTypes() {
|
||||||
if (m_Title.empty()) return nullptr;
|
|
||||||
else return m_Title.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileFilters& GetFileTypes() {
|
|
||||||
return m_FileTypes;
|
return m_FileTypes;
|
||||||
}
|
}
|
||||||
const FileFilters& GetFileTypes() const {
|
|
||||||
return m_FileTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetDefaultFileTypeIndex(UINT idx) { m_DefaultFileTypeIndex = idx; }
|
void SetDefaultFileTypeIndex(UINT idx) { m_DefaultFileTypeIndex = idx; }
|
||||||
UINT GetDefaultFileTypeIndex() const { return m_DefaultFileTypeIndex; }
|
|
||||||
|
|
||||||
void SetInitFileName(const char* init_filename) {
|
void SetInitFileName(const char* init_filename) {
|
||||||
if (init_filename == nullptr) m_InitFileName.clear();
|
if (m_HasInitFileName = init_filename != nullptr)
|
||||||
else m_InitFileName = init_filename;
|
m_InitFileName = init_filename;
|
||||||
}
|
}
|
||||||
const char* GetInitFileName() const {
|
|
||||||
if (m_InitFileName.empty()) return nullptr;
|
|
||||||
else return m_InitFileName.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetInitDirectory(const char* init_dir) {
|
void SetInitDirectory(const char* init_dir) {
|
||||||
if (init_dir == nullptr) m_InitDirectory.clear();
|
if (m_HasInitDirectory = init_dir != nullptr)
|
||||||
else m_InitDirectory = init_dir;
|
m_InitDirectory = init_dir;
|
||||||
}
|
|
||||||
const char* GetInitDirectory() const {
|
|
||||||
if (m_InitDirectory.empty()) return nullptr;
|
|
||||||
else return m_InitDirectory.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
bool Generate(WinFileDialog& win_result) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
HWND m_Owner;
|
HWND m_Owner;
|
||||||
std::string m_Title;
|
|
||||||
|
bool m_HasTitle, m_HasInitFileName, m_HasInitDirectory;
|
||||||
|
std::string m_Title, m_InitFileName, m_InitDirectory;
|
||||||
|
|
||||||
FileFilters m_FileTypes;
|
FileFilters m_FileTypes;
|
||||||
|
/**
|
||||||
|
* @brief The default file type selected in dialog
|
||||||
|
* @remarks Although Windows notice that this is a 1-based index,
|
||||||
|
* but for universal experience, we order this is 0-based index.
|
||||||
|
*/
|
||||||
UINT m_DefaultFileTypeIndex;
|
UINT m_DefaultFileTypeIndex;
|
||||||
std::string m_InitFileName;
|
|
||||||
std::string m_InitDirectory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool OpenFileDialog(const FileDialog& params, std::string& ret);
|
bool OpenFileDialog(const FileDialog& params, std::string& ret);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user