Warning, /graphics/spectacle/src/Gui/ImageView.qml is written in an unsupported language. File is not indexed.
0001 /* SPDX-FileCopyrightText: 2022 Noah Davis <noahadvs@gmail.com> 0002 * SPDX-License-Identifier: LGPL-2.0-or-later 0003 */ 0004 0005 import QtQuick 0006 import QtQuick.Window 0007 import QtQuick.Layouts 0008 import QtQuick.Controls as QQC 0009 import org.kde.kirigami as Kirigami 0010 import org.kde.spectacle.private 0011 0012 import "Annotations" 0013 0014 /** 0015 * This page is shown when a screenshot has been taken 0016 * or accepted from the rectangular region capture mode. 0017 * 0018 * - There is a `contextWindow` context property that can be used to 0019 * access the instance of the ViewerWindow. 0020 */ 0021 EmptyPage { 0022 id: root 0023 focus: true 0024 0025 // Used in ViewerWindow::setMode() 0026 readonly property real minimumWidth: Math.max( 0027 header.implicitWidth, 0028 annotationsToolBar.implicitWidth + separator.implicitWidth + footerLoader.implicitWidth, 0029 captureOptionsLoader.implicitWidth + 480 // leave some room for content if necessary 0030 ) 0031 readonly property real minimumHeight: header.implicitHeight 0032 + Math.max(annotationsToolBar.implicitHeight, 0033 footerLoader.implicitHeight, 0034 captureOptionsLoader.implicitHeight) 0035 0036 property var inlineMessageData: {} 0037 property string inlineMessageSource: "" 0038 onInlineMessageDataChanged: { 0039 if (inlineMessageSource) { 0040 inlineMessageLoader.setSource(inlineMessageSource, inlineMessageData) 0041 inlineMessageLoader.state = "active" 0042 } 0043 } 0044 0045 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft 0046 LayoutMirroring.childrenInherit: true 0047 0048 header: QQC.ToolBar { 0049 id: header 0050 contentItem: MainToolBarContents { 0051 id: mainToolBarContents 0052 showNewScreenshotButton: false 0053 showOptionsMenu: false 0054 showUndoRedo: contextWindow.annotating 0055 displayMode: QQC.AbstractButton.TextBesideIcon 0056 } 0057 } 0058 0059 // Needed for scrolling via keyboard input 0060 Keys.priority: Keys.AfterItem 0061 Keys.enabled: !SpectacleCore.videoMode && contentLoader.item !== null 0062 Keys.forwardTo: contentLoader.item 0063 0064 AnimatedLoader { // parent is contentItem 0065 id: inlineMessageLoader 0066 anchors.left: annotationsToolBar.right 0067 anchors.right: captureOptionsLoader.left 0068 anchors.top: parent.top 0069 anchors.margins: visible ? Kirigami.Units.mediumSpacing : 0 0070 state: "inactive" 0071 height: visible ? implicitHeight : 0 0072 Behavior on height { 0073 NumberAnimation { 0074 duration: inlineMessageLoader.animationDuration 0075 easing.type: Easing.OutCubic 0076 } 0077 } 0078 } 0079 0080 QQC.Pane { // parent is contentItem 0081 id: annotationsToolBar 0082 anchors.top: parent.top 0083 anchors.bottom: parent.bottom 0084 anchors.right: parent.left 0085 visible: false 0086 leftPadding: header.leftPadding 0087 rightPadding: header.rightPadding 0088 topPadding: header.topPadding 0089 bottomPadding: header.bottomPadding 0090 contentItem: AnnotationsToolBarContents { 0091 id: annotationsToolBarContents 0092 displayMode: QQC.AbstractButton.IconOnly 0093 flow: Grid.TopToBottom 0094 showUndoRedo: false 0095 rememberToolType: true 0096 } 0097 background: Rectangle { 0098 color: parent.palette.window 0099 } 0100 } 0101 0102 Kirigami.Separator { // parent is contentItem 0103 id: separator 0104 visible: false 0105 anchors.left: annotationsToolBar.right 0106 anchors.top: parent.top 0107 anchors.bottom: parent.bottom 0108 } 0109 0110 Loader { // parent is contentItem 0111 id: contentLoader 0112 anchors { 0113 left: footerLoader.left 0114 right: captureOptionsLoader.left 0115 top: inlineMessageLoader.bottom 0116 bottom: footerLoader.top 0117 topMargin: inlineMessageLoader.active ? Kirigami.Units.mediumSpacing : 0 0118 } 0119 source: SpectacleCore.videoMode ? "RecordingView.qml" : "ScreenshotView.qml" 0120 } 0121 0122 Loader { // parent is contentItem 0123 id: captureOptionsLoader 0124 visible: true 0125 active: visible 0126 anchors { 0127 top: parent.top 0128 bottom: parent.bottom 0129 right: parent.right 0130 } 0131 width: Math.max(implicitWidth, Kirigami.Units.gridUnit * 15) 0132 sourceComponent: QQC.Page { 0133 0134 leftPadding: Kirigami.Units.mediumSpacing * 2 0135 + (!mirrored ? sideBarSeparator.implicitWidth : 0) 0136 rightPadding: Kirigami.Units.mediumSpacing * 2 0137 + (mirrored ? sideBarSeparator.implicitWidth : 0) 0138 topPadding: Kirigami.Units.mediumSpacing * 2 0139 bottomPadding: Kirigami.Units.mediumSpacing * 2 0140 0141 header: QQC.TabBar { 0142 id: tabBar 0143 visible: VideoPlatform.supportedRecordingModes 0144 currentIndex: 0 0145 QQC.TabButton { 0146 width: tabBar.width / tabBar.count 0147 text: i18n("Screenshot") 0148 } 0149 QQC.TabButton { 0150 width: tabBar.width / tabBar.count 0151 text: i18n("Recording") 0152 } 0153 } 0154 0155 contentItem: Loader { 0156 source: switch (tabBar.currentIndex) { 0157 case 0: return "CaptureOptions.qml" 0158 case 1: return "RecordOptions.qml" 0159 default: return "" 0160 } 0161 } 0162 0163 background: Rectangle { 0164 color: Kirigami.Theme.backgroundColor 0165 Kirigami.Separator { 0166 id: sideBarSeparator 0167 anchors { 0168 left: parent.left 0169 top: parent.top 0170 bottom: parent.bottom 0171 } 0172 } 0173 } 0174 } 0175 } 0176 0177 Loader { 0178 id: footerLoader 0179 anchors.left: separator.right 0180 anchors.right: captureOptionsLoader.left 0181 anchors.top: parent.bottom 0182 visible: false 0183 active: visible 0184 sourceComponent: QQC.ToolBar { // parent is contentItem 0185 position: QQC.ToolBar.Footer 0186 contentHeight: QmlUtils.iconTextButtonHeight 0187 contentItem: RowLayout { 0188 spacing: Kirigami.Units.mediumSpacing 0189 AnimatedLoader { 0190 id: loader 0191 Layout.fillWidth: true 0192 active: opacity > 0 0193 visible: true 0194 state: if (AnnotationDocument.tool.options !== AnnotationTool.NoOptions 0195 || (AnnotationDocument.tool.type === AnnotationTool.SelectTool 0196 && AnnotationDocument.selectedItem.options !== AnnotationTool.NoOptions) 0197 ) { 0198 return "active" 0199 } else { 0200 return "inactive" 0201 } 0202 source: "AnnotationOptionsToolBarContents.qml" 0203 } 0204 QQC.ToolSeparator { 0205 Layout.fillHeight: true 0206 visible: loader.implicitWidth 0207 + implicitWidth 0208 + zoomLabel.implicitWidth 0209 + zoomEditor.implicitWidth 0210 + parent.spacing * 3 >= parent.width 0211 } 0212 QQC.Label { 0213 id: zoomLabel 0214 text: i18n("Zoom:") 0215 } 0216 QQC.SpinBox { 0217 id: zoomEditor 0218 from: contentLoader.item.minZoom * 100 0219 to: contentLoader.item.maxZoom * 100 0220 stepSize: 25 0221 value: contentLoader.item.effectiveZoom * 100 0222 textFromValue: (value, locale) => { 0223 return Number(Math.round(value)).toLocaleString(locale, 'f', 0) + locale.percent 0224 } 0225 valueFromText: (text, locale) => { 0226 return Number.fromLocaleString(locale, text.replace(/\D/g,'')) 0227 } 0228 QQC.ToolTip.text: i18n("Image Zoom") 0229 QQC.ToolTip.visible: hovered 0230 QQC.ToolTip.delay: Kirigami.Units.toolTipDelay 0231 Binding { 0232 target: zoomEditor.contentItem 0233 property: "horizontalAlignment" 0234 value: Text.AlignRight 0235 restoreMode: Binding.RestoreNone 0236 } 0237 onValueModified: contentLoader.item.zoomToPercent(Math.round(value) / 100) 0238 } 0239 } 0240 } 0241 } 0242 0243 Shortcut { 0244 enabled: contextWindow.annotating && !SpectacleCore.videoMode && contentLoader.item !== null 0245 sequences: [StandardKey.ZoomIn] 0246 onActivated: contentLoader.item.zoomIn() 0247 } 0248 Shortcut { 0249 enabled: contextWindow.annotating && !SpectacleCore.videoMode && contentLoader.item !== null 0250 sequences: [StandardKey.ZoomOut] 0251 onActivated: contentLoader.item.zoomOut() 0252 } 0253 // FIXME: This shortcut only exists here because spectacle interprets "Ctrl+Shift+," 0254 // as "Ctrl+Shift+<" for some reason unless we use a QML Shortcut. 0255 Shortcut { 0256 sequences: [StandardKey.Preferences] 0257 onActivated: contextWindow.showPreferencesDialog() 0258 } 0259 0260 state: "normal" 0261 states: [ 0262 State { 0263 name: "annotating" 0264 when: contextWindow.annotating 0265 && !SpectacleCore.videoMode 0266 && contentLoader.item !== null 0267 AnchorChanges { 0268 target: annotationsToolBar 0269 anchors.left: parent.left 0270 anchors.right: undefined 0271 } 0272 AnchorChanges { 0273 target: footerLoader 0274 anchors.bottom: parent.bottom 0275 anchors.top: undefined 0276 } 0277 AnchorChanges { 0278 target: captureOptionsLoader 0279 anchors.left: parent.right 0280 anchors.right: undefined 0281 } 0282 }, 0283 State { 0284 name: "normal" 0285 when: !contextWindow.annotating 0286 || SpectacleCore.videoMode 0287 || contentLoader.item === null 0288 AnchorChanges { 0289 target: annotationsToolBar 0290 anchors.left: undefined 0291 anchors.right: parent.left 0292 } 0293 AnchorChanges { 0294 target: footerLoader 0295 anchors.bottom: undefined 0296 anchors.top: parent.bottom 0297 } 0298 AnchorChanges { 0299 target: captureOptionsLoader 0300 anchors.left: undefined 0301 anchors.right: parent.right 0302 } 0303 } 0304 ] 0305 transitions: [ 0306 Transition { 0307 to: "annotating" 0308 SequentialAnimation { 0309 PropertyAction { 0310 targets: [annotationsToolBar, separator, footerLoader] 0311 property: "visible" 0312 value: true 0313 } 0314 AnchorAnimation { 0315 duration: Kirigami.Units.longDuration 0316 easing.type: Easing.OutCubic 0317 } 0318 PropertyAction { 0319 targets: captureOptionsLoader 0320 property: "visible" 0321 value: false 0322 } 0323 } 0324 }, 0325 Transition { 0326 to: "normal" 0327 SequentialAnimation { 0328 PropertyAction { 0329 targets: captureOptionsLoader 0330 property: "visible" 0331 value: true 0332 } 0333 AnchorAnimation { 0334 duration: Kirigami.Units.longDuration 0335 easing.type: Easing.OutCubic 0336 } 0337 PropertyAction { 0338 targets: [annotationsToolBar, separator, footerLoader] 0339 property: "visible" 0340 value: false 0341 } 0342 } 0343 } 0344 ] 0345 }