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 }