2024-04-26 15:37:28 +08:00
|
|
|
#pragma once
|
|
|
|
#include "YYCCInternal.hpp"
|
|
|
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
|
|
|
2024-06-17 12:46:32 +08:00
|
|
|
#include "COMHelper.hpp"
|
2024-04-26 15:37:28 +08:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2024-05-22 15:53:46 +08:00
|
|
|
#include <initializer_list>
|
2024-04-26 15:37:28 +08:00
|
|
|
|
|
|
|
#include "WinImportPrefix.hpp"
|
|
|
|
#include <Windows.h>
|
2024-04-29 15:48:10 +08:00
|
|
|
#include <shlobj_core.h>
|
2024-04-26 15:37:28 +08:00
|
|
|
#include "WinImportSuffix.hpp"
|
|
|
|
|
|
|
|
namespace YYCC::DialogHelper {
|
|
|
|
|
2024-05-23 09:37:41 +08:00
|
|
|
/**
|
|
|
|
* @brief The class represent the file types region in file dialog
|
|
|
|
* @details THis class is specific for Windows use, not user oriented.
|
|
|
|
*/
|
|
|
|
class WinFileFilters {
|
|
|
|
friend class FileFilters;
|
2024-05-27 14:27:11 +08:00
|
|
|
friend class WinFileDialog;
|
2024-05-23 09:37:41 +08:00
|
|
|
public:
|
|
|
|
WinFileFilters() : m_WinFilters(), m_WinDataStruct(nullptr) {}
|
|
|
|
|
|
|
|
UINT GetFilterCount() const {
|
|
|
|
return static_cast<UINT>(m_WinFilters.size());
|
|
|
|
}
|
|
|
|
const COMDLG_FILTERSPEC* GetFilterSpecs() const {
|
|
|
|
return m_WinDataStruct.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
using WinFilterModes = std::wstring;
|
|
|
|
using WinFilterName = std::wstring;
|
|
|
|
using WinFilterPair = std::pair<WinFilterName, WinFilterModes>;
|
|
|
|
|
|
|
|
std::vector<WinFilterPair> m_WinFilters;
|
|
|
|
std::unique_ptr<COMDLG_FILTERSPEC[]> m_WinDataStruct;
|
2024-05-27 14:27:11 +08:00
|
|
|
|
|
|
|
void Clear() {
|
|
|
|
m_WinDataStruct.reset();
|
|
|
|
m_WinFilters.clear();
|
|
|
|
}
|
2024-05-23 09:37:41 +08:00
|
|
|
};
|
|
|
|
|
2024-05-22 15:53:46 +08:00
|
|
|
/**
|
|
|
|
* @brief The class represent the file types region in file dialog.
|
2024-05-27 14:27:11 +08:00
|
|
|
* @details This class is user oriented. User can use function manipulate file types
|
|
|
|
* and final generation function will produce Windows-understood data struct from this.
|
2024-05-22 15:53:46 +08:00
|
|
|
*/
|
|
|
|
class FileFilters {
|
|
|
|
public:
|
2024-05-26 20:20:59 +08:00
|
|
|
FileFilters() : m_Filters() {}
|
2024-05-22 15:53:46 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add a filter pair in file types list.
|
|
|
|
* @param filter_name[in] The friendly name of the filter.
|
|
|
|
* @param il[in] A C++ initialize list.
|
|
|
|
* Every entries must be `const char*` represent a single filter pattern.
|
|
|
|
* The list at least should have one valid pattern.
|
|
|
|
* This function will not validate these filter patterns, so please write them carefully.
|
|
|
|
* @return True if added success, otherwise false.
|
|
|
|
* @remarks This function allow you register multiple filter patterns for single friendly name.
|
|
|
|
* For example: `Add("Microsoft Word (*.doc; *.docx)", {"*.doc", "*.docx"})`
|
|
|
|
*/
|
|
|
|
bool Add(const char* filter_name, std::initializer_list<const char*> il);
|
|
|
|
/**
|
|
|
|
* @brief Clear filter pairs for following re-use.
|
|
|
|
*/
|
2024-05-23 09:37:41 +08:00
|
|
|
void Clear() { m_Filters.clear(); }
|
|
|
|
/**
|
|
|
|
* @brief Get the count of added filter pairs.
|
|
|
|
* @return The count of already added filter pairs.
|
|
|
|
*/
|
|
|
|
size_t Count() const { return m_Filters.size(); }
|
2024-05-22 15:53:46 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Generate Windows dialog system used data struct.
|
2024-05-23 09:37:41 +08:00
|
|
|
* @param win_result[out] The class holding the generated filter data struct.
|
2024-05-22 15:53:46 +08:00
|
|
|
* @return True if generation is success, otherwise false.
|
2024-05-27 21:21:39 +08:00
|
|
|
* @remarks User should not call this function, this function is used in internal code.
|
2024-05-22 15:53:46 +08:00
|
|
|
*/
|
2024-05-23 09:37:41 +08:00
|
|
|
bool Generate(WinFileFilters& win_result) const;
|
2024-05-22 15:53:46 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
using FilterModes = std::vector<std::string>;
|
|
|
|
using FilterName = std::string;
|
|
|
|
using FilterPair = std::pair<FilterName, FilterModes>;
|
|
|
|
|
|
|
|
std::vector<FilterPair> m_Filters;
|
2024-05-23 09:37:41 +08:00
|
|
|
};
|
2024-05-22 15:53:46 +08:00
|
|
|
|
2024-05-27 14:27:11 +08:00
|
|
|
/**
|
|
|
|
* @brief The class represent the file dialog
|
|
|
|
* @details THis class is specific for Windows use, not user oriented.
|
|
|
|
*/
|
2024-05-26 20:20:59 +08:00
|
|
|
class WinFileDialog {
|
|
|
|
friend class FileDialog;
|
|
|
|
public:
|
|
|
|
WinFileDialog() :
|
|
|
|
m_WinOwner(NULL),
|
|
|
|
m_WinFileTypes(), m_WinDefaultFileTypeIndex(0u),
|
2024-05-27 14:27:11 +08:00
|
|
|
m_HasTitle(false), m_HasInitFileName(false), m_WinTitle(), m_WinInitFileName(),
|
|
|
|
m_WinInitDirectory(nullptr) {}
|
2024-05-26 20:20:59 +08:00
|
|
|
|
|
|
|
bool HasOwner() const { return m_WinOwner != NULL; }
|
|
|
|
HWND GetOwner() const { return m_WinOwner; }
|
|
|
|
|
2024-05-27 14:27:11 +08:00
|
|
|
const WinFileFilters& GetFileTypes() const { return m_WinFileTypes; }
|
|
|
|
UINT GetDefaultFileTypeIndex() const { return m_WinDefaultFileTypeIndex; }
|
|
|
|
|
|
|
|
bool HasTitle() const { return m_HasTitle; }
|
2024-05-26 20:20:59 +08:00
|
|
|
const wchar_t* GetTitle() const { return m_WinTitle.c_str(); }
|
2024-05-27 14:27:11 +08:00
|
|
|
bool HasInitFileName() const { return m_HasInitFileName; }
|
2024-05-26 20:20:59 +08:00
|
|
|
const wchar_t* GetInitFileName() const { return m_WinInitFileName.c_str(); }
|
2024-05-27 14:27:11 +08:00
|
|
|
|
|
|
|
bool HasInitDirectory() const { return m_WinInitDirectory.get() != nullptr; }
|
|
|
|
IShellItem* GetInitDirectory() const { return m_WinInitDirectory.get(); }
|
2024-05-26 20:20:59 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
HWND m_WinOwner;
|
|
|
|
WinFileFilters m_WinFileTypes;
|
2024-05-27 14:27:11 +08:00
|
|
|
/**
|
|
|
|
* @brief The default selected file type in dialog
|
|
|
|
* @remarks This is 1-based index according to Windows specification.
|
2024-05-27 21:21:39 +08:00
|
|
|
* In other words, you should plus 1 for this index when generating this struct from
|
|
|
|
* user oriented file dialog parameters.
|
2024-05-27 14:27:11 +08:00
|
|
|
*/
|
2024-05-26 20:20:59 +08:00
|
|
|
UINT m_WinDefaultFileTypeIndex;
|
|
|
|
bool m_HasTitle, m_HasInitFileName;
|
|
|
|
std::wstring m_WinTitle, m_WinInitFileName;
|
2024-06-17 12:46:32 +08:00
|
|
|
COMHelper::SmartIShellItem m_WinInitDirectory;
|
2024-05-27 14:27:11 +08:00
|
|
|
|
|
|
|
void Clear() {
|
|
|
|
m_WinOwner = nullptr;
|
|
|
|
m_WinFileTypes.Clear();
|
|
|
|
m_WinDefaultFileTypeIndex = 0u;
|
|
|
|
m_HasTitle = m_HasInitFileName = false;
|
|
|
|
m_WinTitle.clear();
|
|
|
|
m_WinInitFileName.clear();
|
|
|
|
m_WinInitDirectory.reset();
|
|
|
|
}
|
2024-05-26 20:20:59 +08:00
|
|
|
};
|
|
|
|
|
2024-05-27 14:27:11 +08:00
|
|
|
/**
|
|
|
|
* @brief The class represent the file dialog.
|
|
|
|
* @details This class is user oriented. User can use function manipulate file dialog properties
|
|
|
|
* and final generation function will produce Windows-understood data struct from this.
|
|
|
|
*/
|
2024-05-23 09:37:41 +08:00
|
|
|
class FileDialog {
|
|
|
|
public:
|
|
|
|
FileDialog() :
|
2024-05-27 14:27:11 +08:00
|
|
|
m_Owner(NULL),
|
2024-05-23 09:37:41 +08:00
|
|
|
m_FileTypes(),
|
|
|
|
m_DefaultFileTypeIndex(0u),
|
2024-05-27 14:27:11 +08:00
|
|
|
m_Title(), m_InitFileName(), m_InitDirectory(),
|
|
|
|
m_HasTitle(false), m_HasInitFileName(false), m_HasInitDirectory(false) {}
|
2024-05-23 09:37:41 +08:00
|
|
|
|
|
|
|
void SetOwner(HWND owner) { m_Owner = owner; }
|
|
|
|
void SetTitle(const char* title) {
|
2024-05-26 20:20:59 +08:00
|
|
|
if (m_HasTitle = title != nullptr)
|
|
|
|
m_Title = title;
|
2024-05-23 09:37:41 +08:00
|
|
|
}
|
2024-05-26 20:20:59 +08:00
|
|
|
FileFilters& ConfigreFileTypes() {
|
2024-05-23 09:37:41 +08:00
|
|
|
return m_FileTypes;
|
|
|
|
}
|
2024-05-27 14:27:11 +08:00
|
|
|
void SetDefaultFileTypeIndex(size_t idx) { m_DefaultFileTypeIndex = idx; }
|
2024-05-23 09:37:41 +08:00
|
|
|
void SetInitFileName(const char* init_filename) {
|
2024-05-26 20:20:59 +08:00
|
|
|
if (m_HasInitFileName = init_filename != nullptr)
|
|
|
|
m_InitFileName = init_filename;
|
2024-05-23 09:37:41 +08:00
|
|
|
}
|
|
|
|
void SetInitDirectory(const char* init_dir) {
|
2024-05-26 20:20:59 +08:00
|
|
|
if (m_HasInitDirectory = init_dir != nullptr)
|
|
|
|
m_InitDirectory = init_dir;
|
2024-05-23 09:37:41 +08:00
|
|
|
}
|
|
|
|
|
2024-05-27 21:21:39 +08:00
|
|
|
/**
|
|
|
|
* @brief Clear file dialog parameters for following re-use.
|
|
|
|
*/
|
2024-05-27 14:27:11 +08:00
|
|
|
void Clear() {
|
|
|
|
m_Owner = nullptr;
|
|
|
|
m_HasTitle = m_HasInitFileName = m_HasInitDirectory = false;
|
|
|
|
m_Title.clear();
|
|
|
|
m_InitFileName.clear();
|
|
|
|
m_InitDirectory.clear();
|
|
|
|
m_FileTypes.Clear();
|
|
|
|
m_DefaultFileTypeIndex = 0u;
|
|
|
|
}
|
2024-05-27 21:21:39 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Generate Windows dialog system used data struct.
|
|
|
|
* @param win_result[out] The class holding the generated filter data struct.
|
|
|
|
* @return True if generation is success, otherwise false.
|
|
|
|
* @remarks User should not call this function, this function is used in internal code.
|
|
|
|
*/
|
2024-05-26 20:20:59 +08:00
|
|
|
bool Generate(WinFileDialog& win_result) const;
|
|
|
|
|
|
|
|
protected:
|
2024-05-23 09:37:41 +08:00
|
|
|
HWND m_Owner;
|
2024-05-26 20:20:59 +08:00
|
|
|
bool m_HasTitle, m_HasInitFileName, m_HasInitDirectory;
|
|
|
|
std::string m_Title, m_InitFileName, m_InitDirectory;
|
2024-05-23 09:37:41 +08:00
|
|
|
FileFilters m_FileTypes;
|
2024-05-26 20:20:59 +08:00
|
|
|
/**
|
2024-05-27 14:27:11 +08:00
|
|
|
* @brief The default selected file type in dialog
|
2024-05-26 20:20:59 +08:00
|
|
|
* @remarks Although Windows notice that this is a 1-based index,
|
|
|
|
* but for universal experience, we order this is 0-based index.
|
|
|
|
*/
|
2024-05-27 14:27:11 +08:00
|
|
|
size_t m_DefaultFileTypeIndex;
|
2024-05-22 15:53:46 +08:00
|
|
|
};
|
|
|
|
|
2024-05-23 09:37:41 +08:00
|
|
|
bool OpenFileDialog(const FileDialog& params, std::string& ret);
|
|
|
|
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<std::string>& ret);
|
|
|
|
bool SaveFileDialog(const FileDialog& params, std::string& ret);
|
|
|
|
|
|
|
|
bool OpenFolderDialog(const FileDialog& params, std::string& ret);
|
2024-04-26 15:37:28 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|