yacreader/YACReaderLibrary/comic_flow.cpp
2019-05-30 19:46:37 +02:00

255 lines
5.5 KiB
C++

#include "comic_flow.h"
#include "qnaturalsorting.h"
#include "yacreader_global.h"
#include <algorithm>
#include <QMutex>
#include <QImageReader>
#include <QTimer>
ComicFlow::ComicFlow(QWidget *parent, FlowType flowType)
: YACReaderFlow(parent, flowType)
{
updateTimer = new QTimer;
connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateImageData()));
worker = new ImageLoader;
connect(this, SIGNAL(centerIndexChanged(int)), this, SLOT(preload()));
connect(this, SIGNAL(centerIndexChangedSilent(int)), this, SLOT(preload()));
setReflectionEffect(PlainReflection);
}
ComicFlow::~ComicFlow()
{
worker->terminate();
delete worker;
delete updateTimer;
}
void ComicFlow::setImagePaths(const QStringList &paths)
{
clear();
//imagePath = path;
imageFiles = paths;
imagesLoaded.clear();
imagesLoaded.fill(false, imageFiles.size());
numImagesLoaded = 0;
imagesSetted.clear();
imagesSetted.fill(false, imageFiles.size());
// populate with empty images
QImage img; //TODO remove
QString s;
for (int i = 0; i < (int)imageFiles.size(); i++) {
addSlide(img);
s = imageFiles.at(i);
s.remove(s.size() - 4, 4);
if (QFileInfo(s + ".r").exists())
markSlide(i);
}
setCenterIndex(0);
worker->reset();
preload();
}
void ComicFlow::preload()
{
if (numImagesLoaded < imagesLoaded.size())
updateTimer->start(30); //TODO comprobar rendimiento, originalmente era 70
}
void ComicFlow::updateImageData()
{
// can't do anything, wait for the next possibility
if (worker->busy())
return;
// set image of last one
int idx = worker->index();
if (idx >= 0 && !worker->result().isNull()) {
if (!imagesSetted[idx]) {
setSlide(idx, worker->result());
imagesSetted[idx] = true;
numImagesLoaded++;
imagesLoaded[idx] = true;
}
}
// try to load only few images on the left and right side
// i.e. all visible ones plus some extra
#define COUNT 8
int indexes[2 * COUNT + 1];
int center = centerIndex();
indexes[0] = center;
for (int j = 0; j < COUNT; j++) {
indexes[j * 2 + 1] = center + j + 1;
indexes[j * 2 + 2] = center - j - 1;
}
for (int c = 0; c < 2 * COUNT + 1; c++) {
int i = indexes[c];
if ((i >= 0) && (i < slideCount()))
if (!imagesLoaded[i]) //slide(i).isNull())
{
// schedule thumbnail generation
QString fname = imageFiles[i];
worker->generate(i, fname, slideSize());
return;
}
}
// no need to generate anything? stop polling...
updateTimer->stop();
}
void ComicFlow::keyPressEvent(QKeyEvent *event)
{
PictureFlow::keyPressEvent(event);
}
void ComicFlow::wheelEvent(QWheelEvent *event)
{
if (event->delta() < 0)
showNext();
else
showPrevious();
event->accept();
}
void ComicFlow::removeSlide(int cover)
{
worker->lock();
worker->reset();
imageFiles.removeAt(cover);
if (imagesLoaded[cover])
numImagesLoaded--;
imagesLoaded.remove(cover);
imagesSetted.remove(cover);
YACReaderFlow::removeSlide(cover);
worker->unlock();
preload();
}
void ComicFlow::resortCovers(QList<int> newOrder)
{
worker->lock();
worker->reset();
YACReaderFlow::resortCovers(newOrder);
QStringList imageFilesNew;
QVector<bool> imagesLoadedNew;
QVector<bool> imagesSettedNew;
foreach (int index, newOrder) {
imageFilesNew << imageFiles.at(index);
imagesLoadedNew << imagesLoaded.at(index);
imagesSettedNew << imagesSetted.at(index);
}
imageFiles = imageFilesNew;
imagesLoaded = imagesLoadedNew;
imagesSetted = imagesSettedNew;
worker->unlock();
}
//-----------------------------------------------------------------------------
//ImageLoader
//-----------------------------------------------------------------------------
static QImage loadImage(const QString &fileName)
{
QImage image;
bool result = image.load(fileName);
if (!result)
return QImage();
return image;
}
ImageLoader::ImageLoader()
: QThread(), restart(false), working(false), idx(-1)
{
}
ImageLoader::~ImageLoader()
{
mutex.lock();
condition.wakeOne();
mutex.unlock();
wait();
}
bool ImageLoader::busy() const
{
return isRunning() ? working : false;
}
void ImageLoader::generate(int index, const QString &fileName, QSize size)
{
mutex.lock();
this->idx = index;
this->fileName = fileName;
this->size = size;
this->img = QImage();
mutex.unlock();
if (!isRunning())
start();
else {
// already running, wake up whenever ready
restart = true;
condition.wakeOne();
}
}
void ImageLoader::lock()
{
mutex.lock();
}
void ImageLoader::unlock()
{
mutex.unlock();
}
void ImageLoader::run()
{
for (;;) {
// copy necessary data
mutex.lock();
this->working = true;
QString fileName = this->fileName;
mutex.unlock();
QImage image = loadImage(fileName);
// let everyone knows it is ready
mutex.lock();
this->working = false;
this->img = image;
mutex.unlock();
// put to sleep
mutex.lock();
if (!this->restart)
condition.wait(&mutex);
restart = false;
mutex.unlock();
}
}
QImage ImageLoader::result()
{
return img;
}