Qt: Implement drag/drop to main window

This commit is contained in:
Connor McLaughlin 2022-05-26 17:49:40 +10:00 committed by refractionpcsx2
parent 25fa70fe9e
commit ce53b7adb1
6 changed files with 104 additions and 28 deletions

View File

@ -990,26 +990,12 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
void MainWindow::onStartFileActionTriggered() void MainWindow::onStartFileActionTriggered()
{ {
QString filename = QString path =
QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select Disc Image"), QString(), tr(DISC_IMAGE_FILTER), nullptr)); QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select Disc Image"), QString(), tr(DISC_IMAGE_FILTER), nullptr));
if (filename.isEmpty()) if (path.isEmpty())
return; return;
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>(); doStartDisc(path);
params->filename = filename.toStdString();
// we might still be saving a resume state...
VMManager::WaitForSaveStateFlush();
const std::optional<bool> resume(
promptForResumeState(
QString::fromStdString(VMManager::GetSaveStateFileName(params->filename.c_str(), -1))));
if (!resume.has_value())
return;
else if (resume.value())
params->state_index = -1;
g_emu_thread->startVM(std::move(params));
} }
void MainWindow::onStartBIOSActionTriggered() void MainWindow::onStartBIOSActionTriggered()
@ -1392,6 +1378,59 @@ void MainWindow::closeEvent(QCloseEvent* event)
QMainWindow::closeEvent(event); QMainWindow::closeEvent(event);
} }
static QString getFilenameFromMimeData(const QMimeData* md)
{
QString filename;
if (md->hasUrls())
{
// only one url accepted
const QList<QUrl> urls(md->urls());
if (urls.size() == 1)
filename = urls.front().toLocalFile();
}
return filename;
}
void MainWindow::dragEnterEvent(QDragEnterEvent* event)
{
const std::string filename(getFilenameFromMimeData(event->mimeData()).toStdString());
// allow save states being dragged in
if (!VMManager::IsLoadableFileName(filename) && !VMManager::IsSaveStateFileName(filename))
return;
event->acceptProposedAction();
}
void MainWindow::dropEvent(QDropEvent* event)
{
const QString filename(getFilenameFromMimeData(event->mimeData()));
const std::string filename_str(filename.toStdString());
if (VMManager::IsSaveStateFileName(filename_str))
{
// can't load a save state without a current VM
if (m_vm_valid)
{
event->acceptProposedAction();
g_emu_thread->loadState(filename);
}
else
{
QMessageBox::critical(this, tr("Load State Failed"), tr("Cannot load a save state without a running VM."));
}
}
else if (VMManager::IsLoadableFileName(filename_str))
{
// if we're already running, do a disc change, otherwise start
event->acceptProposedAction();
if (m_vm_valid)
doDiscChange(filename);
else
doStartDisc(filename);
}
}
DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main) DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
{ {
DevCon.WriteLn("createDisplay(%u, %u)", static_cast<u32>(fullscreen), static_cast<u32>(render_to_main)); DevCon.WriteLn("createDisplay(%u, %u)", static_cast<u32>(fullscreen), static_cast<u32>(render_to_main));
@ -2013,6 +2052,28 @@ void MainWindow::updateSaveStateMenus(const QString& filename, const QString& se
populateSaveStateMenu(m_ui.menuSaveState, serial, crc); populateSaveStateMenu(m_ui.menuSaveState, serial, crc);
} }
void MainWindow::doStartDisc(const QString& path)
{
if (m_vm_valid)
return;
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>();
params->filename = path.toStdString();
// we might still be saving a resume state...
VMManager::WaitForSaveStateFlush();
const std::optional<bool> resume(
promptForResumeState(
QString::fromStdString(VMManager::GetSaveStateFileName(params->filename.c_str(), -1))));
if (!resume.has_value())
return;
else if (resume.value())
params->state_index = -1;
g_emu_thread->startVM(std::move(params));
}
void MainWindow::doDiscChange(const QString& path) void MainWindow::doDiscChange(const QString& path)
{ {
bool reset_system = false; bool reset_system = false;

View File

@ -157,6 +157,8 @@ private Q_SLOTS:
protected: protected:
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override;
private: private:
enum : s32 enum : s32
@ -206,6 +208,7 @@ private:
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc); void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc); void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc); void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc);
void doStartDisc(const QString& path);
void doDiscChange(const QString& path); void doDiscChange(const QString& path);
Ui::MainWindow m_ui; Ui::MainWindow m_ui;

