mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			640 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			640 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //    Copyright (C) 2018-2023 Jakub Melka
 | |
| //
 | |
| //    This file is part of PDF4QT.
 | |
| //
 | |
| //    PDF4QT is free software: you can redistribute it and/or modify
 | |
| //    it under the terms of the GNU Lesser General Public License as published by
 | |
| //    the Free Software Foundation, either version 3 of the License, or
 | |
| //    with the written consent of the copyright owner, any later version.
 | |
| //
 | |
| //    PDF4QT is distributed in the hope that it will be useful,
 | |
| //    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| //    GNU Lesser General Public License for more details.
 | |
| //
 | |
| //    You should have received a copy of the GNU Lesser General Public License
 | |
| //    along with PDF4QT.  If not, see <https://www.gnu.org/licenses/>.
 | |
| 
 | |
| #include "pdfdrawwidget.h"
 | |
| #include "pdfdrawspacecontroller.h"
 | |
| #include "pdfcompiler.h"
 | |
| #include "pdfwidgettool.h"
 | |
| #include "pdfannotation.h"
 | |
| #include "pdfwidgetannotation.h"
 | |
| #include "pdfwidgetformmanager.h"
 | |
| #include "pdfblpainter.h"
 | |
| 
 | |
| #include <QPainter>
 | |
| #include <QGridLayout>
 | |
| #include <QKeyEvent>
 | |
| #include <QApplication>
 | |
| #include <QPixmapCache>
 | |
| #include <QColorSpace>
 | |
| 
 | |
| #include "pdfdbgheap.h"
 | |
| 
 | |
| namespace pdf
 | |
| {
 | |
| 
 | |
| PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, QWidget* parent) :
 | |
|     QWidget(parent),
 | |
|     m_cmsManager(cmsManager),
 | |
|     m_toolManager(nullptr),
 | |
|     m_annotationManager(nullptr),
 | |
|     m_formManager(nullptr),
 | |
|     m_drawWidget(nullptr),
 | |
|     m_horizontalScrollBar(nullptr),
 | |
|     m_verticalScrollBar(nullptr),
 | |
|     m_proxy(nullptr),
 | |
|     m_rendererEngine(engine)
 | |
| {
 | |
|     m_drawWidget = new PDFDrawWidget(this, this);
 | |
|     m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
 | |
|     m_verticalScrollBar = new QScrollBar(Qt::Vertical, this);
 | |
| 
 | |
|     QGridLayout* layout = new QGridLayout(this);
 | |
|     layout->setSpacing(0);
 | |
|     layout->addWidget(m_drawWidget->getWidget(), 0, 0);
 | |
|     layout->addWidget(m_horizontalScrollBar, 1, 0);
 | |
|     layout->addWidget(m_verticalScrollBar, 0, 1);
 | |
|     layout->setContentsMargins(QMargins());
 | |
| 
 | |
|     setLayout(layout);
 | |
|     setFocusProxy(m_drawWidget->getWidget());
 | |
| 
 | |
|     m_proxy = new PDFDrawWidgetProxy(this);
 | |
|     m_proxy->init(this);
 | |
|     m_proxy->updateRenderer(m_rendererEngine);
 | |
|     connect(m_proxy, &PDFDrawWidgetProxy::renderingError, this, &PDFWidget::onRenderingError);
 | |
|     connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
 | |
|     connect(m_proxy, &PDFDrawWidgetProxy::pageImageChanged, this, &PDFWidget::onPageImageChanged);
 | |
| }
 | |
| 
 | |
| PDFWidget::~PDFWidget()
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| bool PDFWidget::focusNextPrevChild(bool next)
 | |
| {
 | |
|     if (m_formManager && m_formManager->focusNextPrevFormField(next))
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     return QWidget::focusNextPrevChild(next);
 | |
| }
 | |
| 
 | |
| void PDFWidget::setDocument(const PDFModifiedDocument& document)
 | |
