Files
Xenia-Canary/src/xenia/ui/file_picker_win.cc
Triang3l fe3f0f26e4 [UI] Image post-processing and full presentation/window rework
[GPU] Add FXAA post-processing
[UI] Add FidelityFX FSR and CAS post-processing
[UI] Add blue noise dithering from 10bpc to 8bpc
[GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color
[UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event
[UI] Allow variable refresh rate (or tearing)
[UI] Present the newest frame (restart) on DXGI
[UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management
[UI] Connect presentation to windows via the Surface class, not native window handles
[Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around
[Vulkan] Lower the minimum required Vulkan version to 1.0
[UI/GPU] Various cleanup, mainly ComPtr usage
[UI] Support per-monitor DPI awareness v2 on Windows
[UI] DPI-scale Dear ImGui
[UI] Replace the remaining non-detachable window delegates with unified window event and input listeners
[UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem
[UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing
[UI] Add explicit window lifecycle phases
[UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback
[UI] GTK: Apply the initial size to the drawing area
[UI] Limit internal UI frame rate to that of the monitor
[UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
2022-01-29 13:22:03 +03:00

215 lines
6.5 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/assert.h"
#include "xenia/base/platform_win.h"
#include "xenia/base/string.h"
#include "xenia/ui/file_picker.h"
#include "xenia/ui/window_win.h"
// Microsoft headers after platform_win.h.
#include <wrl/client.h>
namespace xe {
namespace ui {
class Win32FilePicker : public FilePicker {
public:
Win32FilePicker();
~Win32FilePicker() override;
bool Show(Window* parent_window) override;
private:
};
std::unique_ptr<FilePicker> FilePicker::Create() {
return std::make_unique<Win32FilePicker>();
}
class CDialogEventHandler : public IFileDialogEvents,
public IFileDialogControlEvents {
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) {
// dwOffset may be a DWORD or an int depending on compiler/SDK version.
static const QITAB qit[] = {
{&__uuidof(IFileDialogEvents),
static_cast<decltype(qit[0].dwOffset)>(
OFFSETOFCLASS(IFileDialogEvents, CDialogEventHandler))},
{&__uuidof(IFileDialogControlEvents),
static_cast<decltype(qit[1].dwOffset)>(
OFFSETOFCLASS(IFileDialogControlEvents, CDialogEventHandler))},
{0},
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&_cRef); }
IFACEMETHODIMP_(ULONG) Release() {
long cRef = InterlockedDecrement(&_cRef);
if (!cRef) delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog*) { return S_OK; }
IFACEMETHODIMP OnFolderChange(IFileDialog*) { return S_OK; }
IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return S_OK; }
IFACEMETHODIMP OnHelp(IFileDialog*) { return S_OK; }
IFACEMETHODIMP OnSelectionChange(IFileDialog*) { return S_OK; }
IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*,
FDE_SHAREVIOLATION_RESPONSE*) {
return S_OK;
}
IFACEMETHODIMP OnTypeChange(IFileDialog* pfd) { return S_OK; }
IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*,
FDE_OVERWRITE_RESPONSE*) {
return S_OK;
}
// IFileDialogControlEvents methods
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize* pfdc, DWORD dwIDCtl,
DWORD dwIDItem) {
return S_OK;
}
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize*, DWORD) { return S_OK; }
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize*, DWORD, BOOL) {
return S_OK;
}
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize*, DWORD) {
return S_OK;
}
CDialogEventHandler() : _cRef(1) {}
private:
virtual ~CDialogEventHandler() = default;
long _cRef;
};
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void** ppv) {
*ppv = NULL;
auto dialog_event_handler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = dialog_event_handler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr)) {
hr = dialog_event_handler->QueryInterface(riid, ppv);
dialog_event_handler->Release();
}
return hr;
}
Win32FilePicker::Win32FilePicker() = default;
Win32FilePicker::~Win32FilePicker() = default;
bool Win32FilePicker::Show(Window* parent_window) {
// TODO(benvanik): FileSaveDialog.
assert_true(mode() == Mode::kOpen);
// TODO(benvanik): folder dialogs.
assert_true(type() == Type::kFile);
Microsoft::WRL::ComPtr<IFileDialog> file_dialog;
HRESULT hr =
CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&file_dialog));
if (!SUCCEEDED(hr)) {
return false;
}
hr = file_dialog->SetTitle((LPCWSTR)xe::to_utf16(title()).c_str());
if (!SUCCEEDED(hr)) {
return false;
}
DWORD flags;
hr = file_dialog->GetOptions(&flags);
if (!SUCCEEDED(hr)) {
return false;
}
// FOS_PICKFOLDERS
// FOS_FILEMUSTEXIST
// FOS_PATHMUSTEXIST
flags |= FOS_FORCEFILESYSTEM;
if (multi_selection()) {
flags |= FOS_ALLOWMULTISELECT;
}
hr = file_dialog->SetOptions(flags);
if (!SUCCEEDED(hr)) {
return false;
}
// Set the file types to display only. Notice that this is a 1-based array.
std::vector<std::pair<std::u16string, std::u16string>> file_pairs;
std::vector<COMDLG_FILTERSPEC> file_types;
for (const auto& extension : this->extensions()) {
const auto& file_pair =
file_pairs.emplace_back(std::move(xe::to_utf16(extension.first)),
std::move(xe::to_utf16(extension.second)));
file_types.push_back(
{(LPCWSTR)file_pair.first.c_str(), (LPCWSTR)file_pair.second.c_str()});
}
hr = file_dialog->SetFileTypes(static_cast<UINT>(file_types.size()),
file_types.data());
if (!SUCCEEDED(hr)) {
return false;
}
hr = file_dialog->SetFileTypeIndex(1);
if (!SUCCEEDED(hr)) {
return false;
}
// Create an event handling object, and hook it up to the dialog.
Microsoft::WRL::ComPtr<IFileDialogEvents> file_dialog_events;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&file_dialog_events));
if (!SUCCEEDED(hr)) {
return false;
}
DWORD cookie;
hr = file_dialog->Advise(file_dialog_events.Get(), &cookie);
if (!SUCCEEDED(hr)) {
return false;
}
// Show the dialog modally.
hr = file_dialog->Show(
parent_window ? static_cast<const Win32Window*>(parent_window)->hwnd()
: nullptr);
file_dialog->Unadvise(cookie);
if (!SUCCEEDED(hr)) {
return false;
}
// Obtain the result once the user clicks the 'Open' button.
// The result is an IShellItem object.
Microsoft::WRL::ComPtr<IShellItem> shell_item;
hr = file_dialog->GetResult(&shell_item);
if (!SUCCEEDED(hr)) {
return false;
}
// We are just going to print out the name of the file for sample sake.
PWSTR file_path = nullptr;
hr = shell_item->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
if (!SUCCEEDED(hr)) {
return false;
}
std::vector<std::filesystem::path> selected_files;
selected_files.push_back(std::filesystem::path(file_path));
set_selected_files(selected_files);
CoTaskMemFree(file_path);
return true;
}
} // namespace ui
} // namespace xe