Warning, /office/calligra/gemini/qml/WordsDocumentPage.qml is written in an unsupported language. File is not indexed.

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2014 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  *  This program is free software; you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation; either version 2 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program; if not, write to the Free Software
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0017  */
0018 
0019 import QtQuick 2.11
0020 import org.kde.kirigami 2.7 as Kirigami
0021 import "components"
0022 import org.kde.calligra 1.0 as Calligra
0023 
0024 Item {
0025     id: base;
0026     signal canvasInteractionStarted();
0027     property alias document: wordsDocument;
0028     property alias textEditor: wordsDocument.textEditor;
0029     property QtObject canvas: wordsCanvas;
0030     property alias source: wordsDocument.source;
0031     property alias navigateMode: controllerFlickable.enabled;
0032     property double toolbarOpacity: base.state === "readermode" ? 0.3 : 1;
0033     Calligra.Document {
0034         id: wordsDocument;
0035         onStatusChanged: {
0036             if(status == Calligra.DocumentStatus.Loading) {
0037                 baseLoadingDialog.visible = true;
0038             }
0039             else if(status == Calligra.DocumentStatus.Loaded) {
0040                 console.debug("doc and part: " + wordsDocument.document + " " + wordsDocument.part);
0041                 mainWindow.setDocAndPart(wordsDocument.document, wordsDocument.part);
0042                 baseLoadingDialog.hideMe();
0043             }
0044         }
0045         onCurrentIndexChanged: navigatorListView.positionViewAtIndex(currentIndex - 1, ListView.Center);
0046     }
0047     Calligra.ContentsModel {
0048         id: wordsContentModel;
0049         document: wordsDocument;
0050         useToC: false;
0051         thumbnailSize: Qt.size(Settings.theme.adjustedPixel(280), Settings.theme.adjustedPixel(360));
0052     }
0053     onNavigateModeChanged: {
0054         if(navigateMode === true) {
0055             // This means we've just changed back from having edited stuff.
0056             // Consequently we want to deselect all selections. Tell the canvas about that.
0057             wordsCanvas.deselectEverything();
0058             toolManager.requestToolChange("PageToolFactory_ID");
0059         }
0060     }
0061     Connections {
0062         target: Constants;
0063         onGridSizeChanged: {
0064             var newState = (Constants.IsLandscape ? "" : "readermode");
0065             if(base.state !== newState) {
0066                 base.state = newState;
0067             }
0068         }
0069     }
0070     onWidthChanged: {
0071         if(base.state === "readermode") {
0072             d.zoomToFit();
0073         }
0074     }
0075     onHeightChanged: {
0076         if(base.state === "readermode") {
0077             d.zoomToFit();
0078         }
0079     }
0080     function scrollToEnd() {
0081         controllerFlickable.contentY = controllerFlickable.contentHeight - controllerFlickable.height;
0082     }
0083     Rectangle {
0084         anchors.fill: parent;
0085         color: "#e8e9ea";
0086     }
0087 
0088     Flickable {
0089         id: bgScrollArea;
0090         anchors.fill: parent;
0091         contentHeight: wordsDocument.documentSize.height;
0092         interactive: base.state !== "readermode";
0093         boundsBehavior: controllerFlickable.boundsBehavior;
0094         Item {
0095             width: parent.width;
0096             height: wordsDocument.documentSize.height;
0097             MouseArea {
0098                 anchors.fill: parent;
0099                 property int oldX: 0
0100                 property int oldY: 0
0101                 property int swipeDistance: Settings.theme.adjustedPixel(10);
0102                 onPressed: {
0103                     oldX = mouseX;
0104                     oldY = mouseY;
0105                 }
0106                 onReleased: {
0107                     base.canvasInteractionStarted();
0108                     controllerItem.pageChanging = true;
0109                     var xDiff = oldX - mouseX;
0110                     var yDiff = oldY - mouseY;
0111                     // Don't react if the swipe distance is too small
0112                     if(Math.abs(xDiff) < swipeDistance && Math.abs(yDiff) < swipeDistance) {
0113                         if(Math.abs(xDiff) > Settings.theme.adjustedPixel(2) || Math.abs(yDiff) > Settings.theme.adjustedPixel(2)) {
0114                             // If the swipe distance is sort of big (2 pixels on a 1080p screen)
0115                             // we can assume the finger has moved some distance and should be ignored
0116                             // as not-a-tap.
0117                             controllerItem.pageChanging = false;
0118                             return;
0119                         }
0120                         // This might be done in onClick, but that then eats the events, which is not useful
0121                         // for reader mode we'll accept clicks here, to simulate an e-reader style navigation mode
0122                         if(mouse.x < width / 2) {
0123                             controllerFlickable.pageUp();
0124                         }
0125                         else if(mouse.x > width / 2) {
0126                             controllerFlickable.pageDown();
0127                         }
0128                     }
0129                     else if(base.state === "readermode") {
0130                         if ( Math.abs(xDiff) > Math.abs(yDiff) ) {
0131                             if( oldX > mouseX) {
0132                                 // left
0133                                 controllerFlickable.pageDown();
0134                             } else {
0135                                 // right
0136                                 controllerFlickable.pageUp()
0137                             }
0138                         } else {
0139                             if( oldY > mouseY) {
0140                                 // up
0141                                 controllerFlickable.pageDown();
0142                             }
0143                             else {
0144                                 // down
0145                                 controllerFlickable.pageUp();
0146                             }
0147                         }
0148                     }
0149                     controllerItem.pageChanging = false;
0150                 }
0151             }
0152         }
0153     }
0154     Binding {
0155         target: controllerFlickable;
0156         property: "contentY";
0157         value: bgScrollArea.contentY;
0158         when: controllerFlickable.verticalVelocity === 0;
0159     }
0160     Binding {
0161         target: bgScrollArea;
0162         property: "contentY";
0163         value: controllerFlickable.contentY;
0164         when: bgScrollArea.verticalVelocity === 0;
0165     }
0166     Item {
0167         id: wordsContentItem;
0168         anchors {
0169             top: parent.top;
0170             bottom: parent.bottom;
0171             horizontalCenter: parent.horizontalCenter;
0172         }
0173         width: Math.min(wordsDocument.documentSize.width, base.width);
0174 
0175         Calligra.View {
0176             id: wordsCanvas;
0177             anchors.fill: parent;
0178             document: wordsDocument;
0179         }
0180 
0181         Flickable {
0182             id: controllerFlickable;
0183             anchors {
0184                 top: parent.top;
0185                 topMargin: Settings.theme.adjustedPixel(86);
0186                 right: parent.right;
0187                 bottom: enabled ? parent.bottom : parent.top;
0188                 bottomMargin: enabled ? 0 : -Settings.theme.adjustedPixel(86);
0189             }
0190             width: Math.min(parent.width, base.width - navigatorHandle.width);
0191             interactive: base.state !== "readermode";
0192             property int fastVelocity: Settings.theme.adjustedPixel(1000);
0193             onVerticalVelocityChanged: {
0194                 if(Math.abs(verticalVelocity) > fastVelocity && !controllerItem.pageChanging) {
0195                     d.showThings();
0196                 }
0197                 else {
0198                     d.hideThings();
0199                 }
0200             }
0201 
0202             boundsBehavior: wordsDocument.documentSize.width < base.width ? Flickable.StopAtBounds : Flickable.DragAndOvershootBounds;
0203 
0204             function pageUp() {
0205                 if(base.state === "readermode") {
0206                     if(wordsDocument.currentIndex === 1) {
0207                         controllerFlickable.contentY = wordsCanvas.pagePosition(wordsDocument.indexCount) + 1;
0208                     }
0209                     else {
0210                         controllerFlickable.contentY = wordsCanvas.pagePosition(wordsDocument.currentIndex - 1) + 1;
0211                     }
0212                 }
0213                 else {
0214                     controllerFlickable.contentY = Math.max(0, controllerFlickable.contentY - controllerFlickable.height + (Constants.GridHeight * 1.5));
0215                 }
0216             }
0217             function pageDown() {
0218                 if(base.state === "readermode") {
0219                     controllerFlickable.contentY = wordsCanvas.pagePosition(wordsDocument.currentIndex + 1) + 1;
0220                 }
0221                 else {
0222                     controllerFlickable.contentY = Math.min(controllerFlickable.contentHeight - controllerFlickable.height, controllerFlickable.contentY + controllerFlickable.height - (Constants.GridHeight * 1.5));
0223                 }
0224             }
0225 
0226             Image {
0227                 height: Settings.theme.adjustedPixel(40);
0228                 width: Settings.theme.adjustedPixel(40);
0229                 source: Settings.theme.icon("intel-Words-Handle-cursor");
0230                 opacity: wordsCanvas.hasSelection ? 1 : 0;
0231                 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0232                 x: wordsCanvas.hasSelection ? wordsCanvas.selectionStartPos.x - width / 2 : 0;
0233                 y: wordsCanvas.hasSelection ? wordsCanvas.selectionStartPos.y - (height - 4) : 0;
0234                 Rectangle {
0235                     anchors {
0236                         top: parent.bottom;
0237                         horizontalCenter: parent.horizontalCenter;
0238                     }
0239                     height: wordsCanvas.hasSelection ? wordsCanvas.selectionStartPos.height - 4 : 0;
0240                     width: 4;
0241                     color: "#009bcd";
0242                 }
0243             }
0244             Image {
0245                 height: Settings.theme.adjustedPixel(40);
0246                 width: Settings.theme.adjustedPixel(40);
0247                 source: Settings.theme.icon("intel-Words-Handle-cursor");
0248                 opacity: wordsCanvas.hasSelection ? 1 : 0;
0249                 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0250                 x: wordsCanvas.hasSelection ? wordsCanvas.selectionEndPos.x - width / 2 : 0;
0251                 y: wordsCanvas.hasSelection ? wordsCanvas.selectionEndPos.y + (wordsCanvas.selectionEndPos.height - 4) : 0;
0252                 Rectangle {
0253                     anchors {
0254                         bottom: parent.top;
0255                         horizontalCenter: parent.horizontalCenter;
0256                     }
0257                     height: wordsCanvas.hasSelection ? wordsCanvas.selectionEndPos.height - 4 : 0;
0258                     width: 4;
0259                     color: "#009bcd";
0260                 }
0261             }
0262 
0263             PinchArea {
0264                 x: controllerFlickable.contentX;
0265                 y: controllerFlickable.contentY;
0266                 height: controllerFlickable.height;
0267                 width: controllerFlickable.width;
0268 
0269                 enabled: base.state !== "readermode";
0270 
0271                 onPinchStarted: {
0272                     base.canvasInteractionStarted();
0273                 }
0274                 onPinchUpdated: {
0275                     var newCenter = mapToItem( controllerFlickable, pinch.center.x, pinch.center.y );
0276                     controllerItem.zoomAroundPoint(pinch.scale - pinch.previousScale, newCenter.x, newCenter.y );
0277                 }
0278                 onPinchFinished: {
0279                     controllerFlickable.returnToBounds();
0280                 }
0281 
0282                 MouseArea {
0283                     anchors.fill: parent;
0284                     onDoubleClicked: {
0285                         if(base.state === "readermode") {
0286                             // for reader mode, we don't accept editing input
0287                             base.canvasInteractionStarted();
0288                             return;
0289                         }
0290                         toolManager.requestToolChange("TextToolFactory_ID");
0291                         base.navigateMode = false;
0292                         base.canvasInteractionStarted();
0293                     }
0294 
0295                     property int oldX: 0
0296                     property int oldY: 0
0297                     property int swipeDistance: Settings.theme.adjustedPixel(10);
0298                     onPressed: {
0299                         oldX = mouseX;
0300                         oldY = mouseY;
0301                     }
0302                     onReleased: {
0303                         base.canvasInteractionStarted();
0304                         if(base.state !== "readermode") {
0305                             return;
0306                         }
0307                         var xDiff = oldX - mouseX;
0308                         var yDiff = oldY - mouseY;
0309                         controllerItem.pageChanging = true;
0310                         // Don't react if the swipe distance is too small
0311                         if(Math.abs(xDiff) < swipeDistance && Math.abs(yDiff) < swipeDistance) {
0312                             if(Math.abs(xDiff) > Settings.theme.adjustedPixel(2) || Math.abs(yDiff) > Settings.theme.adjustedPixel(2)) {
0313                                 // If the swipe distance is sort of big (2 pixels on a 1080p screen)
0314                                 // we can assume the finger has moved some distance and should be ignored
0315                                 // as not-a-tap.
0316                                 controllerItem.pageChanging = false;
0317                                 return;
0318                             }
0319                             // This might be done in onClick, but that then eats the events, which is not useful
0320                             // for reader mode we'll accept clicks here, to simulate an e-reader style navigation mode
0321                             if(mouse.x < width / 4) {
0322                                 controllerFlickable.pageUp();
0323                             }
0324                             else if(mouse.x > width * 3 / 4) {
0325                                 controllerFlickable.pageDown();
0326                             }
0327                         }
0328                         else if( Math.abs(xDiff) > Math.abs(yDiff) ) {
0329                             if( oldX > mouseX) {
0330                                 // left
0331                                 controllerFlickable.pageDown();
0332                             } else {
0333                                 // right
0334                                 controllerFlickable.pageUp();
0335                             }
0336                         } else {
0337                             if( oldY > mouseY) {
0338                                 // up
0339                                 controllerFlickable.pageDown();
0340                             }
0341                             else {
0342                                 // down
0343                                 controllerFlickable.pageUp();
0344                             }
0345                         }
0346                         controllerItem.pageChanging = false;
0347                     }
0348                 }
0349             }
0350 
0351             Calligra.ViewController {
0352                 id: controllerItem;
0353                 objectName: "controllerItem";
0354                 view: wordsCanvas;
0355                 flickable: controllerFlickable;
0356                 property bool pageChanging: false;
0357                 zoom: 1.0;
0358                 minimumZoom: 0.5;
0359             }
0360         }
0361     }
0362 
0363     QtObject {
0364         id: d;
0365         property double previouszoom: 0;
0366         function restoreZoom() {
0367             controllerItem.zoom = previouszoom;
0368             previouszoom = 0;
0369         }
0370         function zoomToFit() {
0371             if(previouszoom === 0) {
0372                 previouszoom = controllerItem.zoom;
0373             }
0374             controllerItem.zoomToPage();
0375         }
0376         function showThings() {
0377             if(base.state === "readermode") {
0378                 return;
0379             }
0380             base.state = "sidebarShown";
0381             pageNumber.opacity = 1;
0382             hideTimer.stop();
0383             hidePageNumTimer.stop();
0384         }
0385         function hideThings() {
0386             if(navigatorSidebar.containsMouse) {
0387                 return;
0388             }
0389             hideTimer.start();
0390             hidePageNumTimer.start();
0391         }
0392     }
0393     Timer {
0394         id: hidePageNumTimer;
0395         running: false;
0396         repeat: false;
0397         interval: 500;
0398         onTriggered: {
0399             pageNumber.opacity = 0;
0400         }
0401     }
0402     Timer {
0403         id: hideTimer;
0404         running: false;
0405         repeat: false;
0406         interval: 2000;
0407         onTriggered: {
0408             if(base.state === "readermode") {
0409                 return;
0410             }
0411             base.state = "";
0412         }
0413     }
0414     states: [
0415         State {
0416             name: "sidebarShown"
0417             AnchorChanges { target: navigatorSidebar; anchors.left: parent.left; anchors.right: undefined; }
0418         },
0419         State {
0420             name: "readermode"
0421             PropertyChanges { target: navigatorSidebar; opacity: 0; }
0422         }
0423         ]
0424     transitions: [ Transition {
0425             AnchorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad; }
0426         },
0427         Transition {
0428             to: "readermode";
0429             ScriptAction {
0430                 script: {
0431                     d.zoomToFit();
0432                     controllerFlickable.contentY = wordsCanvas.pagePosition(wordsDocument.currentIndex) + 1;
0433                                         base.canvasInteractionStarted();
0434                     if(mainWindow.maximized) {
0435                         mainWindow.fullScreen = true;
0436                     }
0437                 }
0438             }
0439         },
0440         Transition {
0441             from: "readermode";
0442             ScriptAction {
0443                 script: {
0444                     d.restoreZoom();
0445                                         base.canvasInteractionStarted();
0446                     mainWindow.fullScreen = false;
0447                 }
0448             }
0449         }
0450         ]
0451     Item {
0452         id: navigatorSidebar;
0453         property alias containsMouse: listViewMouseArea.containsMouse;
0454         anchors {
0455             top: parent.top;
0456             right: parent.left;
0457             bottom: parent.bottom;
0458             topMargin: Settings.theme.adjustedPixel(40) + Constants.ToolbarHeight;
0459             bottomMargin: Settings.theme.adjustedPixel(40);
0460         }
0461         width: Settings.theme.adjustedPixel(190);
0462         BorderImage {
0463             anchors {
0464                 fill: parent;
0465                 topMargin: -28;
0466                 leftMargin: -36;
0467                 rightMargin: -36;
0468                 bottomMargin: -44;
0469             }
0470             border { left: 36; top: 28; right: 36; bottom: 44; }
0471             horizontalTileMode: BorderImage.Stretch;
0472             verticalTileMode: BorderImage.Stretch;
0473             source: Settings.theme.image("drop-shadows.png");
0474             opacity: (base.state === "sidebarShown") ? 1 : 0;
0475             Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0476             BorderImage {
0477                 anchors {
0478                     fill: parent;
0479                     topMargin: 28;
0480                     leftMargin: 36;
0481                     rightMargin: 36;
0482                     bottomMargin: 44;
0483                 }
0484                 border { left: 8; top: 8; right: 8; bottom: 8; }
0485                 horizontalTileMode: BorderImage.Stretch;
0486                 verticalTileMode: BorderImage.Stretch;
0487                 source: Settings.theme.image("drop-corners.png");
0488             }
0489         }
0490         Item {
0491             id: navigatorHandle;
0492             anchors {
0493                 left: parent.right;
0494                 verticalCenter: parent.verticalCenter;
0495             }
0496             height: Constants.GridHeight * 2;
0497             width: Kirigami.Units.largeSpacing * 3;
0498             clip: true;
0499             Rectangle {
0500                 anchors {
0501                     fill: parent;
0502                     leftMargin: -(radius + 1);
0503                 }
0504                 radius: Kirigami.Units.largeSpacing;
0505                 color: "#55595e";
0506                 opacity: 0.5;
0507             }
0508             Rectangle {
0509                 anchors {
0510                     top: parent.top;
0511                     bottom: parent.bottom;
0512                     margins: Kirigami.Units.largeSpacing;
0513                     horizontalCenter: parent.horizontalCenter;
0514                 }
0515                 width: 4;
0516                 radius: 2;
0517                 color: "white";
0518                 opacity: 0.5;
0519             }
0520             MouseArea {
0521                 anchors.fill: parent;
0522                 onClicked: {
0523                     if(base.state === "sidebarShown" && base.state !== "readermode") {
0524                         base.state = "";
0525                         pageNumber.opacity = 0;
0526                     }
0527                     else {
0528                         d.showThings();
0529                     }
0530                     base.canvasInteractionStarted();
0531                 }
0532             }
0533         }
0534         Rectangle {
0535             anchors {
0536                 fill: parent;
0537                 leftMargin: -Kirigami.Units.largeSpacing + 1;
0538             }
0539             radius: Kirigami.Units.largeSpacing;
0540             color: "#55595e";
0541             opacity: 0.5;
0542             Rectangle {
0543                 anchors.fill: parent;
0544                 radius: parent.radius;
0545                 color: "transparent";
0546                 border.width: 1;
0547                 border.color: "black";
0548                 opacity: 0.6;
0549             }
0550         }
0551         MouseArea {
0552             id: listViewMouseArea;
0553             anchors.fill: parent;
0554             hoverEnabled: true;
0555         }
0556         Button {
0557             anchors {
0558                 top: parent.top;
0559                 left: parent.left;
0560                 right: parent.right;
0561             }
0562             height: Constants.GridHeight / 2;
0563             image: Settings.theme.icon("Arrow-ScrollUp-1");
0564             imageMargin: 2;
0565             Rectangle {
0566                 anchors {
0567                     left: parent.left;
0568                     right: parent.right;
0569                     rightMargin: 1;
0570                     bottom: parent.bottom;
0571                 }
0572                 height: 1;
0573                 color: "black";
0574                 opacity: 0.3;
0575             }
0576         }
0577         Button {
0578             anchors {
0579                 left: parent.left;
0580                 right: parent.right;
0581                 bottom: parent.bottom;
0582             }
0583             height: Constants.GridHeight / 2;
0584             image: Settings.theme.icon("Arrow-ScrollDown-1");
0585             imageMargin: 2;
0586             Rectangle {
0587                 anchors {
0588                     top: parent.top;
0589                     left: parent.left;
0590                     right: parent.right;
0591                     rightMargin: 1;
0592                 }
0593                 height: 1;
0594                 color: "black";
0595                 opacity: 0.3;
0596             }
0597         }
0598         ListView {
0599             id: navigatorListView;
0600             anchors {
0601                 fill: parent;
0602                 topMargin: Constants.GridHeight / 2;
0603                 bottomMargin: Constants.GridHeight / 2;
0604                 rightMargin: 1;
0605             }
0606             clip: true;
0607             model: wordsContentModel;
0608             delegate: Item {
0609                 width: Settings.theme.adjustedPixel(190);
0610                 height: Settings.theme.adjustedPixel(190);
0611                 Calligra.ImageDataItem {
0612                     id: navigatorThumbnail;
0613                     anchors {
0614                         top: parent.top;
0615                         right: parent.right;
0616                         bottom: parent.bottom;
0617                         margins: Settings.theme.adjustedPixel(5);
0618                     }
0619                     width: Settings.theme.adjustedPixel(140);
0620                     data: model.thumbnail;
0621                 }
0622                 Rectangle {
0623                     anchors.fill: navigatorThumbnail;
0624                     color: "transparent";
0625                     border.width: 1;
0626                     border.color: "black";
0627                     opacity: 0.1;
0628                 }
0629                 Label {
0630                     anchors {
0631                         left: parent.left;
0632                         leftMargin: Kirigami.Units.largeSpacing;
0633                         verticalCenter: parent.verticalCenter;
0634                     }
0635                     text: index + 1;
0636                     font: Settings.theme.font("applicationSemi");
0637                     color: "#c1cdd1";
0638                 }
0639                 MouseArea {
0640                     anchors.fill: parent;
0641                     onClicked: {
0642                         wordsDocument.currentIndex = model.contentIndex;
0643 //                         controllerFlickable.contentY = wordsCanvas.pagePosition(index + 1) + 1;
0644                         base.canvasInteractionStarted();
0645                     }
0646                 }
0647             }
0648         }
0649         Item {
0650             anchors.fill: navigatorListView;
0651             clip: true;
0652             Item {
0653                 id: visualiserContainer;
0654                 property double scale: height / controllerFlickable.contentHeight;
0655                 width: parent.width;
0656                 height: (wordsDocument === null) ? 0 : wordsDocument.indexCount * Settings.theme.adjustedPixel(190);
0657                 x: 0;
0658                 y: -navigatorListView.contentY;
0659                 Rectangle {
0660                     x: 0;
0661                     y: controllerFlickable.contentY * visualiserContainer.scale;
0662                     width: Settings.theme.adjustedPixel(190);
0663                     height: visualiserContainer.scale * controllerFlickable.height;
0664                     color: "#00adf5"
0665                     opacity: 0.4;
0666                 }
0667             }
0668         }
0669     }
0670     Item {
0671         id: pageNumber;
0672         anchors {
0673             right: parent.right;
0674             bottom: parent.bottom;
0675             margins: Kirigami.Units.largeSpacing;
0676         }
0677         opacity: 0;
0678         Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0679         height: Constants.GridHeight / 2;
0680         width: Constants.GridWidth;
0681         Rectangle {
0682             anchors.fill: parent;
0683             radius: Kirigami.Units.largeSpacing;
0684             color: Settings.theme.color("components/overlay/base");
0685             opacity: 0.7;
0686         }
0687         Label {
0688             anchors.centerIn: parent;
0689             color: Settings.theme.color("components/overlay/text");
0690             text: (wordsDocument === null) ? 0 : wordsDocument.currentIndex + " of " + wordsDocument.indexCount;
0691         }
0692     }
0693     Item {
0694         id: zoomLevel;
0695         anchors {
0696             right: parent.right;
0697             bottom: (pageNumber.opacity > 0) ? pageNumber.top : parent.bottom;
0698             margins: Kirigami.Units.largeSpacing;
0699         }
0700         opacity: 0;
0701         Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0702         height: Constants.GridHeight / 2;
0703         width: Constants.GridWidth;
0704         Rectangle {
0705             anchors.fill: parent;
0706             radius: Kirigami.Units.largeSpacing;
0707             color: Settings.theme.color("components/overlay/base");
0708             opacity: 0.7;
0709         }
0710         Timer {
0711             id: hideZoomLevelTimer;
0712             repeat: false; running: false; interval: 1000;
0713             onTriggered: zoomLevel.opacity = 0;
0714         }
0715         Label {
0716             anchors.centerIn: parent;
0717             color: Settings.theme.color("components/overlay/text");
0718             text: wordsCanvas.zoomAction ? (wordsCanvas.zoomAction.effectiveZoom * 100).toFixed(2) + "%" : "";
0719             onTextChanged: {
0720                 zoomLevel.opacity = 1;
0721                 hideZoomLevelTimer.start();
0722             }
0723         }
0724     }
0725 }