yacreader/YACReader/goto_flow.cpp
Luis Ángel San Martín 686e91af57 Fix missing include
2023-04-30 14:28:40 +02:00

298 lines
7.3 KiB
C++

#include "goto_flow.h"
#include "configuration.h"
#include <QVBoxLayout>
#include <QSize>
#include <QImage>
#include <QLabel>
#include <QPushButton>
#include <QMutex>
#include <QApplication>
#include <QLineEdit>
#include <QPushButton>
#include <QPixmap>
#include <QThread>
#include <QSize>
#include <QIntValidator>
#include <QWaitCondition>
#include <QObject>
#include <QEvent>
#include <QKeyEvent>
#include <QLabel>
#include <QTimer>
#include "yacreader_flow.h"
#include "goto_flow_toolbar.h"
GoToFlow::GoToFlow(QWidget *parent, FlowType flowType)
: GoToFlowWidget(parent), ready(false)
{
updateTimer = new QTimer;
connect(updateTimer, &QTimer::timeout, this, &GoToFlow::updateImageData);
worker = new PageLoader(&mutexGoToFlow);
flow = new YACReaderFlow(this, flowType);
flow->setReflectionEffect(PictureFlow::PlainReflection);
imageSize = Configuration::getConfiguration().getGotoSlideSize();
flow->setSlideSize(imageSize);
connect(flow, &PictureFlow::centerIndexChanged, this, &GoToFlowWidget::setPageNumber);
connect(flow, &YACReaderFlow::selected, this, &GoToFlow::goToPage);
connect(flow, &PictureFlow::centerIndexChanged, this, &GoToFlow::preload);
connect(flow, &PictureFlow::centerIndexChangedSilent, this, &GoToFlow::preload);
connect(toolBar, &GoToFlowToolBar::goToPage, this, &GoToFlow::goToPage);
connect(toolBar, &GoToFlowToolBar::setCenter, flow, &PictureFlow::showSlide);
mainLayout->addWidget(flow);
toolBar->raise();
resize(static_cast<int>(5 * imageSize.width()), toolBar->height() + static_cast<int>(imageSize.height() * 1.7));
this->setCursor(QCursor(Qt::ArrowCursor));
}
GoToFlow::~GoToFlow()
{
delete flow;
delete updateTimer;
worker->deleteLater();
}
void GoToFlow::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Left:
case Qt::Key_Right:
case Qt::Key_Up:
QApplication::sendEvent(flow, event);
return;
default:
break;
}
GoToFlowWidget::keyPressEvent(event);
}
void GoToFlow::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
toolBar->move(0, event->size().height() - toolBar->height());
toolBar->setFixedWidth(width());
}
void GoToFlow::centerSlide(int slide)
{
if (flow->centerIndex() != slide) {
flow->setCenterIndex(slide);
if (ready) // load images if pages are loaded.
{
// worker->reset(); //BUG FIXED : image didn't load if worker was working
preload();
}
}
}
void GoToFlow::setNumSlides(unsigned int slides)
{
// numPagesLabel->setText(tr("Total pages : ")+QString::number(slides));
// numPagesLabel->adjustSize();
imagesReady.clear();
imagesReady.fill(false, slides);
rawImages.clear();
rawImages.resize(slides);
toolBar->setTop(slides);
imagesLoaded.clear();
imagesLoaded.fill(false, slides);
imagesSetted.clear();
imagesSetted.fill(false, slides);
numImagesLoaded = 0;
ready = true;
worker->reset();
flow->clear();
for (unsigned int i = 0; i < slides; i++)
flow->addSlide(QImage());
flow->setCenterIndex(0);
}
void GoToFlow::reset()
{
updateTimer->stop();
/*imagesLoaded.clear();
numImagesLoaded = 0;
imagesReady.clear();
rawImages.clear();*/
ready = false;
}
void GoToFlow::setImageReady(int index, const QByteArray &image)
{
rawImages[index] = image;
imagesReady[index] = true;
preload();
}
void GoToFlow::preload()
{
if (numImagesLoaded < imagesLoaded.size())
updateTimer->start(30); // TODO comprobar rendimiento, antes era 70
}
void GoToFlow::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]) {
flow->setSlide(idx, worker->result());
imagesSetted[idx] = true;
numImagesLoaded++;
rawImages[idx].clear();
; // release memory
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 = flow->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 < flow->slideCount()))
if (!imagesLoaded[i] && imagesReady[i]) // slide(i).isNull())
{
// schedule thumbnail generation
worker->generate(i, flow->slideSize(), rawImages[i]);
return;
}
}
// no need to generate anything? stop polling...
updateTimer->stop();
}
void GoToFlow::wheelEvent(QWheelEvent *event)
{
if (event->angleDelta().y() < 0)
flow->showNext();
else
flow->showPrevious();
event->accept();
}
void GoToFlow::setFlowType(YACReader::FlowType flowType)
{
flow->setFlowType(flowType);
}
void GoToFlow::updateConfig(QSettings *settings)
{
GoToFlowWidget::updateConfig(settings);
imageSize = Configuration::getConfiguration().getGotoSlideSize();
flow->setFlowType(Configuration::getConfiguration().getFlowType());
resize(5 * imageSize.width(), toolBar->height() + imageSize.height() * 1.7);
updateSize();
}
void GoToFlow::setFlowRightToLeft(bool b)
{
flow->setFlowRightToLeft(b);
}
//-----------------------------------------------------------------------------
// PageLoader
//-----------------------------------------------------------------------------
PageLoader::PageLoader(QMutex *m)
: QThread(), mutex(m), restart(false), working(false), idx(-1)
{
}
PageLoader::~PageLoader()
{
// TODO this destructor never runs. If it is ever called, it will hang, because
// the implementation is broken due to the absolutely endless loop in run().
mutex->lock();
condition.wakeOne();
mutex->unlock();
wait();
}
bool PageLoader::busy() const
{
return isRunning() ? working.load() : false;
}
void PageLoader::generate(int index, QSize size, const QByteArray &rImage)
{
mutex->lock();
this->idx = index;
// this->img = QImage();
this->size = size;
this->rawImage = rImage;
mutex->unlock();
if (!isRunning())
start();
else {
mutex->lock();
// already running, wake up whenever ready
restart = true;
condition.wakeOne();
mutex->unlock();
}
}
void PageLoader::run()
{
for (;;) {
// copy necessary data
mutex->lock();
this->working = true;
// int idx = this->idx;
QImage image;
image.loadFromData(this->rawImage);
// let everyone knows it is ready
image = image.scaled(this->size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
mutex->unlock();
mutex->lock();
this->img = image;
this->working = false;
mutex->unlock();
// put to sleep
mutex->lock();
while (!this->restart)
condition.wait(mutex);
restart = false;
mutex->unlock();
}
}