aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp')
-rw-r--r--Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp229
1 files changed, 229 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp
new file mode 100644
index 00000000..4adaa2ef
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/mptrack/FileDialog.cpp
@@ -0,0 +1,229 @@
+/*
+ * FileDialog.cpp
+ * --------------
+ * Purpose: File and folder selection dialogs implementation.
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "FileDialog.h"
+#include "Mainfrm.h"
+#include "InputHandler.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+class CFileDialogEx : public CFileDialog
+{
+public:
+ CFileDialogEx(bool bOpenFileDialog,
+ LPCTSTR lpszDefExt,
+ LPCTSTR lpszFileName,
+ DWORD dwFlags,
+ LPCTSTR lpszFilter,
+ CWnd *pParentWnd,
+ DWORD dwSize,
+ BOOL bVistaStyle,
+ bool preview)
+ : CFileDialog(bOpenFileDialog ? TRUE : FALSE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd, dwSize, bVistaStyle)
+ , m_fileNameBuf(65536)
+ , doPreview(preview)
+ , played(false)
+ {
+ // MFC's filename buffer is way too small for multi-selections of a large number of files.
+ _tcsncpy(m_fileNameBuf.data(), lpszFileName, m_fileNameBuf.size());
+ m_fileNameBuf.back() = '\0';
+ m_ofn.lpstrFile = m_fileNameBuf.data();
+ m_ofn.nMaxFile = mpt::saturate_cast<DWORD>(m_fileNameBuf.size());
+ }
+
+ ~CFileDialogEx()
+ {
+ if(played)
+ {
+ CMainFrame::GetMainFrame()->StopPreview();
+ }
+ }
+
+#if NTDDI_VERSION >= NTDDI_VISTA
+ // MFC's AddPlace() is declared as throw() but can in fact throw if any of the COM calls fail, e.g. because the place does not exist.
+ // Avoid this by re-implementing our own version which doesn't throw.
+ void AddPlace(const mpt::PathString &path)
+ {
+ if(m_bVistaStyle && path.IsDirectory())
+ {
+ CComPtr<IShellItem> shellItem;
+ HRESULT hr = SHCreateItemFromParsingName(path.ToWide().c_str(), nullptr, IID_IShellItem, reinterpret_cast<void **>(&shellItem));
+ if(SUCCEEDED(hr))
+ {
+ static_cast<IFileDialog*>(m_pIFileDialog)->AddPlace(shellItem, FDAP_TOP);
+ }
+ }
+ }
+#endif
+
+protected:
+ std::vector<TCHAR> m_fileNameBuf;
+ CString oldName;
+ bool doPreview, played;
+
+ void OnFileNameChange() override
+ {
+ if(doPreview)
+ {
+ CString name = GetPathName();
+ if(!name.IsEmpty() && name != oldName)
+ {
+ oldName = name;
+ if(CMainFrame::GetMainFrame()->PlaySoundFile(mpt::PathString::FromCString(name), NOTE_MIDDLEC))
+ {
+ played = true;
+ }
+ }
+ }
+ CFileDialog::OnFileNameChange();
+ }
+};
+
+
+// Display the file dialog.
+bool FileDialog::Show(CWnd *parent)
+{
+ m_filenames.clear();
+
+ // First, set up the dialog...
+ CFileDialogEx dlg(m_load,
+ m_defaultExtension.empty() ? nullptr : m_defaultExtension.c_str(),
+ m_defaultFilename.c_str(),
+ OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | (m_multiSelect ? OFN_ALLOWMULTISELECT : 0) | (m_load ? 0 : (OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN)),
+ m_extFilter.c_str(),
+ parent != nullptr ? parent : CMainFrame::GetMainFrame(),
+ 0,
+ (mpt::OS::Windows::IsWine() || mpt::OS::Windows::Version::Current().IsBefore(mpt::OS::Windows::Version::WinVista)) ? FALSE : TRUE,
+ m_preview && TrackerSettings::Instance().previewInFileDialogs);
+ OPENFILENAME &ofn = dlg.GetOFN();
+ ofn.nFilterIndex = m_filterIndex != nullptr ? *m_filterIndex : 0;
+ if(!m_workingDirectory.empty())
+ {
+ ofn.lpstrInitialDir = m_workingDirectory.c_str();
+ }
+#if NTDDI_VERSION >= NTDDI_VISTA
+ const auto places =
+ {
+ &TrackerSettings::Instance().PathPluginPresets,
+ &TrackerSettings::Instance().PathPlugins,
+ &TrackerSettings::Instance().PathSamples,
+ &TrackerSettings::Instance().PathInstruments,
+ &TrackerSettings::Instance().PathSongs,
+ };
+ for(const auto place : places)
+ {
+ dlg.AddPlace(place->GetDefaultDir());
+ }
+ for(const auto &place : m_places)
+ {
+ dlg.AddPlace(place);
+ }
+#endif
+
+ // Do it!
+ BypassInputHandler bih;
+ if(dlg.DoModal() != IDOK)
+ {
+ return false;
+ }
+
+ // Retrieve variables
+ if(m_filterIndex != nullptr)
+ *m_filterIndex = ofn.nFilterIndex;
+
+ if(m_multiSelect)
+ {
+#if NTDDI_VERSION >= NTDDI_VISTA
+ // Multiple files might have been selected
+ if(CComPtr<IShellItemArray> shellItems = dlg.GetResults(); shellItems != nullptr)
+ {
+ // Using the old-style GetNextPathName doesn't work properly when the user performs a search and selects files from different folders.
+ // Hence we use that only as a fallback.
+ DWORD numItems = 0;
+ shellItems->GetCount(&numItems);
+ for(DWORD i = 0; i < numItems; i++)
+ {
+ CComPtr<IShellItem> shellItem;
+ shellItems->GetItemAt(i, &shellItem);
+
+ LPWSTR filePath = nullptr;
+ if(HRESULT hr = shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath); SUCCEEDED(hr))
+ {
+ m_filenames.push_back(mpt::PathString::FromWide(filePath));
+ ::CoTaskMemFree(filePath);
+ }
+ }
+ } else
+#endif
+ {
+ POSITION pos = dlg.GetStartPosition();
+ while(pos != nullptr)
+ {
+ m_filenames.push_back(mpt::PathString::FromCString(dlg.GetNextPathName(pos)));
+ }
+ }
+ } else
+ {
+ // Only one file
+ m_filenames.push_back(mpt::PathString::FromCString(dlg.GetPathName()));
+ }
+
+ if(m_filenames.empty())
+ {
+ return false;
+ }
+
+ m_workingDirectory = m_filenames.front().AsNative().substr(0, ofn.nFileOffset);
+ m_extension = m_filenames.front().AsNative().substr(ofn.nFileExtension);
+
+ return true;
+}
+
+
+// Helper callback to set start path.
+int CALLBACK BrowseForFolder::BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /*lParam*/, LPARAM lpData)
+{
+ if(uMsg == BFFM_INITIALIZED && lpData != NULL)
+ {
+ const BrowseForFolder *that = reinterpret_cast<BrowseForFolder *>(lpData);
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, reinterpret_cast<LPARAM>(that->m_workingDirectory.AsNative().c_str()));
+ }
+ return 0;
+}
+
+
+// Display the folder dialog.
+bool BrowseForFolder::Show(CWnd *parent)
+{
+ // Note: MFC's CFolderPickerDialog won't work on pre-Vista systems, as it tries to use OPENFILENAME.
+ BypassInputHandler bih;
+ TCHAR path[MAX_PATH];
+ BROWSEINFO bi;
+ MemsetZero(bi);
+ bi.hwndOwner = (parent != nullptr ? parent : theApp.m_pMainWnd)->m_hWnd;
+ if(!m_caption.IsEmpty()) bi.lpszTitle = m_caption;
+ bi.pszDisplayName = path;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
+ bi.lpfn = BrowseCallbackProc;
+ bi.lParam = reinterpret_cast<LPARAM>(this);
+ LPITEMIDLIST pid = SHBrowseForFolder(&bi);
+ bool success = pid != nullptr && SHGetPathFromIDList(pid, path);
+ CoTaskMemFree(pid);
+ if(success)
+ {
+ m_workingDirectory = mpt::PathString::FromNative(path);
+ }
+ return success;
+}
+
+
+OPENMPT_NAMESPACE_END