2015-09-24 15:47:26 +00:00
|
|
|
/*
|
2021-05-24 07:25:56 +00:00
|
|
|
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
|
|
|
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2015-09-24 15:47:26 +00:00
|
|
|
|
2022-01-26 13:26:47 +00:00
|
|
|
import QtQuick 2.15
|
|
|
|
import QtQuick.Controls 2.15 as QQC2
|
2015-09-24 15:47:26 +00:00
|
|
|
import org.kde.okular 2.0
|
|
|
|
import "./private"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A touchscreen optimized view for a document
|
|
|
|
*
|
|
|
|
* It supports changing pages by a swipe gesture, pinch zoom
|
|
|
|
* and flicking to scroll around
|
|
|
|
*/
|
2019-06-10 18:58:54 +00:00
|
|
|
QQC2.ScrollView {
|
2015-09-24 15:47:26 +00:00
|
|
|
id: root
|
2015-09-24 18:34:00 +00:00
|
|
|
property DocumentItem document
|
|
|
|
property PageItem page: mouseArea.currPageDelegate.pageItem
|
2015-12-01 16:28:49 +00:00
|
|
|
signal clicked
|
2016-05-13 14:17:26 +00:00
|
|
|
|
|
|
|
//NOTE: on some themes it tries to set the flickable to interactive
|
|
|
|
//but we need it always non interactive as we need to manage
|
|
|
|
//dragging by ourselves
|
|
|
|
Component.onCompleted: flick.interactive = false
|
2015-09-24 15:47:26 +00:00
|
|
|
Flickable {
|
|
|
|
id: flick
|
2016-05-13 14:17:26 +00:00
|
|
|
interactive: false
|
|
|
|
onWidthChanged: resizeTimer.restart()
|
|
|
|
onHeightChanged: resizeTimer.restart()
|
2015-09-24 18:34:00 +00:00
|
|
|
|
2015-09-24 15:47:26 +00:00
|
|
|
Component.onCompleted: {
|
|
|
|
flick.contentWidth = flick.width
|
|
|
|
flick.contentHeight = flick.width / mouseArea.currPageDelegate.pageRatio
|
|
|
|
}
|
2015-09-24 18:34:00 +00:00
|
|
|
Connections {
|
|
|
|
target: root.document
|
2021-11-24 16:58:52 +00:00
|
|
|
function onUrlChanged() {
|
|
|
|
resizeTimer.restart()
|
|
|
|
}
|
2015-09-24 18:34:00 +00:00
|
|
|
}
|
|
|
|
Timer {
|
|
|
|
id: resizeTimer
|
|
|
|
interval: 250
|
|
|
|
onTriggered: {
|
|
|
|
flick.contentWidth = flick.width
|
|
|
|
flick.contentHeight = flick.width / mouseArea.currPageDelegate.pageRatio
|
|
|
|
}
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PinchArea {
|
|
|
|
width: flick.contentWidth
|
|
|
|
height: flick.contentHeight
|
|
|
|
|
|
|
|
property real initialWidth
|
|
|
|
property real initialHeight
|
|
|
|
|
|
|
|
onPinchStarted: {
|
|
|
|
initialWidth = mouseArea.currPageDelegate.implicitWidth * mouseArea.currPageDelegate.scaleFactor
|
|
|
|
initialHeight = mouseArea.currPageDelegate.implicitHeight * mouseArea.currPageDelegate.scaleFactor
|
|
|
|
}
|
|
|
|
|
|
|
|
onPinchUpdated: {
|
|
|
|
// adjust content pos due to drag
|
|
|
|
flick.contentX += pinch.previousCenter.x - pinch.center.x
|
|
|
|
flick.contentY += pinch.previousCenter.y - pinch.center.y
|
|
|
|
|
|
|
|
// resize content
|
2015-09-25 14:33:46 +00:00
|
|
|
//use the scale property during pinch, for speed reasons
|
|
|
|
if (initialHeight * pinch.scale > flick.height &&
|
|
|
|
initialHeight * pinch.scale < flick.height * 3) {
|
|
|
|
mouseArea.scale = pinch.scale;
|
|
|
|
}
|
2016-05-13 14:36:06 +00:00
|
|
|
resizeTimer.stop();
|
2015-09-25 14:33:46 +00:00
|
|
|
flick.returnToBounds();
|
|
|
|
}
|
|
|
|
onPinchFinished: {
|
|
|
|
flick.resizeContent(Math.max(flick.width+1, initialWidth * mouseArea.scale), Math.max(flick.height, initialHeight * mouseArea.scale), pinch.center);
|
|
|
|
mouseArea.scale = 1;
|
|
|
|
|
2018-04-25 16:08:03 +00:00
|
|
|
resizeTimer.stop()
|
2015-09-24 15:47:26 +00:00
|
|
|
flick.returnToBounds();
|
|
|
|
}
|
|
|
|
MouseArea {
|
|
|
|
id: mouseArea
|
|
|
|
width: parent.width
|
|
|
|
height: parent.height
|
|
|
|
|
|
|
|
property real oldMouseX
|
|
|
|
property real oldMouseY
|
2016-05-13 15:01:17 +00:00
|
|
|
property real startMouseX
|
|
|
|
property real startMouseY
|
2015-09-24 15:47:26 +00:00
|
|
|
property bool incrementing: true
|
|
|
|
property Item currPageDelegate: page1
|
|
|
|
property Item prevPageDelegate: page2
|
|
|
|
property Item nextPageDelegate: page3
|
|
|
|
|
|
|
|
onPressed: {
|
|
|
|
var pos = mapToItem(flick, mouse.x, mouse.y);
|
2016-05-13 15:01:17 +00:00
|
|
|
startMouseX = oldMouseX = pos.x;
|
|
|
|
startMouseY = oldMouseY = pos.y;
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
onPositionChanged: {
|
|
|
|
var pos = mapToItem(flick, mouse.x, mouse.y);
|
|
|
|
|
|
|
|
flick.contentY = Math.max(0, Math.min(flick.contentHeight - flick.height, flick.contentY - (pos.y - oldMouseY)));
|
|
|
|
|
2016-05-13 15:01:17 +00:00
|
|
|
if ((pos.x - oldMouseX > 0 && flick.atXBeginning) ||
|
|
|
|
(pos.x - oldMouseX < 0 && flick.atXEnd)) {
|
|
|
|
currPageDelegate.x += pos.x - oldMouseX;
|
|
|
|
mouseArea.incrementing = currPageDelegate.x <= 0;
|
|
|
|
} else {
|
|
|
|
flick.contentX = Math.max(0, Math.min(flick.contentWidth - flick.width, flick.contentX - (pos.x - oldMouseX)));
|
|
|
|
}
|
|
|
|
|
2015-09-24 15:47:26 +00:00
|
|
|
oldMouseX = pos.x;
|
|
|
|
oldMouseY = pos.y;
|
|
|
|
}
|
|
|
|
onReleased: {
|
2015-09-24 18:34:00 +00:00
|
|
|
if (root.document.currentPage > 0 &&
|
2015-09-24 15:47:26 +00:00
|
|
|
currPageDelegate.x > width/6) {
|
|
|
|
switchAnimation.running = true;
|
2015-09-24 18:34:00 +00:00
|
|
|
} else if (root.document.currentPage < document.pageCount-1 &&
|
2015-09-24 15:47:26 +00:00
|
|
|
currPageDelegate.x < -width/6) {
|
|
|
|
switchAnimation.running = true;
|
|
|
|
} else {
|
|
|
|
resetAnim.running = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onCanceled: {
|
|
|
|
resetAnim.running = true;
|
|
|
|
}
|
|
|
|
onDoubleClicked: {
|
|
|
|
flick.contentWidth = flick.width
|
|
|
|
flick.contentHeight = flick.width / mouseArea.currPageDelegate.pageRatio
|
|
|
|
}
|
2015-12-01 16:28:49 +00:00
|
|
|
onClicked: {
|
2016-05-13 15:01:17 +00:00
|
|
|
var pos = mapToItem(flick, mouse.x, mouse.y);
|
|
|
|
if (Math.abs(startMouseX - pos.x) < 20 &&
|
|
|
|
Math.abs(startMouseY - pos.y) < 20) {
|
2015-12-01 16:28:49 +00:00
|
|
|
root.clicked();
|
|
|
|
}
|
|
|
|
}
|
2016-05-13 14:36:06 +00:00
|
|
|
onWheel: {
|
|
|
|
if (wheel.modifiers & Qt.ControlModifier) {
|
2016-05-13 15:19:48 +00:00
|
|
|
//generate factors between 0.8 and 1.2
|
|
|
|
var factor = (((wheel.angleDelta.y / 120)+1) / 5 )+ 0.8;
|
|
|
|
|
|
|
|
var newWidth = flick.contentWidth * factor;
|
|
|
|
var newHeight = flick.contentHeight * factor;
|
|
|
|
|
|
|
|
if (newWidth < flick.width || newHeight < flick.height ||
|
|
|
|
newHeight > flick.height * 3) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
flick.resizeContent(newWidth, newHeight, Qt.point(wheel.x, wheel.y));
|
|
|
|
flick.returnToBounds();
|
2016-05-13 14:36:06 +00:00
|
|
|
resizeTimer.stop();
|
2016-05-13 15:01:17 +00:00
|
|
|
} else {
|
|
|
|
flick.contentY = Math.min(flick.contentHeight-flick.height, Math.max(0, flick.contentY - wheel.angleDelta.y));
|
2016-05-13 14:36:06 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-24 15:47:26 +00:00
|
|
|
|
|
|
|
PageView {
|
|
|
|
id: page1
|
2015-09-24 18:34:00 +00:00
|
|
|
document: root.document
|
2015-09-24 15:47:26 +00:00
|
|
|
z: 2
|
|
|
|
}
|
|
|
|
PageView {
|
|
|
|
id: page2
|
2015-09-24 18:34:00 +00:00
|
|
|
document: root.document
|
2015-09-24 15:47:26 +00:00
|
|
|
z: 1
|
|
|
|
}
|
|
|
|
PageView {
|
|
|
|
id: page3
|
2015-09-24 18:34:00 +00:00
|
|
|
document: root.document
|
2015-09-24 15:47:26 +00:00
|
|
|
z: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Binding {
|
|
|
|
target: mouseArea.currPageDelegate
|
|
|
|
property: "pageNumber"
|
2015-09-24 18:34:00 +00:00
|
|
|
value: root.document.currentPage
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
Binding {
|
|
|
|
target: mouseArea.currPageDelegate
|
|
|
|
property: "visible"
|
|
|
|
value: true
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding {
|
|
|
|
target: mouseArea.prevPageDelegate
|
|
|
|
property: "pageNumber"
|
2015-09-24 18:34:00 +00:00
|
|
|
value: root.document.currentPage - 1
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
Binding {
|
|
|
|
target: mouseArea.prevPageDelegate
|
|
|
|
property: "visible"
|
2015-09-24 18:34:00 +00:00
|
|
|
value: !mouseArea.incrementing && root.document.currentPage > 0
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Binding {
|
|
|
|
target: mouseArea.nextPageDelegate
|
|
|
|
property: "pageNumber"
|
2015-09-24 18:34:00 +00:00
|
|
|
value: root.document.currentPage + 1
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
Binding {
|
|
|
|
target: mouseArea.nextPageDelegate
|
|
|
|
property: "visible"
|
2015-09-24 18:34:00 +00:00
|
|
|
value: mouseArea.incrementing && root.document.currentPage < document.pageCount-1
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SequentialAnimation {
|
|
|
|
id: switchAnimation
|
2016-05-13 16:07:37 +00:00
|
|
|
ParallelAnimation {
|
|
|
|
NumberAnimation {
|
|
|
|
target: flick
|
|
|
|
properties: "contentY"
|
|
|
|
to: 0
|
|
|
|
easing.type: Easing.InQuad
|
|
|
|
//hardcoded number, we would need units from kirigami
|
|
|
|
//which cannot depend from here
|
|
|
|
duration: 250
|
|
|
|
}
|
|
|
|
NumberAnimation {
|
|
|
|
target: mouseArea.currPageDelegate
|
|
|
|
properties: "x"
|
|
|
|
to: mouseArea.incrementing ? -mouseArea.currPageDelegate.width : mouseArea.currPageDelegate.width
|
|
|
|
easing.type: Easing.InQuad
|
|
|
|
//hardcoded number, we would need units from kirigami
|
|
|
|
//which cannot depend from here
|
|
|
|
duration: 250
|
|
|
|
}
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
ScriptAction {
|
|
|
|
script: {
|
|
|
|
mouseArea.currPageDelegate.z = 0;
|
|
|
|
mouseArea.prevPageDelegate.z = 1;
|
|
|
|
mouseArea.nextPageDelegate.z = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ScriptAction {
|
|
|
|
script: {
|
|
|
|
mouseArea.currPageDelegate.x = 0
|
|
|
|
var oldCur = mouseArea.currPageDelegate;
|
|
|
|
var oldPrev = mouseArea.prevPageDelegate;
|
|
|
|
var oldNext = mouseArea.nextPageDelegate;
|
|
|
|
|
|
|
|
if (mouseArea.incrementing) {
|
2015-09-24 18:34:00 +00:00
|
|
|
root.document.currentPage++;
|
2015-09-24 15:47:26 +00:00
|
|
|
mouseArea.currPageDelegate = oldNext;
|
|
|
|
mouseArea.prevPageDelegate = oldCur;
|
|
|
|
mouseArea. nextPageDelegate = oldPrev;
|
|
|
|
} else {
|
2015-09-24 18:34:00 +00:00
|
|
|
root.document.currentPage--;
|
2015-09-24 15:47:26 +00:00
|
|
|
mouseArea.currPageDelegate = oldPrev;
|
2018-05-13 15:57:22 +00:00
|
|
|
mouseArea.nextPageDelegate = oldCur;
|
|
|
|
mouseArea.prevPageDelegate = oldNext;
|
2015-09-24 15:47:26 +00:00
|
|
|
}
|
|
|
|
mouseArea.currPageDelegate.z = 2;
|
|
|
|
mouseArea.prevPageDelegate.z = 1;
|
|
|
|
mouseArea.nextPageDelegate.z = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NumberAnimation {
|
|
|
|
id: resetAnim
|
|
|
|
target: mouseArea.currPageDelegate
|
|
|
|
properties: "x"
|
|
|
|
to: 0
|
|
|
|
easing.type: Easing.InQuad
|
|
|
|
duration: 250
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-13 14:17:26 +00:00
|
|
|
}
|