| {
 | |
|     m_proxy->setDocument(document);
 | |
|     m_pageRenderingErrors.clear();
 | |
|     m_drawWidget->getWidget()->update();
 | |
| }
 | |
| 
 | |
| void PDFWidget::updateRenderer(RendererEngine engine)
 | |
| {
 | |
|     m_rendererEngine = engine;
 | |
|     m_proxy->updateRenderer(m_rendererEngine);
 | |
| }
 | |
| 
 | |
| void PDFWidget::updateCacheLimits(int compiledPageCacheLimit, int thumbnailsCacheLimit, int fontCacheLimit, int instancedFontCacheLimit)
 | |
| {
 | |
|     m_proxy->getCompiler()->setCacheLimit(compiledPageCacheLimit);
 | |
|     QPixmapCache::setCacheLimit(qMax(thumbnailsCacheLimit, 16384));
 | |
|     m_proxy->getFontCache()->setCacheLimits(fontCacheLimit, instancedFontCacheLimit);
 | |
| }
 | |
| 
 | |
| int PDFWidget::getPageRenderingErrorCount() const
 | |
| {
 | |
|     int count = 0;
 | |
|     for (const auto& item : m_pageRenderingErrors)
 | |
|     {
 | |
|         count += item.second.size();
 | |
|     }
 | |
|     return count;
 | |
| }
 | |
| 
 | |
| void PDFWidget::onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors)
 | |
| {
 | |
|     // Empty list of error should not be reported!
 | |
|     Q_ASSERT(!errors.empty());
 | |
|     m_pageRenderingErrors[pageIndex] = errors;
 | |
|     Q_EMIT pageRenderingErrorsChanged(pageIndex, errors.size());
 | |
| }
 | |
| 
 | |
| void PDFWidget::onPageImageChanged(bool all, const std::vector<PDFInteger>& pages)
 | |
