mirror of
https://github.com/YACReader/yacreader
synced 2025-05-28 03:10:27 -04:00
266 lines
4.9 KiB
C++
266 lines
4.9 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;
|
|
}
|