View File

@ -110,17 +110,13 @@ const char* GameList::EntryCompatibilityRatingToString(CompatibilityRating ratin
// clang-format on // clang-format on
} }
bool GameList::IsScannableFilename(const std::string& path) bool GameList::IsScannableFilename(const std::string_view& path)
{ {
static const char* extensions[] = {".iso", ".mdf", ".nrg", ".bin", ".img", ".gz", ".cso", ".chd", ".elf", ".irx"}; static const char* extensions[] = {".iso", ".mdf", ".nrg", ".bin", ".img", ".gz", ".cso", ".chd", ".elf", ".irx"};
const std::string::size_type pos = path.rfind('.');
if (pos == std::string::npos)
return false;
for (const char* test_extension : extensions) for (const char* test_extension : extensions)
{ {
if (StringUtil::Strcasecmp(&path[pos], test_extension) == 0) if (StringUtil::EndsWithNoCase(path, test_extension))
return true; return true;
} }

View File

@ -72,7 +72,7 @@ namespace GameList
const char* RegionToString(Region region); const char* RegionToString(Region region);
const char* EntryCompatibilityRatingToString(CompatibilityRating rating); const char* EntryCompatibilityRatingToString(CompatibilityRating rating);
bool IsScannableFilename(const std::string& path); bool IsScannableFilename(const std::string_view& path);
/// Fills in boot parameters (iso or elf) based on the game list entry. /// Fills in boot parameters (iso or elf) based on the game list entry.
void FillBootParametersForEntry(VMBootParameters* params, const Entry* entry); void FillBootParametersForEntry(VMBootParameters* params, const Entry* entry);

View File

@ -1208,18 +1208,28 @@ bool VMManager::ChangeDisc(std::string path)
return result; return result;
} }
bool VMManager::IsElfFileName(const std::string& path) bool VMManager::IsElfFileName(const std::string_view& path)
{ {
return StringUtil::EndsWithNoCase(path, ".elf"); return StringUtil::EndsWithNoCase(path, ".elf");
} }
bool VMManager::IsGSDumpFileName(const std::string& path) bool VMManager::IsGSDumpFileName(const std::string_view& path)
{ {
return (StringUtil::EndsWithNoCase(path, ".gs") || return (StringUtil::EndsWithNoCase(path, ".gs") ||
StringUtil::EndsWithNoCase(path, ".gs.xz") || StringUtil::EndsWithNoCase(path, ".gs.xz") ||
StringUtil::EndsWithNoCase(path, ".gs.zst")); StringUtil::EndsWithNoCase(path, ".gs.zst"));
} }
bool VMManager::IsSaveStateFileName(const std::string_view& path)
{
return StringUtil::EndsWithNoCase(path, ".p2s");
}
bool VMManager::IsLoadableFileName(const std::string_view& path)
{
return IsElfFileName(path) || IsGSDumpFileName(path) || GameList::IsScannableFilename(path);
}
void VMManager::Execute() void VMManager::Execute()
{ {
// Check for interpreter<->recompiler switches. // Check for interpreter<->recompiler switches.

View File

@ -135,10 +135,16 @@ namespace VMManager
bool ChangeDisc(std::string path); bool ChangeDisc(std::string path);
/// Returns true if the specified path is an ELF. /// Returns true if the specified path is an ELF.
bool IsElfFileName(const std::string& path); bool IsElfFileName(const std::string_view& path);
/// Returns true if the specified path is a GS Dump. /// Returns true if the specified path is a GS Dump.
bool IsGSDumpFileName(const std::string& path); bool IsGSDumpFileName(const std::string_view& path);
/// Returns true if the specified path is a save state.
bool IsSaveStateFileName(const std::string_view& path);
/// Returns true if the specified path is a disc/elf/etc.
bool IsLoadableFileName(const std::string_view& path);
/// Returns the path for the game settings ini file for the specified CRC. /// Returns the path for the game settings ini file for the specified CRC.
std::string GetGameSettingsPath(const std::string_view& game_serial, u32 game_crc); std::string GetGameSettingsPath(const std::string_view& game_serial, u32 game_crc);