Merge pull request #475 from YACReader/custom_comic_covers

This commit is contained in:
Luis Ángel San Martín 2025-05-10 07:52:28 +02:00 committed by GitHub
commit a4ab11d44d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 350 additions and 75 deletions

View File

@ -16,7 +16,11 @@ Version counting is based on semantic versioning (Major.Feature.Patch)
* New setting in Comic Vine scraper to force exact volume matches. * New setting in Comic Vine scraper to force exact volume matches.
* Better default search query in the Comic Vine scraper. * Better default search query in the Comic Vine scraper.
* Improved navigation in Comic Vine scraper, including keeping the current query around to make edits and refined searches easier. * Improved navigation in Comic Vine scraper, including keeping the current query around to make edits and refined searches easier.
* Add support for adding custom covers for folders using the context menu. * Add support for custom covers for any folder using the context menu.
* The edit cover buttons now support looping through pages, going forward from the last returns to the first, and going backward from the first jumps to the last.
* Add support for custom covers for comics using the edit metadata dialog, you can use a pick file button or drag&drop an image into the cover view in the dialog.
* Covers can be set in bulk for various comics at once.
* New button to reset to the default cover of a comic.
### YACReaderLibraryServer ### YACReaderLibraryServer
* Log libraries validation when the app starts. * Log libraries validation when the app starts.

View File

@ -43,6 +43,7 @@
<file>../images/flow4.png</file> <file>../images/flow4.png</file>
<file>../images/flow5.png</file> <file>../images/flow5.png</file>
<file>../images/glowLine.png</file> <file>../images/glowLine.png</file>
<file>../images/loadCustomCover.svg</file>
<file>../images/hiddenCovers.png</file> <file>../images/hiddenCovers.png</file>
<file>../images/icon-new.svg</file> <file>../images/icon-new.svg</file>
<file>../images/iconLibrary.png</file> <file>../images/iconLibrary.png</file>
@ -70,6 +71,7 @@
<file>../images/previousCoverPage.png</file> <file>../images/previousCoverPage.png</file>
<file>../images/readingRibbon.png</file> <file>../images/readingRibbon.png</file>
<file>../images/readRibbon.png</file> <file>../images/readRibbon.png</file>
<file>../images/resetCover.svg</file>
<file>../images/searching_icon.png</file> <file>../images/searching_icon.png</file>
<file>../images/serverConfigBackground.png</file> <file>../images/serverConfigBackground.png</file>
<file>../images/shortcuts_group_comics.svg</file> <file>../images/shortcuts_group_comics.svg</file>

View File

