Fix drag and drop

This commit is contained in:
James Rowe 2019-11-28 10:56:58 -07:00
parent 86f203e6e8
commit 782eae7f65
5 changed files with 72 additions and 22 deletions

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <QApplication> #include <QApplication>
#include <QDragEnterEvent>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QKeyEvent> #include <QKeyEvent>
#include <QOffscreenSurface> #include <QOffscreenSurface>
@ -14,6 +15,7 @@
#include <QWindow> #include <QWindow>
#include <fmt/format.h> #include <fmt/format.h>
#include "citra_qt/bootmanager.h" #include "citra_qt/bootmanager.h"
#include "citra_qt/main.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "core/3ds.h" #include "core/3ds.h"
@ -31,6 +33,15 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor
EmuThread::~EmuThread() = default; EmuThread::~EmuThread() = default;
static GMainWindow* GetMainWindow() {
for (QWidget* w : qApp->topLevelWidgets()) {
if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) {
return main;
}
}
return nullptr;
}
void EmuThread::run() { void EmuThread::run() {
MicroProfileOnThreadCreate("EmuThread"); MicroProfileOnThreadCreate("EmuThread");
Frontend::ScopeAcquireContext scope(core_context); Frontend::ScopeAcquireContext scope(core_context);
@ -138,6 +149,15 @@ bool OpenGLWindow::event(QEvent* event) {
case QEvent::InputMethodQuery: case QEvent::InputMethodQuery:
case QEvent::TouchCancel: case QEvent::TouchCancel:
return QCoreApplication::sendEvent(event_handler, event); return QCoreApplication::sendEvent(event_handler, event);
case QEvent::Drop:
GetMainWindow()->DropAction(static_cast<QDropEvent*>(event));
return true;
case QEvent::DragResponse:
case QEvent::DragEnter:
case QEvent::DragLeave:
case QEvent::DragMove:
GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event));
return true;
default: default:
return QWindow::event(event); return QWindow::event(event);
} }
@ -298,15 +318,19 @@ void GRenderWindow::TouchEndEvent() {
} }
bool GRenderWindow::event(QEvent* event) { bool GRenderWindow::event(QEvent* event) {
if (event->type() == QEvent::TouchBegin) { switch (event->type()) {
case QEvent::TouchBegin:
TouchBeginEvent(static_cast<QTouchEvent*>(event)); TouchBeginEvent(static_cast<QTouchEvent*>(event));
return true; return true;
} else if (event->type() == QEvent::TouchUpdate) { case QEvent::TouchUpdate:
TouchUpdateEvent(static_cast<QTouchEvent*>(event)); TouchUpdateEvent(static_cast<QTouchEvent*>(event));
return true; return true;
} else if (event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) { case QEvent::TouchEnd:
case QEvent::TouchCancel:
TouchEndEvent(); TouchEndEvent();
return true; return true;
default:
break;
} }
return QWidget::event(event); return QWidget::event(event);

View File

@ -127,11 +127,10 @@ void ConfigureWeb::OnLoginChanged() {
void ConfigureWeb::VerifyLogin() { void ConfigureWeb::VerifyLogin() {
ui->button_verify_login->setDisabled(true); ui->button_verify_login->setDisabled(true);
ui->button_verify_login->setText(tr("Verifying...")); ui->button_verify_login->setText(tr("Verifying..."));
verify_watcher.setFuture(QtConcurrent::run( verify_watcher.setFuture(QtConcurrent::run([
[username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()), username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()),
token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] { token = TokenFromDisplayToken(ui->edit_token->text().toStdString())
return Core::VerifyLogin(username, token); ] { return Core::VerifyLogin(username, token); }));
}));
} }
void ConfigureWeb::OnLoginVerified() { void ConfigureWeb::OnLoginVerified() {

View File

@ -1869,14 +1869,33 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
QWidget::closeEvent(event); QWidget::closeEvent(event);
} }
static bool IsSingleFileDropEvent(QDropEvent* event) { static bool IsSingleFileDropEvent(const QMimeData* mime) {
const QMimeData* mimeData = event->mimeData(); return mime->hasUrls() && mime->urls().length() == 1;
return mimeData->hasUrls() && mimeData->urls().length() == 1;
} }
void GMainWindow::dropEvent(QDropEvent* event) { static const std::array<std::string, 8> AcceptedExtensions = {"cci", "3ds", "cxi", "bin",
if (!IsSingleFileDropEvent(event)) { "3dsx", "app", "elf", "axf"};
return;
static bool IsCorrectFileExtension(const QMimeData* mime) {
const QString& filename = mime->urls().at(0).toLocalFile();
return std::find(AcceptedExtensions.begin(), AcceptedExtensions.end(),
QFileInfo(filename).suffix().toStdString()) != AcceptedExtensions.end();
}
static bool IsAcceptableDropEvent(QDropEvent* event) {
return IsSingleFileDropEvent(event->mimeData()) && IsCorrectFileExtension(event->mimeData());
}
void GMainWindow::AcceptDropEvent(QDropEvent* event) {
if (IsAcceptableDropEvent(event)) {
event->setDropAction(Qt::DropAction::LinkAction);
event->accept();
}
}
bool GMainWindow::DropAction(QDropEvent* event) {
if (!IsAcceptableDropEvent(event)) {
return false;
} }
const QMimeData* mime_data = event->mimeData(); const QMimeData* mime_data = event->mimeData();
@ -1891,16 +1910,19 @@ void GMainWindow::dropEvent(QDropEvent* event) {
BootGame(filename); BootGame(filename);
} }
} }
return true;
}
void GMainWindow::dropEvent(QDropEvent* event) {
DropAction(event);
} }
void GMainWindow::dragEnterEvent(QDragEnterEvent* event) { void GMainWindow::dragEnterEvent(QDragEnterEvent* event) {
if (IsSingleFileDropEvent(event)) { AcceptDropEvent(event);
event->acceptProposedAction();
}
} }
void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { void GMainWindow::dragMoveEvent(QDragMoveEvent* event) {
event->acceptProposedAction(); AcceptDropEvent(event);
} }
bool GMainWindow::ConfirmChangeGame() { bool GMainWindow::ConfirmChangeGame() {

View File

@ -41,6 +41,7 @@ class QProgressBar;
class RegistersWidget; class RegistersWidget;
class Updater; class Updater;
class WaitTreeWidget; class WaitTreeWidget;
namespace DiscordRPC { namespace DiscordRPC {
class DiscordInterface; class DiscordInterface;
} }
@ -69,8 +70,12 @@ public:
GameList* game_list; GameList* game_list;
std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc; std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
bool DropAction(QDropEvent* event);
void AcceptDropEvent(QDropEvent* event);
public slots: public slots:
void OnAppFocusStateChanged(Qt::ApplicationState state); void OnAppFocusStateChanged(Qt::ApplicationState state);
signals: signals:
/** /**
@ -78,8 +83,8 @@ signals:
* about to start. At this time, the core system emulation has been initialized, and all * about to start. At this time, the core system emulation has been initialized, and all
* emulation handles and memory should be valid. * emulation handles and memory should be valid.
* *
* @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need to * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need
* access/change emulation state). * to access/change emulation state).
*/ */
void EmulationStarting(EmuThread* emu_thread); void EmulationStarting(EmuThread* emu_thread);