| {
 | |
|     if (all)
 | |
|     {
 | |
|         m_drawWidget->getWidget()->update();
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         std::vector<PDFInteger> currentPages = m_drawWidget->getCurrentPages();
 | |
| 
 | |
|         Q_ASSERT(std::is_sorted(pages.cbegin(), pages.cend()));
 | |
|         for (PDFInteger pageIndex : currentPages)
 | |
|         {
 | |
|             if (std::binary_search(pages.cbegin(), pages.cend(), pageIndex))
 | |
|             {
 | |
|                 m_drawWidget->getWidget()->update();
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFWidget::removeInputInterface(IDrawWidgetInputInterface* inputInterface)
 | |
| {
 | |
|     auto it = std::find(m_inputInterfaces.begin(), m_inputInterfaces.end(), inputInterface);
 | |
|     if (it != m_inputInterfaces.end())
 | |
|     {
 | |
|         m_inputInterfaces.erase(it);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
 | |
| {
 | |
|     if (inputInterface)
 | |
|     {
 | |
|         m_inputInterfaces.push_back(inputInterface);
 | |
|         std::sort(m_inputInterfaces.begin(), m_inputInterfaces.end(), IDrawWidgetInputInterface::Comparator());
 | |
|     }
 | |
| }
 | |
| 
 | |
| PDFWidgetFormManager* PDFWidget::getFormManager() const
 | |
| {
 | |
|     return m_formManager;
 | |
| }
 | |
| 
 | |
| void PDFWidget::setFormManager(PDFWidgetFormManager* formManager)
 | |
| {
 | |
|     removeInputInterface(m_formManager);
 | |
|     m_formManager = formManager;
 | |
|     addInputInterface(m_formManager);
 | |
| }
 | |
| 
 | |
| void PDFWidget::setToolManager(PDFToolManager* toolManager)
 | |
| {
 | |
|     removeInputInterface(m_toolManager);
 | |
|     m_toolManager = toolManager;
 | |
|     addInputInterface(m_toolManager);
 | |
| }
 | |
| 
 | |
| void PDFWidget::setAnnotationManager(PDFWidgetAnnotationManager* annotationManager)
 | |
| {
 | |
|     removeInputInterface(m_annotationManager);
 | |
|     m_annotationManager = annotationManager;
 | |
|     addInputInterface(m_annotationManager);
 | |
| }
 | |
| 
 | |
| PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
 | |
|     BaseClass(parent),
 | |
|     m_widget(widget),
 | |
|     m_mouseOperation(MouseOperation::None)
 | |
| {
 | |
|     this->setFocusPolicy(Qt::StrongFocus);
 | |
|     this->setMouseTracking(true);
 | |
| 
 | |
|     QObject::connect(&m_autoScrollTimer, &QTimer::timeout, this, &PDFDrawWidget::onAutoScrollTimeout);
 | |
| }
 | |
| 
 | |
| std::vector<PDFInteger> PDFDrawWidget::getCurrentPages() const
 | |
| {
 | |
|     return this->m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect());
 | |
| }
 | |
| 
 | |
| QSize PDFDrawWidget::minimumSizeHint() const
 | |
| {
 | |
|     return QSize(200, 200);
 | |
| }
 | |
| 
 | |
| bool PDFDrawWidget::event(QEvent* event)
 | |
| {
 | |
|     if (event->type() == QEvent::ShortcutOverride)
 | |
|     {
 | |
|         return processEvent<QKeyEvent, &IDrawWidgetInputInterface::shortcutOverrideEvent>(static_cast<QKeyEvent*>(event));
 | |
|     }
 | |
| 
 | |
|     return BaseClass::event(event);
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::performMouseOperation(QPoint currentMousePosition)
 | |
| {
 | |
|     switch (m_mouseOperation)
 | |
|     {
 | |
|         case MouseOperation::None:
 | |
|             // No operation performed
 | |
|             break;
 | |
| 
 | |
|         case MouseOperation::Translate:
 | |
|         {
 | |
|             QPoint difference = currentMousePosition - m_lastMousePosition;
 | |
|             m_widget->getDrawWidgetProxy()->scrollByPixels(difference);
 | |
|             m_lastMousePosition = currentMousePosition;
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case MouseOperation::AutoScroll:
 | |
|         {
 | |
|             m_lastMousePosition = currentMousePosition;
 | |
|             onAutoScrollTimeout();
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         default:
 | |
|             Q_ASSERT(false);
 | |
|     }
 | |
| }
 | |
| 
 | |
| template<typename Event, void (IDrawWidgetInputInterface::* Function)(QWidget*, Event*)>
 | |
| bool PDFDrawWidget::processEvent(Event* event)
 | |
| {
 | |
|     QString tooltip;
 | |
|     for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces())
 | |
|     {
 | |
|         (inputInterface->*Function)(this, event);
 | |
| 
 | |
|         // Update tooltip
 | |
|         if (tooltip.isEmpty())
 | |
|         {
 | |
|             tooltip = inputInterface->getTooltip();
 | |
|         }
 | |
| 
 | |
|         // If event is accepted, then update cursor/tooltip and return
 | |
|         if (event->isAccepted())
 | |
|         {
 | |
|             this->setToolTip(tooltip);
 | |
|             this->updateCursor();
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     this->setToolTip(tooltip);
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::keyPressEvent(QKeyEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QKeyEvent, &IDrawWidgetInputInterface::keyPressEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     // Vertical navigation
 | |
|     QScrollBar* verticalScrollbar = m_widget->getVerticalScrollbar();
 | |
|     if (verticalScrollbar->isVisible())
 | |
|     {
 | |
|         constexpr std::pair<QKeySequence::StandardKey, PDFDrawWidgetProxy::Operation> keyToOperations[] =
 | |
|         {
 | |
|             { QKeySequence::MoveToStartOfDocument, PDFDrawWidgetProxy::NavigateDocumentStart },
 | |
|             { QKeySequence::MoveToEndOfDocument, PDFDrawWidgetProxy::NavigateDocumentEnd },
 | |
|             { QKeySequence::MoveToNextPage, PDFDrawWidgetProxy::NavigateNextPage },
 | |
|             { QKeySequence::MoveToPreviousPage, PDFDrawWidgetProxy::NavigatePreviousPage },
 | |
|             { QKeySequence::MoveToNextLine, PDFDrawWidgetProxy::NavigateNextStep },
 | |
|             { QKeySequence::MoveToPreviousLine, PDFDrawWidgetProxy::NavigatePreviousStep }
 | |
|         };
 | |
| 
 | |
|         for (const std::pair<QKeySequence::StandardKey, PDFDrawWidgetProxy::Operation>& keyToOperation : keyToOperations)
 | |
|         {
 | |
|             if (event->matches(keyToOperation.first))
 | |
|             {
 | |
|                 m_widget->getDrawWidgetProxy()->performOperation(keyToOperation.second);
 | |
|                 event->accept();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     updateCursor();
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::keyReleaseEvent(QKeyEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QKeyEvent, &IDrawWidgetInputInterface::keyReleaseEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     event->accept();
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::mousePressEvent(QMouseEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mousePressEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (event->button() == Qt::LeftButton)
 | |
|     {
 | |
|         m_mouseOperation = MouseOperation::Translate;
 | |
|         m_lastMousePosition = event->pos();
 | |
|     }
 | |
| 
 | |
|     if (event->button() == Qt::MiddleButton)
 | |
|     {
 | |
|         if (m_mouseOperation == MouseOperation::AutoScroll)
 | |
|         {
 | |
|             m_mouseOperation = MouseOperation::None;
 | |
|             m_autoScrollTimer.stop();
 | |
|             m_autoScrollLastElapsedTimer.restart();
 | |
|             m_autoScrollOffset = QPointF(0.0, 0.0);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             m_mouseOperation = MouseOperation::AutoScroll;
 | |
|             m_autoScrollMousePosition = event->pos();
 | |
|             m_autoScrollLastElapsedTimer.restart();
 | |
|             m_autoScrollOffset = QPointF(0.0, 0.0);
 | |
|             m_lastMousePosition = event->pos();
 | |
|             m_autoScrollTimer.setInterval(10);
 | |
|             m_autoScrollTimer.start();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     updateCursor();
 | |
|     event->accept();
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::mouseDoubleClickEvent(QMouseEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mouseDoubleClickEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::mouseReleaseEvent(QMouseEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mouseReleaseEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     performMouseOperation(event->pos());
 | |
| 
 | |
|     switch (m_mouseOperation)
 | |
|     {
 | |
|         case MouseOperation::None:
 | |
|             break;
 | |
| 
 | |
|         case MouseOperation::Translate:
 | |
|         {
 | |
|             if (event->button() != Qt::MiddleButton)
 | |
|             {
 | |
|                 m_mouseOperation = MouseOperation::None;
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case MouseOperation::AutoScroll:
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             Q_ASSERT(false);
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     updateCursor();
 | |
|     event->accept();
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::mouseMoveEvent(QMouseEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mouseMoveEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     performMouseOperation(event->pos());
 | |
|     updateCursor();
 | |
|     event->accept();
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::updateCursor()
 | |
| {
 | |
|     std::optional<QCursor> cursor;
 | |
| 
 | |
|     for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces())
 | |
|     {
 | |
|         cursor = inputInterface->getCursor();
 | |
| 
 | |
|         if (cursor)
 | |
|         {
 | |
|             // We have found cursor
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!cursor)
 | |
|     {
 | |
|         switch (m_mouseOperation)
 | |
|         {
 | |
|             case MouseOperation::None:
 | |
|                 cursor = QCursor(Qt::OpenHandCursor);
 | |
|                 break;
 | |
| 
 | |
|             case MouseOperation::Translate:
 | |
|                 cursor = QCursor(Qt::ClosedHandCursor);
 | |
|                 break;
 | |
| 
 | |
|             case MouseOperation::AutoScroll:
 | |
|                 cursor = QCursor(Qt::SizeAllCursor);
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 Q_ASSERT(false);
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (cursor)
 | |
|     {
 | |
|         this->setCursor(*cursor);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         this->unsetCursor();
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::onAutoScrollTimeout()
 | |
| {
 | |
|     if (m_mouseOperation != MouseOperation::AutoScroll)
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     QPointF offset = m_autoScrollMousePosition - m_lastMousePosition;
 | |
|     QPointF scrollOffset = m_autoScrollOffset;
 | |
| 
 | |
|     qreal secondsElapsed = qreal(m_autoScrollLastElapsedTimer.nsecsElapsed()) * 0.000000001;
 | |
|     m_autoScrollLastElapsedTimer.restart();
 | |
|     scrollOffset += offset * secondsElapsed;
 | |
| 
 | |
|     int scrollX = qFloor(scrollOffset.x());
 | |
|     int scrollY = qFloor(scrollOffset.y());
 | |
| 
 | |
|     scrollOffset -= QPointF(scrollX, scrollY);
 | |
|     m_autoScrollOffset = scrollOffset;
 | |
| 
 | |
|     PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
 | |
|     proxy->scrollByPixels(QPoint(scrollX, scrollY));
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::wheelEvent(QWheelEvent* event)
 | |
| {
 | |
|     event->ignore();
 | |
| 
 | |
|     if (processEvent<QWheelEvent, &IDrawWidgetInputInterface::wheelEvent>(event))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
 | |
| 
 | |
|     PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
 | |
|     if (keyboardModifiers.testFlag(Qt::ControlModifier))
 | |
|     {
 | |
|         // Zoom in/Zoom out
 | |
|         const int angleDeltaY = event->angleDelta().y();
 | |
|         const PDFReal zoom = m_widget->getDrawWidgetProxy()->getZoom();
 | |
|         const PDFReal zoomStep = std::pow(PDFDrawWidgetProxy::ZOOM_STEP, static_cast<PDFReal>(angleDeltaY) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep));
 | |
|         const PDFReal newZoom = zoom * zoomStep;
 | |
|         proxy->zoom(newZoom);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         // Move Up/Down. Angle is negative, if wheel is scrolled down. First we try to scroll by pixel delta.
 | |
|         // Otherwise we compute scroll using angle.
 | |
|         QPoint scrollByPixels = event->pixelDelta();
 | |
|         if (scrollByPixels.isNull())
 | |
|         {
 | |
|             const QPoint angleDelta = event->angleDelta();
 | |
|             const bool shiftModifier = keyboardModifiers.testFlag(Qt::ShiftModifier);
 | |
|             int stepVertical = 0;
 | |
|             int stepHorizontal = shiftModifier ? m_widget->getHorizontalScrollbar()->pageStep() : m_widget->getHorizontalScrollbar()->singleStep();
 | |
| 
 | |
|             if (proxy->isBlockMode())
 | |
|             {
 | |
|                 // In block mode, we must calculate pixel offsets differently - scrollbars corresponds to indices of blocks,
 | |
|                 // not to the pixels.
 | |
|                 QRect boundingBox = proxy->getPagesIntersectingRectBoundingBox(this->rect());
 | |
| 
 | |
|                 if (boundingBox.isEmpty())
 | |
|                 {
 | |
|                     // This occurs, when we have not opened a document
 | |
|                     boundingBox = this->rect();
 | |
|                 }
 | |
| 
 | |
|                 stepVertical = shiftModifier ? boundingBox.height() : boundingBox.height() / 10;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 stepVertical = shiftModifier ? m_widget->getVerticalScrollbar()->pageStep() : m_widget->getVerticalScrollbar()->singleStep();
 | |
|             }
 | |
| 
 | |
|             const int scrollVertical = stepVertical * static_cast<PDFReal>(angleDelta.y()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep);
 | |
|             const int scrollHorizontal = stepHorizontal * static_cast<PDFReal>(angleDelta.x()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep);
 | |
| 
 | |
|             scrollByPixels = QPoint(scrollHorizontal, scrollVertical);
 | |
|         }
 | |
| 
 | |
|         QPoint offset = proxy->scrollByPixels(scrollByPixels);
 | |
| 
 | |
|         if (offset.y() == 0 && scrollByPixels.y() != 0 && proxy->isBlockMode())
 | |
|         {
 | |
|             // We must move to another block (we are in block mode)
 | |
|             bool up = scrollByPixels.y() > 0;
 | |
| 
 | |
|             QScrollBar* verticalScrollbar = m_widget->getVerticalScrollbar();
 | |
|             const int newValue = verticalScrollbar->value() + (up ? -1 : 1);
 | |
| 
 | |
|             if (newValue >= verticalScrollbar->minimum() && newValue <= verticalScrollbar->maximum())
 | |
|             {
 | |
|                 verticalScrollbar->setValue(newValue);
 | |
|                 proxy->scrollByPixels(QPoint(0, up ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max()));
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     event->accept();
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::paintEvent(QPaintEvent* event)
 | |
| {
 | |
|     Q_UNUSED(event);
 | |
| 
 | |
|     RendererEngine rendererEngine = getPDFWidget()->getDrawWidgetProxy()->getRendererEngine();
 | |
|     switch (rendererEngine)
 | |
|     {
 | |
|         case RendererEngine::Blend2D_MultiThread:
 | |
|         case RendererEngine::Blend2D_SingleThread:
 | |
|         {
 | |
|             QRect rect = this->rect();
 | |
| 
 | |
|             qreal devicePixelRatio = devicePixelRatioF();
 | |
|             m_blend2DframeBuffer.setDevicePixelRatio(devicePixelRatio);
 | |
| 
 | |
|             qreal dpmX = logicalDpiX() / 0.0254;
 | |
|             qreal dpmY = logicalDpiY() / 0.0254;
 | |
|             m_blend2DframeBuffer.setDotsPerMeterX(qCeil(dpmX));
 | |
|             m_blend2DframeBuffer.setDotsPerMeterY(qCeil(dpmY));
 | |
| 
 | |
|             QSize requiredSize = rect.size() * devicePixelRatio;
 | |
|             if (m_blend2DframeBuffer.size() != requiredSize)
 | |
|             {
 | |
|                 m_blend2DframeBuffer = QImage(requiredSize, QImage::Format_ARGB32_Premultiplied);
 | |
|             }
 | |
| 
 | |
|             const bool multithreaded = rendererEngine == RendererEngine::Blend2D_MultiThread;
 | |
|             PDFBLPaintDevice blPaintDevice(m_blend2DframeBuffer, multithreaded);
 | |
|             QPainter blPainter;
 | |
| 
 | |
|             if (blPainter.begin(&blPaintDevice))
 | |
|             {
 | |
|                 getPDFWidget()->getDrawWidgetProxy()->draw(&blPainter, rect);
 | |
|                 blPainter.end();
 | |
|             }
 | |
| 
 | |
|             QPainter painter(this);
 | |
|             painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case RendererEngine::QPainter:
 | |
|         {
 | |
|             QPainter painter(this);
 | |
|             getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
 | |
|             m_blend2DframeBuffer = QImage();
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         default:
 | |
|             Q_ASSERT(false);
 | |
|             break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFDrawWidget::resizeEvent(QResizeEvent* event)
 | |
| {
 | |
|     BaseClass::resizeEvent(event);
 | |
| 
 | |
|     getPDFWidget()->getDrawWidgetProxy()->update();
 | |
| }
 | |
| 
 | |
| }   // namespace pdf
 |