#include "goto_flow.h" #include "configuration.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(5 * imageSize.width()), toolBar->height() + static_cast(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(); } }