diff --git a/ui/drivers/qt/qt_playlist.cpp b/ui/drivers/qt/qt_playlist.cpp index 62f87b62ce..2bd62e14d3 100644 --- a/ui/drivers/qt/qt_playlist.cpp +++ b/ui/drivers/qt/qt_playlist.cpp @@ -130,18 +130,25 @@ void PlaylistModel::setThumbnailCacheLimit(int limit) QString PlaylistModel::getThumbnailPath(const QModelIndex &index, QString type) const { + return getThumbnailPath(m_contents.at(index.row()), type); +} + +QString PlaylistModel::getPlaylistThumbnailsDir(const QString playlistName) const +{ + return QDir::cleanPath(QString(config_get_ptr()->paths.directory_thumbnails)) + "/" + playlistName; +} + +bool PlaylistModel::isSupportedImage(const QString path) const +{ + int lastIndex = -1; QByteArray extension; QString extensionStr; - QString thumbnailFileNameNoExt; - int lastIndex = -1; - - const QHash &hash = m_contents.at(index.row()); - lastIndex = hash["path"].lastIndexOf('.'); + lastIndex = path.lastIndexOf('.'); if (lastIndex >= 0) { - extensionStr = hash["path"].mid(lastIndex + 1); + extensionStr = path.mid(lastIndex + 1); if (!extensionStr.isEmpty()) { @@ -150,15 +157,26 @@ QString PlaylistModel::getThumbnailPath(const QModelIndex &index, QString type) } if (!extension.isEmpty() && m_imageFormats.contains(extension)) + return true; + + return false; +} + +QString PlaylistModel::getSanitizedThumbnailName(QString label) const +{ + return label.replace(m_fileSanitizerRegex, "_") + ".png"; +} + +QString PlaylistModel::getThumbnailPath(const QHash &hash, QString type) const +{ + if (isSupportedImage(hash["path"])) { /* use thumbnail widgets to show regular image files */ return hash["path"]; } else { - thumbnailFileNameNoExt = hash["label_noext"]; - thumbnailFileNameNoExt.replace(m_fileSanitizerRegex, "_"); - return QDir::cleanPath(QString(config_get_ptr()->paths.directory_thumbnails)) + "/" + hash.value("db_name") + "/" + type + "/" + thumbnailFileNameNoExt + ".png"; + return getPlaylistThumbnailsDir(hash.value("db_name")) + "/" + type + "/" + getSanitizedThumbnailName(hash["label_noext"]); } } diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 8d5026901e..c509d6b32a 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -302,7 +302,6 @@ MainWindow::MainWindow(QWidget *parent) : ,m_thumbnailPixmap(NULL) ,m_thumbnailPixmap2(NULL) ,m_thumbnailPixmap3(NULL) - ,m_fileSanitizerRegex("[&*/:`<>?\\|]") ,m_settings(NULL) ,m_viewOptionsDialog(NULL) ,m_coreInfoDialog(new CoreInfoDialog(this, NULL)) @@ -1265,6 +1264,108 @@ void MainWindow::changeThumbnailType(ThumbnailType type) m_gridView->viewport()->update(); } +QString MainWindow::changeThumbnail(const QImage &image, QString type) +{ + QHash hash = getCurrentContentHash(); + QString dirString = m_playlistModel->getPlaylistThumbnailsDir(hash["db_name"]) + "/" + type; + QString thumbPath = dirString + "/" + m_playlistModel->getSanitizedThumbnailName(hash["label_noext"]); + QByteArray dirArray = QDir::toNativeSeparators(dirString).toUtf8(); + const char *dirData = dirArray.constData(); + QByteArray thumbArray = QDir::toNativeSeparators(thumbPath).toUtf8(); + const char *thumbData = thumbArray.constData(); + QDir dir(dirString); + int quality = -1; + QImage scaledImage(image); + + if (!dir.exists()) + { + if (dir.mkpath(".")) + RARCH_LOG("[Qt]: Created directory: %s\n", dirData); + else + { + RARCH_ERR("[Qt]: Could not create directory: %s\n", dirData); + return QString(); + } + } + + if (m_settings->contains("thumbnail_max_size")) + { + int size = m_settings->value("thumbnail_max_size", 512).toInt(); + + if (size != 0) + scaledImage = image.scaled(size, size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + + if (m_settings->contains("thumbnail_quality")) + quality = m_settings->value("thumbnail_quality", -1).toInt(); + + if (scaledImage.save(thumbPath, "png", quality)) + { + RARCH_LOG("[Qt]: Saved image: %s\n", thumbData); + m_playlistModel->reloadThumbnailPath(thumbPath); + updateVisibleItems(); + + return thumbPath; + } + + RARCH_ERR("[Qt]: Could not save image: %s\n", thumbData); + return QString(); +} + +void MainWindow::onThumbnailDropped(const QImage &image, ThumbnailType thumbnailType) +{ + switch (thumbnailType) + { + case THUMBNAIL_TYPE_BOXART: + { + QString path = changeThumbnail(image, THUMBNAIL_BOXART); + + if (path.isNull()) + return; + + if (m_thumbnailPixmap) + delete m_thumbnailPixmap; + + m_thumbnailPixmap = new QPixmap(path); + + onResizeThumbnailOne(); + break; + } + + case THUMBNAIL_TYPE_TITLE_SCREEN: + { + QString path = changeThumbnail(image, THUMBNAIL_TITLE); + + if (path.isNull()) + return; + + if (m_thumbnailPixmap2) + delete m_thumbnailPixmap2; + + m_thumbnailPixmap2 = new QPixmap(path); + + onResizeThumbnailTwo(); + break; + } + + case THUMBNAIL_TYPE_SCREENSHOT: + { + QString path = changeThumbnail(image, THUMBNAIL_SCREENSHOT); + + if (path.isNull()) + return; + + if (m_thumbnailPixmap3) + delete m_thumbnailPixmap3; + + m_thumbnailPixmap3 = new QPixmap(path); + + onResizeThumbnailThree(); + break; + } + } +} + QVector > MainWindow::getCoreInfo() { QVector > infoList; @@ -2107,6 +2208,22 @@ void MainWindow::setCoreActions() } } +void MainWindow::setThumbnailsAcceptDrops(bool accept) +{ + ThumbnailWidget *thumbnail = findChild("thumbnail1Widget"); + ThumbnailWidget *thumbnail2 = findChild("thumbnail2Widget"); + ThumbnailWidget *thumbnail3 = findChild("thumbnail3Widget"); + + if (thumbnail) + thumbnail->setAcceptDrops(accept); + + if (thumbnail2) + thumbnail2->setAcceptDrops(accept); + + if (thumbnail3) + thumbnail3->setAcceptDrops(accept); +} + void MainWindow::onTabWidgetIndexChanged(int index) { if (m_browserAndPlaylistTabWidget->tabText(index) == msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_TAB_FILE_BROWSER)) @@ -2394,29 +2511,7 @@ void MainWindow::onCurrentFileChanged(const QModelIndex &index) void MainWindow::onCurrentItemChanged(const QHash &hash) { - settings_t *settings = config_get_ptr(); - QString label; - QString playlist_name; - QByteArray extension; - QString extensionStr; - int lastIndex = -1; - - label = hash["label_noext"]; - label.replace(m_fileSanitizerRegex, "_"); - - lastIndex = hash["path"].lastIndexOf('.'); - - if (lastIndex >= 0) - { - extensionStr = hash["path"].mid(lastIndex + 1); - - if (!extensionStr.isEmpty()) - { - extension = extensionStr.toLower().toUtf8(); - } - } - - playlist_name = hash["db_name"]; + QString path = hash["path"]; if (m_thumbnailPixmap) delete m_thumbnailPixmap; @@ -2425,18 +2520,31 @@ void MainWindow::onCurrentItemChanged(const QHash &hash) if (m_thumbnailPixmap3) delete m_thumbnailPixmap3; - if (!extension.isEmpty() && m_imageFormats.contains(extension)) + if (m_playlistModel->isSupportedImage(path)) { /* use thumbnail widgets to show regular image files */ - m_thumbnailPixmap = new QPixmap(hash["path"]); + m_thumbnailPixmap = new QPixmap(path); m_thumbnailPixmap2 = new QPixmap(*m_thumbnailPixmap); m_thumbnailPixmap3 = new QPixmap(*m_thumbnailPixmap); + + setThumbnailsAcceptDrops(false); } else { - m_thumbnailPixmap = new QPixmap(QString(settings->paths.directory_thumbnails) + "/" + playlist_name + "/" + THUMBNAIL_BOXART + "/" + label + ".png"); - m_thumbnailPixmap2 = new QPixmap(QString(settings->paths.directory_thumbnails) + "/" + playlist_name + "/" + THUMBNAIL_TITLE + "/" + label + ".png"); - m_thumbnailPixmap3 = new QPixmap(QString(settings->paths.directory_thumbnails) + "/" + playlist_name + "/" + THUMBNAIL_SCREENSHOT + "/" + label + ".png"); + QString thumbnailsDir = m_playlistModel->getPlaylistThumbnailsDir(hash["db_name"]); + QString thumbnailName = m_playlistModel->getSanitizedThumbnailName(hash["label_noext"]); + + m_thumbnailPixmap = new QPixmap(thumbnailsDir + "/" + THUMBNAIL_BOXART + "/" + thumbnailName); + m_thumbnailPixmap2 = new QPixmap(thumbnailsDir + "/" + THUMBNAIL_TITLE + "/" + thumbnailName); + m_thumbnailPixmap3 = new QPixmap(thumbnailsDir + "/" + THUMBNAIL_SCREENSHOT + "/" + thumbnailName); + + if (m_currentBrowser == BROWSER_TYPE_PLAYLISTS) + { + if (currentPlaylistIsSpecial()) + setThumbnailsAcceptDrops(false); + else + setThumbnailsAcceptDrops(true); + } } resizeThumbnails(true, true, true); diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 9cf8e0ed45..e499a43ddb 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -63,9 +63,10 @@ typedef struct ui_companion_qt ui_window_qt_t *window; } ui_companion_qt_t; -ThumbnailWidget::ThumbnailWidget(QWidget *parent) : +ThumbnailWidget::ThumbnailWidget(ThumbnailType type, QWidget *parent) : QFrame(parent) ,m_sizeHint(QSize(256, 256)) + ,m_thumbnailType(type) { } @@ -111,6 +112,40 @@ void ThumbnailWidget::setSizeHint(QSize size) m_sizeHint = size; } +void ThumbnailWidget::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + event->acceptProposedAction(); +} + +/* Workaround for QTBUG-72844. Without it, you can't drop on this if you first drag over another widget that doesn't accept drops. */ +void ThumbnailWidget::dragMoveEvent(QDragMoveEvent *event) +{ + event->acceptProposedAction(); +} + +void ThumbnailWidget::dropEvent(QDropEvent *event) +{ + const QMimeData *data = event->mimeData(); + + if (data->hasUrls()) + { + const QString imageString = data->urls().at(0).toLocalFile(); + const QImage image(imageString); + + if (!image.isNull()) + emit(filesDropped(image, m_thumbnailType)); + else + { + QByteArray stringArray = QDir::toNativeSeparators(imageString).toUtf8(); + const char *stringData = stringArray.constData(); + RARCH_ERR("[Qt]: Could not read image: %s\n", stringData); + } + } +} + ThumbnailLabel::ThumbnailLabel(QWidget *parent) : QWidget(parent) ,m_pixmap(NULL) @@ -403,9 +438,14 @@ static void* ui_companion_qt_init(void) browserButtonsHBoxLayout->addItem(new QSpacerItem(browserAndPlaylistTabWidget->tabBar()->width(), 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); - thumbnailWidget = new ThumbnailWidget(); - thumbnail2Widget = new ThumbnailWidget(); - thumbnail3Widget = new ThumbnailWidget(); + thumbnailWidget = new ThumbnailWidget(THUMBNAIL_TYPE_BOXART); + thumbnailWidget->setObjectName("thumbnail1Widget"); + + thumbnail2Widget = new ThumbnailWidget(THUMBNAIL_TYPE_TITLE_SCREEN); + thumbnail2Widget->setObjectName("thumbnail2Widget"); + + thumbnail3Widget = new ThumbnailWidget(THUMBNAIL_TYPE_SCREENSHOT); + thumbnail3Widget->setObjectName("thumbnail3Widget"); thumbnailWidget->setLayout(new QVBoxLayout()); thumbnail2Widget->setLayout(new QVBoxLayout()); @@ -415,6 +455,10 @@ static void* ui_companion_qt_init(void) thumbnail2Widget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); thumbnail3Widget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + QObject::connect(thumbnailWidget, SIGNAL(filesDropped(const QImage&, ThumbnailType)), mainwindow, SLOT(onThumbnailDropped(const QImage&, ThumbnailType))); + QObject::connect(thumbnail2Widget, SIGNAL(filesDropped(const QImage&, ThumbnailType)), mainwindow, SLOT(onThumbnailDropped(const QImage&, ThumbnailType))); + QObject::connect(thumbnail3Widget, SIGNAL(filesDropped(const QImage&, ThumbnailType)), mainwindow, SLOT(onThumbnailDropped(const QImage&, ThumbnailType))); + thumbnail = new ThumbnailLabel(); thumbnail->setObjectName("thumbnail"); diff --git a/ui/drivers/ui_qt.h b/ui/drivers/ui_qt.h index cad3009d9e..0684a833cd 100644 --- a/ui/drivers/ui_qt.h +++ b/ui/drivers/ui_qt.h @@ -42,7 +42,6 @@ #include #include #include -#include #include "qt/filedropwidget.h" @@ -143,6 +142,9 @@ public: void reloadThumbnailPath(const QString path); void reloadSystemThumbnails(const QString system); void setThumbnailCacheLimit(int limit); + bool isSupportedImage(const QString path) const; + QString getPlaylistThumbnailsDir(const QString playlistName) const; + QString getSanitizedThumbnailName(QString label) const; signals: void imageLoaded(const QImage image, const QModelIndex &index, const QString &path); @@ -158,6 +160,7 @@ private: QRegularExpression m_fileSanitizerRegex; ThumbnailType m_thumbnailType = THUMBNAIL_TYPE_BOXART; QString getThumbnailPath(const QModelIndex &index, QString type) const; + QString getThumbnailPath(const QHash &hash, QString type) const; QString getCurrentTypeThumbnailPath(const QModelIndex &index) const; void getPlaylistItems(QString path); void loadImage(const QModelIndex &index, const QString &path); @@ -168,6 +171,7 @@ class ThumbnailWidget : public QFrame Q_OBJECT public: ThumbnailWidget(QWidget *parent = 0); + ThumbnailWidget(ThumbnailType type, QWidget *parent = 0); ThumbnailWidget(const ThumbnailWidget& other) { retro_assert(false && "DONT EVER USE THIS"); } QSize sizeHint() const; @@ -175,13 +179,18 @@ public: signals: void mouseDoubleClicked(); void mousePressed(); + void filesDropped(const QImage& image, ThumbnailType type); private: QSize m_sizeHint; + ThumbnailType m_thumbnailType; protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); }; class ThumbnailLabel : public QWidget @@ -457,6 +466,7 @@ public slots: void downloadPlaylistThumbnails(QString playlistPath); void downloadNextPlaylistThumbnail(QString system, QString title, QString type, QUrl url = QUrl()); void changeThumbnailType(ThumbnailType type); + void onThumbnailDropped(const QImage &image, ThumbnailType type); private slots: void onLoadCoreClicked(const QStringList &extensionFilters = QStringList()); @@ -540,6 +550,8 @@ private: bool currentPlaylistIsAll(); void applySearch(); void updateItemsCount(); + void setThumbnailsAcceptDrops(bool accept); + QString changeThumbnail(const QImage &image, QString type); PlaylistModel *m_playlistModel; QSortFilterProxyModel *m_proxyModel; @@ -571,7 +583,6 @@ private: QPixmap *m_thumbnailPixmap; QPixmap *m_thumbnailPixmap2; QPixmap *m_thumbnailPixmap3; - QRegularExpression m_fileSanitizerRegex; QSettings *m_settings; ViewOptionsDialog *m_viewOptionsDialog; CoreInfoDialog *m_coreInfoDialog;