diff options
Diffstat (limited to 'src/pdfquick/PdfScrollablePageView.qml')
-rw-r--r-- | src/pdfquick/PdfScrollablePageView.qml | 187 |
1 files changed, 61 insertions, 126 deletions
diff --git a/src/pdfquick/PdfScrollablePageView.qml b/src/pdfquick/PdfScrollablePageView.qml index 6b03c1c1c..9fa0547c6 100644 --- a/src/pdfquick/PdfScrollablePageView.qml +++ b/src/pdfquick/PdfScrollablePageView.qml @@ -1,41 +1,8 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtPDF module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls import QtQuick.Pdf @@ -75,8 +42,6 @@ Flickable { This property holds the \l {QtQuick::Image::status}{rendering status} of the \l {currentPage}{current page}. - - \sa PdfPageImage::status */ property alias status: image.status @@ -126,9 +91,9 @@ Flickable { \c onCurrentPageChanged script) to update the part of the user interface that shows the current page number, such as a \l SpinBox. - \sa PdfNavigationStack::currentPage + \sa PdfPageNavigator::currentPage */ - property alias currentPage: navigationStack.currentPage + property alias currentPage: pageNavigator.currentPage /*! \qmlproperty bool PdfScrollablePageView::backEnabled @@ -137,9 +102,9 @@ Flickable { This property indicates if it is possible to go back in the navigation history to a previous-viewed page. - \sa PdfNavigationStack::backAvailable, back() + \sa PdfPageNavigator::backAvailable, back() */ - property alias backEnabled: navigationStack.backAvailable + property alias backEnabled: pageNavigator.backAvailable /*! \qmlproperty bool PdfScrollablePageView::forwardEnabled @@ -148,9 +113,9 @@ Flickable { This property indicates if it is possible to go to next location in the navigation history. - \sa PdfNavigationStack::forwardAvailable, forward() + \sa PdfPageNavigator::forwardAvailable, forward() */ - property alias forwardEnabled: navigationStack.forwardAvailable + property alias forwardEnabled: pageNavigator.forwardAvailable /*! \qmlmethod void PdfScrollablePageView::back() @@ -159,9 +124,9 @@ Flickable { recently; or does nothing if there is no previous location on the navigation stack. - \sa PdfNavigationStack::back(), currentPage, backEnabled + \sa PdfPageNavigator::back(), currentPage, backEnabled */ - function back() { navigationStack.back() } + function back() { pageNavigator.back() } /*! \qmlmethod void PdfScrollablePageView::forward() @@ -170,19 +135,19 @@ Flickable { method was called; or does nothing if there is no "next" location on the navigation stack. - \sa PdfNavigationStack::forward(), currentPage + \sa PdfPageNavigator::forward(), currentPage */ - function forward() { navigationStack.forward() } + function forward() { pageNavigator.forward() } /*! \qmlmethod void PdfScrollablePageView::goToPage(int page) Changes the view to the \a page, if possible. - \sa PdfNavigationStack::jump(), currentPage + \sa PdfPageNavigator::jump(), currentPage */ function goToPage(page) { - if (page === navigationStack.currentPage) + if (page === pageNavigator.currentPage) return goToLocation(page, Qt.point(0, 0), 0) } @@ -193,12 +158,12 @@ Flickable { Scrolls the view to the \a location on the \a page, if possible, and sets the \a zoom level. - \sa PdfNavigationStack::jump(), currentPage + \sa PdfPageNavigator::jump(), currentPage */ function goToLocation(page, location, zoom) { if (zoom > 0) root.renderScale = zoom - navigationStack.jump(page, location, zoom) + pageNavigator.jump(page, location, zoom) } // -------------------------------- @@ -209,8 +174,6 @@ Flickable { This property holds the ratio of pixels to points. The default is \c 1, meaning one point (1/72 of an inch) equals 1 logical pixel. - - \sa PdfPageImage::status */ property real renderScale: 1 @@ -221,8 +184,6 @@ Flickable { The default value is \c 0 degrees (that is, no rotation relative to the orientation of the pages as stored in the PDF file). - - \sa PdfPageImage::rotation */ property real pageRotation: 0 @@ -231,7 +192,7 @@ Flickable { This property holds the scaled width and height of the full-frame image. - \sa PdfPageImage::sourceSize + \sa {QtQuick::Image::sourceSize}{Image.sourceSize} */ property alias sourceSize: image.sourceSize @@ -254,7 +215,7 @@ Flickable { degrees, it will be scaled so that its width fits \a height. */ function scaleToWidth(width, height) { - const pagePointSize = document.pagePointSize(navigationStack.currentPage) + const pagePointSize = document.pagePointSize(pageNavigator.currentPage) root.renderScale = root.width / (paper.rot90 ? pagePointSize.height : pagePointSize.width) console.log(lcSPV, "scaling", pagePointSize, "to fit", root.width, "rotated?", paper.rot90, "scale", root.renderScale) root.contentX = 0 @@ -270,7 +231,7 @@ Flickable { it is first rotated to have a matching aspect ratio. */ function scaleToPage(width, height) { - const pagePointSize = document.pagePointSize(navigationStack.currentPage) + const pagePointSize = document.pagePointSize(pageNavigator.currentPage) root.renderScale = Math.min( root.width / (paper.rot90 ? pagePointSize.height : pagePointSize.width), root.height / (paper.rot90 ? pagePointSize.width : pagePointSize.height) ) @@ -295,8 +256,8 @@ Flickable { \qmlproperty string PdfScrollablePageView::searchString This property holds the search string that the user may choose to search - for. It is typically used in a binding to the - \l {QtQuick.Controls::TextField::text}{text} property of a TextField. + for. It is typically used in a binding to the \c text property of a + TextField. \sa searchModel */ @@ -331,7 +292,7 @@ Flickable { if (!active ) { const currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale, (root.contentY + root.height / 2) / root.renderScale) - navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale) + pageNavigator.update(pageNavigator.currentPage, currentLocation, root.renderScale) } } ScrollBar.horizontal: ScrollBar { @@ -339,47 +300,42 @@ Flickable { if (!active ) { const currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale, (root.contentY + root.height / 2) / root.renderScale) - navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale) + pageNavigator.update(pageNavigator.currentPage, currentLocation, root.renderScale) } } onRenderScaleChanged: { - image.sourceSize.width = document.pagePointSize(navigationStack.currentPage).width * - renderScale * Screen.devicePixelRatio - image.sourceSize.height = 0 paper.scale = 1 const currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale, (root.contentY + root.height / 2) / root.renderScale) - navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale) + pageNavigator.update(pageNavigator.currentPage, currentLocation, root.renderScale) } PdfSearchModel { id: searchModel document: root.document === undefined ? null : root.document - // TODO maybe avoid jumping if the result is already fully visible in the viewport - onCurrentResultBoundingRectChanged: root.goToLocation(currentPage, - Qt.point(currentResultBoundingRect.x, currentResultBoundingRect.y), 0) + onCurrentResultChanged: pageNavigator.jump(currentResultLink) } - PdfNavigationStack { - id: navigationStack - onJumped: function(page, location, zoom) { - root.renderScale = zoom - const dx = Math.max(0, location.x * root.renderScale - root.width / 2) - root.contentX - const dy = Math.max(0, location.y * root.renderScale - root.height / 2) - root.contentY + PdfPageNavigator { + id: pageNavigator + onJumped: function(current) { + root.renderScale = current.zoom + const dx = Math.max(0, current.location.x * root.renderScale - root.width / 2) - root.contentX + const dy = Math.max(0, current.location.y * root.renderScale - root.height / 2) - root.contentY // don't jump if location is in the viewport already, i.e. if the "error" between desired and actual contentX/Y is small if (Math.abs(dx) > root.width / 3) root.contentX += dx if (Math.abs(dy) > root.height / 3) root.contentY += dy - console.log(lcSPV, "going to zoom", zoom, "loc", location, - "on page", page, "ended up @", root.contentX + ", " + root.contentY) + console.log(lcSPV, "going to zoom", current.zoom, "loc", current.location, + "on page", current.page, "ended up @", root.contentX + ", " + root.contentY) } onCurrentPageChanged: searchModel.currentPage = currentPage property url documentSource: root.document.source onDocumentSourceChanged: { - navigationStack.clear() + pageNavigator.clear() root.resetScale() root.contentX = 0 root.contentY = 0 @@ -397,16 +353,22 @@ Flickable { height: rot90 ? image.width : image.height property real rotationModulus: Math.abs(root.pageRotation % 180) property bool rot90: rotationModulus > 45 && rotationModulus < 135 + property real minScale: 0.1 + property real maxScale: 10 PdfPageImage { id: image document: root.document - currentPage: navigationStack.currentPage + currentFrame: pageNavigator.currentPage asynchronous: true fillMode: Image.PreserveAspectFit rotation: root.pageRotation anchors.centerIn: parent - property real pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width + property real pageScale: image.paintedWidth / document.pagePointSize(pageNavigator.currentPage).width + width: document.pagePointSize(pageNavigator.currentPage).width * root.renderScale + height: document.pagePointSize(pageNavigator.currentPage).height * root.renderScale + sourceSize.width: width * Screen.devicePixelRatio + sourceSize.height: 0 Shape { anchors.fill: parent @@ -441,47 +403,21 @@ Flickable { model: PdfLinkModel { id: linkModel document: root.document - page: navigationStack.currentPage + page: pageNavigator.currentPage } - delegate: Shape { - required property rect rect - required property url url - required property int page - required property point location - required property real zoom - x: rect.x * image.pageScale - y: rect.y * image.pageScale - width: rect.width * image.pageScale - height: rect.height * image.pageScale + delegate: PdfLinkDelegate { + x: rectangle.x * image.pageScale + y: rectangle.y * image.pageScale + width: rectangle.width * image.pageScale + height: rectangle.height * image.pageScale visible: image.status === Image.Ready - ShapePath { - strokeWidth: style.linkUnderscoreStrokeWidth - strokeColor: style.linkUnderscoreColor - strokeStyle: style.linkUnderscoreStrokeStyle - dashPattern: style.linkUnderscoreDashPattern - startX: 0; startY: height - PathLine { x: width; y: height } - } - HoverHandler { - id: linkHH - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: { - if (page >= 0) - navigationStack.jump(page, Qt.point(0, 0), root.renderScale) + onTapped: + (link) => { + if (link.page >= 0) + pageNavigator.jump(link.page, link.location, link.zoom) else Qt.openUrlExternally(url) } - } - ToolTip { - visible: linkHH.hovered - delay: 1000 - text: page >= 0 ? - ("page " + (page + 1) + - " location " + location.x.toFixed(1) + ", " + location.y.toFixed(1) + - " zoom " + zoom) : url - } } } DragHandler { @@ -507,21 +443,20 @@ Flickable { id: selection anchors.fill: parent document: root.document - page: navigationStack.currentPage + page: pageNavigator.currentPage renderScale: image.pageScale == 0 ? 1.0 : image.pageScale - fromPoint: textSelectionDrag.centroid.pressPosition - toPoint: textSelectionDrag.centroid.position + from: textSelectionDrag.centroid.pressPosition + to: textSelectionDrag.centroid.position hold: !textSelectionDrag.active && !mouseClickHandler.pressed focus: true } PinchHandler { id: pinch - minimumScale: 0.1 - maximumScale: root.renderScale < 4 ? 2 : 1 + minimumScale: paper.minScale / root.renderScale + maximumScale: Math.max(1, paper.maxScale / root.renderScale) minimumRotation: 0 maximumRotation: 0 - enabled: image.sourceSize.width < 5000 onActiveChanged: if (!active) { const centroidInPoints = Qt.point(pinch.centroid.position.x / root.renderScale, @@ -539,7 +474,7 @@ Flickable { paper.y = 0 root.contentX = centroidOnPage.x - centroidInFlickable.x root.contentY = centroidOnPage.y - centroidInFlickable.y - root.renderScale *= ratio // onRenderScaleChanged calls navigationStack.update() so we don't need to here + root.renderScale *= ratio // onRenderScaleChanged calls pageNavigator.update() so we don't need to here console.log(lcSPV, "contentX/Y adjusted to", root.contentX.toFixed(2), root.contentY.toFixed(2)) } else { paper.x = 0 |