diff options
Diffstat (limited to 'src/pdf/quick/qml/PdfMultiPageView.qml')
-rw-r--r-- | src/pdf/quick/qml/PdfMultiPageView.qml | 171 |
1 files changed, 113 insertions, 58 deletions
diff --git a/src/pdf/quick/qml/PdfMultiPageView.qml b/src/pdf/quick/qml/PdfMultiPageView.qml index 70bb5454f..71485c214 100644 --- a/src/pdf/quick/qml/PdfMultiPageView.qml +++ b/src/pdf/quick/qml/PdfMultiPageView.qml @@ -48,15 +48,15 @@ Item { property string selectedText function selectAll() { - var currentItem = tableView.itemAtPos(0, tableView.contentY + root.height / 2) - if (currentItem !== null) + var currentItem = tableHelper.itemAtCell(tableHelper.cellAtPos(root.width / 2, root.height / 2)) + if (currentItem) currentItem.selection.selectAll() } function copySelectionToClipboard() { - var currentItem = tableView.itemAtPos(0, tableView.contentY + root.height / 2) + var currentItem = tableHelper.itemAtCell(tableHelper.cellAtPos(root.width / 2, root.height / 2)) if (debug) console.log("currentItem", currentItem, "sel", currentItem.selection.text) - if (currentItem !== null) + if (currentItem) currentItem.selection.copyToClipboard() } @@ -69,14 +69,19 @@ Item { function goToPage(page) { if (page === navigationStack.currentPage) return - goToLocation(page, Qt.point(0, 0), 0) + goToLocation(page, Qt.point(-1, -1), 0) } function goToLocation(page, location, zoom) { - if (zoom > 0) + if (zoom > 0) { + navigationStack.jumping = true // don't call navigationStack.update() because we will push() instead root.renderScale = zoom - navigationStack.push(page, location, zoom) - searchModel.currentPage = page + tableView.forceLayout() // but do ensure that the table layout is correct before we try to jump + navigationStack.jumping = false + } + navigationStack.push(page, location, zoom) // actually jump } + property vector2d jumpLocationMargin: Qt.vector2d(10, 10) // px from top-left corner + property int currentPageRenderingStatus: Image.Null // page scaling property real renderScale: 1 @@ -115,29 +120,27 @@ Item { id: tableView anchors.fill: parent anchors.leftMargin: 2 - model: root.document === undefined ? 0 : root.document.pageCount + model: modelInUse && root.document !== undefined ? root.document.pageCount : 0 + // workaround to make TableView do scheduleRebuildTable(RebuildOption::All) in cases when forceLayout() doesn't + property bool modelInUse: true + function rebuild() { + modelInUse = false + modelInUse = true + } + // end workaround rowSpacing: 6 property real rotationNorm: Math.round((360 + (root.pageRotation % 360)) % 360) property bool rot90: rotationNorm == 90 || rotationNorm == 270 onRot90Changed: forceLayout() property size firstPagePointSize: document === undefined ? Qt.size(0, 0) : document.pagePointSize(0) - contentWidth: document === undefined ? 0 : (rot90 ? document.maxPageHeight : document.maxPageWidth) * root.renderScale + vscroll.width + 2 - // workaround for missing function (see https://codereview.qt-project.org/c/qt/qtdeclarative/+/248464) - function itemAtPos(x, y, includeSpacing) { - // we don't care about x (assume col 0), and assume includeSpacing is true - var ret = null - for (var i = 0; i < contentItem.children.length; ++i) { - var child = contentItem.children[i]; - if (root.debug) - console.log(child, "@y", child.y) - if (child.y < y && (!ret || child.y > ret.y)) - ret = child - } - if (root.debug && ret !== null) - console.log("given y", y, "found", ret, "@", ret.y) - return ret // the delegate with the largest y that is less than the given y - } + property real pageHolderWidth: Math.max(root.width, document === undefined ? 0 : + (rot90 ? document.maxPageHeight : document.maxPageWidth) * root.renderScale) + contentWidth: document === undefined ? 0 : pageHolderWidth + vscroll.width + 2 rowHeightProvider: function(row) { return (rot90 ? document.pagePointSize(row).width : document.pagePointSize(row).height) * root.renderScale } + TableViewExtra { + id: tableHelper + tableView: tableView + } delegate: Rectangle { id: pageHolder color: root.debug ? "beige" : "transparent" @@ -147,11 +150,8 @@ Item { rotation: -90; text: pageHolder.width.toFixed(1) + "x" + pageHolder.height.toFixed(1) + "\n" + image.width.toFixed(1) + "x" + image.height.toFixed(1) } - implicitWidth: Math.max(root.width, (tableView.rot90 ? document.maxPageHeight : document.maxPageWidth) * root.renderScale) + implicitWidth: tableView.pageHolderWidth implicitHeight: tableView.rot90 ? image.width : image.height - onImplicitWidthChanged: tableView.forceLayout() - objectName: "page " + index - property int delegateIndex: row // expose the context property for JS outside of the delegate property alias selection: selection Rectangle { id: paper @@ -177,6 +177,10 @@ Item { paper.scale = 1 searchHighlights.update() } + onStatusChanged: { + if (index === navigationStack.currentPage) + root.currentPageRenderingStatus = status + } } Shape { anchors.fill: parent @@ -276,9 +280,17 @@ Item { target: null } TapHandler { - id: tapHandler + id: mouseClickHandler acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus } + TapHandler { + id: touchTapHandler + acceptedDevices: PointerDevice.TouchScreen + onTapped: { + selection.clear() + selection.forceActiveFocus() + } + } Repeater { model: PdfLinkModel { id: linkModel @@ -290,6 +302,7 @@ Item { y: rect.y * paper.pageScale width: rect.width * paper.pageScale height: rect.height * paper.pageScale + visible: image.status === Image.Ready ShapePath { strokeWidth: style.linkUnderscoreStrokeWidth strokeColor: style.linkUnderscoreColor @@ -320,17 +333,18 @@ Item { } } } - } - PdfSelection { - id: selection - document: root.document - page: image.currentFrame - fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / paper.pageScale, - textSelectionDrag.centroid.pressPosition.y / paper.pageScale) - toPoint: Qt.point(textSelectionDrag.centroid.position.x / paper.pageScale, - textSelectionDrag.centroid.position.y / paper.pageScale) - hold: !textSelectionDrag.active && !tapHandler.pressed - onTextChanged: root.selectedText = text + PdfSelection { + id: selection + anchors.fill: parent + document: root.document + page: image.currentFrame + renderScale: image.renderScale + fromPoint: textSelectionDrag.centroid.pressPosition + toPoint: textSelectionDrag.centroid.position + hold: !textSelectionDrag.active && !mouseClickHandler.pressed + onTextChanged: root.selectedText = text + focus: true + } } } ScrollBar.vertical: ScrollBar { @@ -338,42 +352,83 @@ Item { property bool moved: false onPositionChanged: moved = true onActiveChanged: { - var currentItem = tableView.itemAtPos(0, tableView.contentY + root.height / 2) - var currentPage = currentItem.delegateIndex - var currentLocation = Qt.point((tableView.contentX - currentItem.x + root.width / 2) / root.renderScale, - (tableView.contentY - currentItem.y + root.height / 2) / root.renderScale) + var cell = tableHelper.cellAtPos(root.width / 2, root.height / 2) + var currentItem = tableHelper.itemAtCell(cell) + var currentLocation = Qt.point(0, 0) + if (currentItem) { // maybe the delegate wasn't loaded yet + currentLocation = Qt.point((tableView.contentX - currentItem.x + jumpLocationMargin.x) / root.renderScale, + (tableView.contentY - currentItem.y + jumpLocationMargin.y) / root.renderScale) + } if (active) { moved = false - navigationStack.push(currentPage, currentLocation, root.renderScale) + // emitJumped false to avoid interrupting a pinch if TableView thinks it should scroll at the same time + navigationStack.push(cell.y, currentLocation, root.renderScale, false) } else if (moved) { - navigationStack.update(currentPage, currentLocation, root.renderScale) + navigationStack.update(cell.y, currentLocation, root.renderScale) } } } ScrollBar.horizontal: ScrollBar { } } onRenderScaleChanged: { - tableView.forceLayout() - var currentItem = tableView.itemAtPos(tableView.contentX + root.width / 2, tableView.contentY + root.height / 2) - if (currentItem !== undefined) - navigationStack.update(currentItem.delegateIndex, Qt.point(currentItem.x / renderScale, currentItem.y / renderScale), renderScale) + // if navigationStack.jumped changes the scale, don't turn around and update the stack again; + // and don't force layout either, because positionViewAtCell() will do that + if (navigationStack.jumping) + return + // make TableView rebuild from scratch, because otherwise it doesn't know the delegates are changing size + tableView.rebuild() + var cell = tableHelper.cellAtPos(root.width / 2, root.height / 2) + var currentItem = tableHelper.itemAtCell(cell) + if (currentItem) { + var currentLocation = Qt.point((tableView.contentX - currentItem.x + jumpLocationMargin.x) / root.renderScale, + (tableView.contentY - currentItem.y + jumpLocationMargin.y) / root.renderScale) + navigationStack.update(cell.y, currentLocation, renderScale) + } } PdfNavigationStack { id: navigationStack + property bool jumping: false + property int previousPage: 0 onJumped: { + jumping = true root.renderScale = zoom - tableView.contentX = Math.max(0, location.x - root.width / 2) * root.renderScale - tableView.contentY = tableView.originY + root.document.heightSumBeforePage(page, tableView.rowSpacing / root.renderScale) * root.renderScale - if (root.debug) { - console.log("going to page", page, - "@y", root.document.heightSumBeforePage(page, tableView.rowSpacing / root.renderScale) * root.renderScale, - "ended up @", tableView.contentY, "originY is", tableView.originY) + if (location.y < 0) { + // invalid to indicate that a specific location was not needed, + // so attempt to position the new page just as the current page is + var currentYOffset = 0 + var previousPageDelegate = tableHelper.itemAtCell(0, previousPage) + if (previousPageDelegate) + currentYOffset = tableView.contentY - previousPageDelegate.y + tableHelper.positionViewAtRow(page, Qt.AlignTop, currentYOffset) + if (root.debug) { + console.log("going from page", previousPage, "to", page, "offset", currentYOffset, + "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1)) + } + } else { + // jump to a page and position the given location relative to the top-left corner of the viewport + var pageSize = root.document.pagePointSize(page) + pageSize.width *= root.renderScale + pageSize.height *= root.renderScale + var xOffsetLimit = Math.max(0, pageSize.width - root.width) / 2 + var offset = Qt.point(Math.max(-xOffsetLimit, Math.min(xOffsetLimit, + location.x * root.renderScale - jumpLocationMargin.x)), + Math.max(0, location.y * root.renderScale - jumpLocationMargin.y)) + tableHelper.positionViewAtCell(0, page, Qt.AlignLeft | Qt.AlignTop, offset) + if (root.debug) { + console.log("going to zoom", zoom, "loc", location, "on page", page, + "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1)) + } } + jumping = false + previousPage = page } + onCurrentPageChanged: searchModel.currentPage = currentPage } PdfSearchModel { id: searchModel document: root.document === undefined ? null : root.document - onCurrentPageChanged: if (currentPage != navigationStack.currentPage) root.goToPage(currentPage) + // 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) } } |