@ -1,6 +1,7 @@
#include "library_window.h" #include "library_window.h"
#include "yacreader_global.h" #include "yacreader_global.h"
#include "yacreader_global_gui.h"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QSplitter> #include <QSplitter>
@ -2313,12 +2314,7 @@ void LibraryWindow::setFolderCover()
void LibraryWindow::setCustomFolderCover(Folder folder) void LibraryWindow::setCustomFolderCover(Folder folder)
{ {
QString supportedImageFormatsString; auto customCoverPath = YACReader::imageFileLoader(this);
for (const QByteArray &format : QImageReader::supportedImageFormats()) {
supportedImageFormatsString += QString("*.%1 ").arg(QString(format));
}
QString customCoverPath = QFileDialog::getOpenFileName(this, tr("Select custom cover"), QDir::homePath(), tr("Images (%1)").arg(supportedImageFormatsString));
if (!customCoverPath.isEmpty()) { if (!customCoverPath.isEmpty()) {
QImage cover(customCoverPath); QImage cover(customCoverPath);
if (cover.isNull()) { if (cover.isNull()) {

View File

@ -1,10 +1,14 @@
#include "properties_dialog.h" #include "properties_dialog.h"
#include "yacreader_global_gui.h"
#include "cover_utils.h"
#include "data_base_management.h" #include "data_base_management.h"
#include "initial_comic_info_extractor.h" #include "initial_comic_info_extractor.h"
#include "yacreader_field_edit.h" #include "yacreader_field_edit.h"
#include "yacreader_field_plain_text_edit.h" #include "yacreader_field_plain_text_edit.h"
#include "db_helper.h" #include "db_helper.h"
#include "yacreader_cover_label.h"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QApplication> #include <QApplication>
@ -36,7 +40,8 @@ PropertiesDialog::PropertiesDialog(QWidget *parent)
createTabBar(); createTabBar();
auto rootLayout = new QGridLayout; auto rootLayout = new QGridLayout;
cover = new QLabel(); cover = new YACReader::CoverLabel();
connect(cover, &YACReader::CoverLabel::imageDropped, this, &PropertiesDialog::loadCustomCoverImageFromPath);
mainLayout = new QGridLayout; mainLayout = new QGridLayout;
mainLayout->addWidget(tabBar, 0, 0); mainLayout->addWidget(tabBar, 0, 0);
@ -102,11 +107,23 @@ void PropertiesDialog::createCoverBox()
showPreviousCoverPageButton = new QToolButton(); showPreviousCoverPageButton = new QToolButton();
showPreviousCoverPageButton->setIcon(QIcon(":/images/previousCoverPage.png")); showPreviousCoverPageButton->setIcon(QIcon(":/images/previousCoverPage.png"));
showPreviousCoverPageButton->setToolTip(tr("Load previous page as cover"));
showPreviousCoverPageButton->setStyleSheet("QToolButton {border:none;}"); showPreviousCoverPageButton->setStyleSheet("QToolButton {border:none;}");
showNextCoverPageButton = new QToolButton(); showNextCoverPageButton = new QToolButton();
showNextCoverPageButton->setIcon(QIcon(":/images/nextCoverPage.png")); showNextCoverPageButton->setIcon(QIcon(":/images/nextCoverPage.png"));
showNextCoverPageButton->setToolTip(tr("Load next page as cover"));
showNextCoverPageButton->setStyleSheet("QToolButton {border:none;}"); showNextCoverPageButton->setStyleSheet("QToolButton {border:none;}");
resetCoverButton = new QToolButton();
resetCoverButton->setIcon(QIcon(":/images/resetCover.svg"));
resetCoverButton->setToolTip(tr("Reset cover to the default image"));
resetCoverButton->setStyleSheet("QToolButton {border:none;}");
loadCustomCoverImageButton = new QToolButton();
loadCustomCoverImageButton->setIcon(QIcon(":/images/loadCustomCover.svg"));
loadCustomCoverImageButton->setToolTip(tr("Load custom cover image"));
loadCustomCoverImageButton->setStyleSheet("QToolButton {border:none;}");
coverPageNumberLabel = new QLabel("-"); coverPageNumberLabel = new QLabel("-");
coverPageNumberLabel->setStyleSheet("QLabel {color: white; font-weight:bold; font-size:14px;}"); coverPageNumberLabel->setStyleSheet("QLabel {color: white; font-weight:bold; font-size:14px;}");
@ -116,6 +133,10 @@ void PropertiesDialog::createCoverBox()
layout->addWidget(coverPageNumberLabel, 0, Qt::AlignVCenter); layout->addWidget(coverPageNumberLabel, 0, Qt::AlignVCenter);
layout->addSpacing(5); layout->addSpacing(5);
layout->addWidget(showNextCoverPageButton, 0, Qt::AlignVCenter); layout->addWidget(showNextCoverPageButton, 0, Qt::AlignVCenter);
layout->addSpacing(5);
layout->addWidget(resetCoverButton, 0, Qt::AlignVCenter);
layout->addSpacing(5);
layout->addWidget(loadCustomCoverImageButton, 0, Qt::AlignVCenter);
coverPageEdit->setStyleSheet("QLineEdit {border:none;}"); coverPageEdit->setStyleSheet("QLineEdit {border:none;}");
layout->setSpacing(0); layout->setSpacing(0);
@ -132,6 +153,8 @@ void PropertiesDialog::createCoverBox()
connect(showPreviousCoverPageButton, &QAbstractButton::clicked, this, &PropertiesDialog::loadPreviousCover); connect(showPreviousCoverPageButton, &QAbstractButton::clicked, this, &PropertiesDialog::loadPreviousCover);
connect(showNextCoverPageButton, &QAbstractButton::clicked, this, &PropertiesDialog::loadNextCover); connect(showNextCoverPageButton, &QAbstractButton::clicked, this, &PropertiesDialog::loadNextCover);
connect(resetCoverButton, &QAbstractButton::clicked, this, &PropertiesDialog::resetCover);
connect(loadCustomCoverImageButton, &QAbstractButton::clicked, this, &PropertiesDialog::loadCustomCoverImage);
} }
void PropertiesDialog::createGeneralInfoBox() void PropertiesDialog::createGeneralInfoBox()
@ -434,6 +457,8 @@ QImage blurred(const QImage &image, const QRect &rect, int radius, bool alphaOnl
void PropertiesDialog::loadComic(ComicDB &comic) void PropertiesDialog::loadComic(ComicDB &comic)
{ {
customCover = QImage();
if (!comic.info.series.isNull()) if (!comic.info.series.isNull())
series->setText(comic.info.series.toString()); series->setText(comic.info.series.toString());
if (!comic.info.title.isNull()) if (!comic.info.title.isNull())
@ -456,22 +481,17 @@ void PropertiesDialog::loadComic(ComicDB &comic)
showPreviousCoverPageButton->setEnabled(true); showPreviousCoverPageButton->setEnabled(true);
showNextCoverPageButton->setEnabled(true); showNextCoverPageButton->setEnabled(true);
if (coverPage == 1)
showPreviousCoverPageButton->setDisabled(true);
if (coverPage == comic.info.numPages.toInt())
showNextCoverPageButton->setDisabled(true);
coverChanged = false; coverChanged = false;
coverBox->show(); updateCoverBoxForSingleComic();
if (!QFileInfo(basePath + comic.path).exists()) { if (!QFileInfo(basePath + comic.path).exists()) {
QMessageBox::warning(this, tr("Not found"), tr("Comic not found. You should update your library.")); QMessageBox::warning(this, tr("Not found"), tr("Comic not found. You should update your library."));
showPreviousCoverPageButton->setDisabled(true); showPreviousCoverPageButton->setDisabled(true);
showNextCoverPageButton->setDisabled(true); showNextCoverPageButton->setDisabled(true);
} }
} else {
coverPageNumberLabel->setText("1");
} }
/*if(comic.info.numPages != NULL)
numPagesEdit->setText(QString::number(*comic.info.numPages));*/
if (!comic.info.number.isNull()) if (!comic.info.number.isNull())
numberEdit->setText(comic.info.number.toString()); numberEdit->setText(comic.info.number.toString());
@ -581,9 +601,13 @@ void PropertiesDialog::updateButtons()
void PropertiesDialog::setComics(QList<ComicDB> comics) void PropertiesDialog::setComics(QList<ComicDB> comics)
{ {
updated = false;
sequentialEditing = false; sequentialEditing = false;
updated = false;
currentComicIndex = 0;
coverChanged = false;
customCover = QImage();
this->comics = comics; this->comics = comics;
ComicDB comic = comics[0]; ComicDB comic = comics[0];
@ -593,7 +617,7 @@ void PropertiesDialog::setComics(QList<ComicDB> comics)
updateButtons(); updateButtons();
if (comics.length() > 1) { if (comics.length() > 1) {
coverBox->hide(); updateCoverBoxForMultipleComics();
setDisableUniqueValues(true); setDisableUniqueValues(true);
this->setWindowTitle(tr("Edit selected comics information")); this->setWindowTitle(tr("Edit selected comics information"));
@ -700,9 +724,12 @@ void PropertiesDialog::setComics(QList<ComicDB> comics)
void PropertiesDialog::setComicsForSequentialEditing(int currentComicIndex, QList<ComicDB> comics) void PropertiesDialog::setComicsForSequentialEditing(int currentComicIndex, QList<ComicDB> comics)
{ {
updated = false;
sequentialEditing = true; sequentialEditing = true;
updated = false;
coverChanged = false;
customCover = QImage();
this->comics = comics; this->comics = comics;
this->currentComicIndex = currentComicIndex; this->currentComicIndex = currentComicIndex;
@ -726,6 +753,40 @@ void PropertiesDialog::updateComics()
DBHelper::update(&(itr->info), db); DBHelper::update(&(itr->info), db);
updated = true; updated = true;
} }
if (!sequentialEditing && coverChanged) {
auto coverPath = LibraryPaths::coverPath(basePath, itr->info.hash);
if (customCover.isNull()) { // reseted, we need to restore the default cover
itr->info.coverPage = QVariant();
InitialComicInfoExtractor ie(basePath + itr->path, coverPath, 1);
ie.extract();
if (ie.getOriginalCoverSize().second > 0) {
itr->info.originalCoverSize = QString("%1x%2").arg(ie.getOriginalCoverSize().first).arg(ie.getOriginalCoverSize().second);
itr->info.coverSizeRatio = static_cast<float>(ie.getOriginalCoverSize().first) / ie.getOriginalCoverSize().second;
}
emit coverChangedSignal(*itr);
DBHelper::update(&(itr->info), db);
updated = true;
} else {
itr->info.coverPage = QVariant();
YACReader::saveCover(coverPath, customCover);
auto width = customCover.width();
auto height = customCover.height();
itr->info.originalCoverSize = QString("%1x%2").arg(width).arg(height);
itr->info.coverSizeRatio = static_cast<float>(width) / height;
DBHelper::update(&(itr->info), db);
updated = true;
emit coverChangedSignal(*itr);
}
}
} }
db.commit(); db.commit();
connectionName = db.connectionName(); connectionName = db.connectionName();
@ -739,14 +800,14 @@ void PropertiesDialog::setMultipleCover()
QPixmap last = lastComic.info.getCover(basePath); QPixmap last = lastComic.info.getCover(basePath);
last = last.scaledToHeight(575, Qt::SmoothTransformation); last = last.scaledToHeight(575, Qt::SmoothTransformation);
coverImage = QPixmap::fromImage(blurred(last.toImage(), QRect(0, 0, last.width(), last.height()), 15)); auto coverImage = QPixmap::fromImage(blurred(last.toImage(), QRect(0, 0, last.width(), last.height()), 15));
cover->setPixmap(coverImage); cover->setPixmap(coverImage);
} }
void PropertiesDialog::setCover(const QPixmap &coverI) void PropertiesDialog::setCover(const QPixmap &coverI)
{ {
coverImage = coverI.scaledToHeight(575, Qt::SmoothTransformation); auto coverImage = coverI.scaledToHeight(575, Qt::SmoothTransformation);
cover->setPixmap(coverImage); cover->setPixmap(coverImage);
} }
@ -755,13 +816,14 @@ void PropertiesDialog::setFilename(const QString &nameString)
{ {
title->setText(nameString); title->setText(nameString);
} }
void PropertiesDialog::setNumpages(int pagesNum) void PropertiesDialog::setNumpages(int pagesNum)
{ {
numPagesEdit->setText(QString::number(pagesNum)); numPagesEdit->setText(QString::number(pagesNum));
} }
void PropertiesDialog::setSize(float sizeFloat) void PropertiesDialog::setSize(float sizeFloat)
{ {
size->setText(QString::number(sizeFloat, 'f', 2) + " MB"); size->setText(QString::number(sizeFloat, 'f', 2) + " MB");
} }
@ -787,7 +849,11 @@ void PropertiesDialog::save()
if (sequentialEditing) if (sequentialEditing)
if (coverChanged) { if (coverChanged) {
itr->info.coverPage = coverPageNumberLabel->text().toInt(); if (customCover.isNull()) {
itr->info.coverPage = coverPageNumberLabel->text().toInt();
} else {
itr->info.coverPage = QVariant();
}
edited = true; edited = true;
} }
@ -955,15 +1021,31 @@ void PropertiesDialog::save()
if (sequentialEditing) { if (sequentialEditing) {
if (coverChanged) { if (coverChanged) {
auto coverPath = LibraryPaths::coverPath(basePath, comics[currentComicIndex].info.hash); auto coverPath = LibraryPaths::coverPath(basePath, comics[currentComicIndex].info.hash);
InitialComicInfoExtractor ie(basePath + comics[currentComicIndex].path, coverPath, comics[currentComicIndex].info.coverPage.toInt());
ie.extract();
if (ie.getOriginalCoverSize().second > 0) { if (customCover.isNull()) {
comics[currentComicIndex].info.originalCoverSize = QString("%1x%2").arg(ie.getOriginalCoverSize().first).arg(ie.getOriginalCoverSize().second); InitialComicInfoExtractor ie(basePath + comics[currentComicIndex].path, coverPath, comics[currentComicIndex].info.coverPage.toInt());
comics[currentComicIndex].info.coverSizeRatio = static_cast<float>(ie.getOriginalCoverSize().first) / ie.getOriginalCoverSize().second; ie.extract();
if (ie.getOriginalCoverSize().second > 0) {
comics[currentComicIndex].info.originalCoverSize = QString("%1x%2").arg(ie.getOriginalCoverSize().first).arg(ie.getOriginalCoverSize().second);
comics[currentComicIndex].info.coverSizeRatio = static_cast<float>(ie.getOriginalCoverSize().first) / ie.getOriginalCoverSize().second;
}
comics[currentComicIndex].info.edited = true;
emit coverChangedSignal(comics[currentComicIndex]);
} else {
auto width = customCover.width();
auto height = customCover.height();
comics[currentComicIndex].info.originalCoverSize = QString("%1x%2").arg(width).arg(height);
comics[currentComicIndex].info.coverSizeRatio = static_cast<float>(width) / height;
comics[currentComicIndex].info.edited = true;
YACReader::saveCover(coverPath, customCover);
emit coverChangedSignal(comics[currentComicIndex]);
} }
emit coverChangedSignal(comics[currentComicIndex]);
} }
} }
} }
@ -1093,48 +1175,87 @@ void PropertiesDialog::updateCoverPageNumberLabel(int n)
void PropertiesDialog::loadNextCover() void PropertiesDialog::loadNextCover()
{ {
int current = coverPageNumberLabel->text().toInt(); int current = coverPageNumberLabel->text().toInt();
if (current < comics[currentComicIndex].info.numPages.toInt()) { int next;
updateCoverPageNumberLabel(current + 1);
InitialComicInfoExtractor ie(basePath + comics[currentComicIndex].path, "", current + 1); if (current == comics[currentComicIndex].info.numPages.toInt())
ie.extract(); next = 1;
setCover(ie.getCover()); else
repaint(); next = current + 1;
if ((current + 1) == comics[currentComicIndex].info.numPages.toInt()) { setCoverPage(next);
showNextCoverPageButton->setDisabled(true);
}
showPreviousCoverPageButton->setEnabled(true); coverChanged = next != comics[currentComicIndex].info.coverPage;
if (current + 1 != comics[currentComicIndex].info.coverPage)
coverChanged = true;
else
coverChanged = false;
}
} }
void PropertiesDialog::loadPreviousCover() void PropertiesDialog::loadPreviousCover()
{ {
int current = coverPageNumberLabel->text().toInt(); int current = coverPageNumberLabel->text().toInt();
if (current != 1) { int previous;
updateCoverPageNumberLabel(current - 1);
InitialComicInfoExtractor ie(basePath + comics[currentComicIndex].path, "", current - 1); if (current == 1)
previous = comics[currentComicIndex].info.numPages.toInt();
else
previous = current - 1;
setCoverPage(previous);
coverChanged = previous != comics[currentComicIndex].info.coverPage.toInt();
}
void PropertiesDialog::resetCover()
{
if (sequentialEditing) {
setCoverPage(1);
coverChanged = true; // it could be that the cover is a custom cover, so we need to always update it
} else {
InitialComicInfoExtractor ie(basePath + comics.last().path, "", 1);
ie.extract(); ie.extract();
setCover(ie.getCover()); auto cover = ie.getCover();
repaint(); cover = cover.scaledToHeight(575, Qt::SmoothTransformation);
if ((current - 1) == 1) { auto coverImage = QPixmap::fromImage(blurred(cover.toImage(), QRect(0, 0, cover.width(), cover.height()), 15));
showPreviousCoverPageButton->setDisabled(true);
}
showNextCoverPageButton->setEnabled(true); this->cover->setPixmap(coverImage);
if (current - 1 != comics[currentComicIndex].info.coverPage.toInt())
coverChanged = true; customCover = QImage();
else coverChanged = true;
coverChanged = false;
} }
} }
void PropertiesDialog::loadCustomCoverImage()
{
auto path = YACReader::imageFileLoader(this);
loadCustomCoverImageFromPath(path);
}
void PropertiesDialog::loadCustomCoverImageFromPath(const QString &path)
{
if (path.isEmpty()) {
return;
}
customCover = QImage(path);
coverChanged = true;
if (customCover.isNull()) {
QMessageBox::warning(this, tr("Invalid cover"), tr("The image is invalid."));
return;
}
setCover(QPixmap::fromImage(customCover));
}
void PropertiesDialog::setCoverPage(int pageNumber)
{
customCover = QImage();
updateCoverPageNumberLabel(pageNumber);
InitialComicInfoExtractor ie(basePath + comics[currentComicIndex].path, "", pageNumber);
ie.extract();
setCover(ie.getCover());
repaint();
}
bool PropertiesDialog::close() bool PropertiesDialog::close()
{ {
if (updated) { if (updated) {
@ -1143,3 +1264,17 @@ bool PropertiesDialog::close()
return QDialog::close(); return QDialog::close();
} }
void PropertiesDialog::updateCoverBoxForMultipleComics()
{
showPreviousCoverPageButton->hide();
showNextCoverPageButton->hide();
coverPageNumberLabel->hide();
}
void PropertiesDialog::updateCoverBoxForSingleComic()
{
showPreviousCoverPageButton->show();
showNextCoverPageButton->show();
coverPageNumberLabel->show();
}

View File

@ -19,6 +19,10 @@ class QComboBox;
// class YACReaderBusyWidget; // class YACReaderBusyWidget;
class QToolButton; class QToolButton;
namespace YACReader {
class CoverLabel;
}
#include "comic_db.h" #include "comic_db.h"
class PropertiesDialog : public QDialog class PropertiesDialog : public QDialog
@ -33,7 +37,7 @@ private:
QTabWidget *tabBar; QTabWidget *tabBar;
QWidget *coverBox; QWidget *coverBox;
QLabel *cover; YACReader::CoverLabel *cover;
QScrollArea *sa; QScrollArea *sa;
QWidget *generalInfoBox; QWidget *generalInfoBox;
@ -113,12 +117,13 @@ private:
QPushButton *previousButton; QPushButton *previousButton;
QPushButton *restoreButton; //?? QPushButton *restoreButton; //??
QPixmap coverImage;
QToolButton *showPreviousCoverPageButton; QToolButton *showPreviousCoverPageButton;
QToolButton *showNextCoverPageButton; QToolButton *showNextCoverPageButton;
QLabel *coverPageNumberLabel; QLabel *coverPageNumberLabel;
QToolButton *resetCoverButton;
QToolButton *loadCustomCoverImageButton;
void createTabBar(); void createTabBar();
void createCoverBox(); void createCoverBox();
void createGeneralInfoBox(); void createGeneralInfoBox();
@ -144,6 +149,8 @@ private:
bool updated; bool updated;
QString originalCoverSize; QString originalCoverSize;
QImage customCover;
public: public:
PropertiesDialog(QWidget *parent = nullptr); PropertiesDialog(QWidget *parent = nullptr);
QString databasePath; QString databasePath;
@ -170,7 +177,13 @@ public slots:
void setSize(float size); void setSize(float size);
void loadNextCover(); void loadNextCover();
void loadPreviousCover(); void loadPreviousCover();
void resetCover();
void loadCustomCoverImage();
void loadCustomCoverImageFromPath(const QString &path);
void setCoverPage(int pageNumber);
bool close(); bool close();
void updateCoverBoxForMultipleComics();
void updateCoverBoxForSingleComic();
signals: signals:
void coverChangedSignal(const ComicDB &comic); void coverChangedSignal(const ComicDB &comic);

View File

@ -404,12 +404,7 @@ ComicInfo &ComicInfo::operator=(const ComicInfo &comicInfo)
QPixmap ComicInfo::getCover(const QString &basePath) QPixmap ComicInfo::getCover(const QString &basePath)
{ {
if (cover.isNull()) { return QPixmap(YACReader::LibraryPaths::coverPath(basePath, hash));
cover.load(YACReader::LibraryPaths::coverPath(basePath, hash));
}
QPixmap c;
c.convertFromImage(cover);
return c;
} }
QStringList ComicInfo::getWriters() QStringList ComicInfo::getWriters()

View File

@ -84,8 +84,6 @@ public:
QVariant comicVineID; // string QVariant comicVineID; // string
QImage cover;
QVariant lastTimeOpened; // integer/date QVariant lastTimeOpened; // integer/date
QVariant coverSizeRatio; // h/w QVariant coverSizeRatio; // h/w
QVariant originalCoverSize; // string "WxH" QVariant originalCoverSize; // string "WxH"
@ -189,8 +187,6 @@ public:
Q_PROPERTY(QVariant comicVineID MEMBER comicVineID CONSTANT) Q_PROPERTY(QVariant comicVineID MEMBER comicVineID CONSTANT)
Q_PROPERTY(QImage cover MEMBER cover CONSTANT)
Q_PROPERTY(QVariant lastTimeOpened MEMBER lastTimeOpened CONSTANT) Q_PROPERTY(QVariant lastTimeOpened MEMBER lastTimeOpened CONSTANT)
Q_PROPERTY(QVariant coverSizeRatio MEMBER coverSizeRatio CONSTANT) Q_PROPERTY(QVariant coverSizeRatio MEMBER coverSizeRatio CONSTANT)

View File

@ -2,6 +2,8 @@
#include <QtCore> #include <QtCore>
#include <QAction> #include <QAction>
#include <QImageReader>
#include <QFileDialog>
using namespace YACReader; using namespace YACReader;
@ -99,3 +101,47 @@ QPixmap YACReader::hdpiPixmap(const QString &file, QSize size)
{ {
return QIcon(file).pixmap(size); return QIcon(file).pixmap(size);
} }
QString YACReader::imageFileLoader(QWidget *parent)
{
QString supportedImageFormatsString;
for (const QByteArray &format : QImageReader::supportedImageFormats()) {
supportedImageFormatsString += QString("*.%1 ").arg(QString(format));
}
return QFileDialog::getOpenFileName(parent, QObject::tr("Select custom cover"), QDir::homePath(), QObject::tr("Images (%1)").arg(supportedImageFormatsString));
}
QString YACReader::imagePathFromMimeData(const QMimeData *mimeData)
{
QString filePath;
if (mimeData->hasUrls()) {
QList<QUrl> urlList = mimeData->urls();
if (!urlList.isEmpty()) {
QUrl url = urlList.first();
if (url.isLocalFile()) {
filePath = url.toLocalFile();
QFileInfo fileInfo(filePath);
QString extension = fileInfo.suffix().toLower();
QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
bool isSupported = false;
for (const QByteArray &format : supportedFormats) {
if (extension == QString(format).toLower()) {
isSupported = true;
break;
}
}
if (!isSupported) {
filePath.clear();
}
}
}
}
return filePath;
}

View File

@ -112,6 +112,7 @@ QString addExtensionToIconPath(const QString &path);
QString addExtensionToIconPathInToolbar(const QString &path); QString addExtensionToIconPathInToolbar(const QString &path);
QAction *actionWithCustomIcon(const QIcon &icon, QAction *action); QAction *actionWithCustomIcon(const QIcon &icon, QAction *action);
QPixmap hdpiPixmap(const QString &file, QSize size); QPixmap hdpiPixmap(const QString &file, QSize size);
QString imageFileLoader(QWidget *parent);
QString imagePathFromMimeData(const QMimeData *mimeData);
} }
#endif #endif

View File

@ -21,7 +21,8 @@ HEADERS += \
$$PWD/yacreader_library_list_widget.h \ $$PWD/yacreader_library_list_widget.h \
$$PWD/yacreader_library_item_widget.h \ $$PWD/yacreader_library_item_widget.h \
$$PWD/yacreader_treeview.h \ $$PWD/yacreader_treeview.h \
$$PWD/yacreader_busy_widget.h $$PWD/yacreader_busy_widget.h \
$$PWD/yacreader_cover_label.h
!CONFIG(no_opengl){ !CONFIG(no_opengl){
HEADERS += $$PWD/yacreader_gl_flow_config_widget.h HEADERS += $$PWD/yacreader_gl_flow_config_widget.h
} }
@ -50,8 +51,8 @@ SOURCES += \
$$PWD/yacreader_library_list_widget.cpp \ $$PWD/yacreader_library_list_widget.cpp \
$$PWD/yacreader_library_item_widget.cpp \ $$PWD/yacreader_library_item_widget.cpp \
$$PWD/yacreader_treeview.cpp \ $$PWD/yacreader_treeview.cpp \
$$PWD/yacreader_busy_widget.cpp $$PWD/yacreader_busy_widget.cpp \
$$PWD/yacreader_cover_label.cpp
!CONFIG(no_opengl){ !CONFIG(no_opengl){
SOURCES += $$PWD/yacreader_gl_flow_config_widget.cpp SOURCES += $$PWD/yacreader_gl_flow_config_widget.cpp
} }

View File

@ -0,0 +1,31 @@
#include "yacreader_cover_label.h"
#include "yacreader_global_gui.h"
YACReader::CoverLabel::CoverLabel(QWidget *parent)
: QLabel(parent)
{
setAcceptDrops(true);
}
void YACReader::CoverLabel::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls() && !YACReader::imagePathFromMimeData(event->mimeData()).isEmpty()) {
event->acceptProposedAction();
}
}
void YACReader::CoverLabel::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void YACReader::CoverLabel::dropEvent(QDropEvent *event)
{
QString path = YACReader::imagePathFromMimeData(event->mimeData());
if (!path.isEmpty()) {
emit imageDropped(path);
event->acceptProposedAction();
}
}

View File

@ -0,0 +1,29 @@
#ifndef DROP_LABEL_H
#define DROP_LABEL_H
#include <QLabel>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
namespace YACReader {
class CoverLabel : public QLabel
{
Q_OBJECT
public:
explicit CoverLabel(QWidget *parent = nullptr);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
signals:
void imageDropped(const QString &path);
};
}
#endif // DROP_LABEL_H

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<defs>
<style>
.cls-1 {
fill: #fff;
}
</style>
</defs>
<polygon class="cls-1" points="4 3 4 2 2 2 2 3 2 6 6 6 6 3 4 3"/>
</svg>

After

Width:  |  Height:  |  Size: 292 B

15
images/resetCover.svg Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #fff;
stroke-miterlimit: 10;
stroke-width: 1.5px;
}
</style>
</defs>
<line class="cls-1" x1="2.35" y1="2.29" x2="5.65" y2="5.71"/>
<line class="cls-1" x1="5.65" y1="2.29" x2="2.35" y2="5.71"/>
</svg>

After

Width:  |  Height:  |  Size: 434 B