Warning, /graphics/spectacle/src/Gui/VideoCaptureOverlay.qml is written in an unsupported language. File is not indexed.

0001 /* SPDX-FileCopyrightText: 2023 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 MouseArea {
0013     id: root
0014     readonly property rect viewportRect: G.mapFromPlatformRect(screenToFollow.geometry,
0015                                                                screenToFollow.devicePixelRatio)
0016     focus: true
0017     acceptedButtons: Qt.LeftButton | Qt.RightButton
0018     hoverEnabled: true
0019     LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
0020     LayoutMirroring.childrenInherit: true
0021     anchors.fill: parent
0022     enabled: !VideoPlatform.isRecording
0023 
0024     component Overlay: Rectangle {
0025         color: Settings.useLightMaskColor ? "white" : "black"
0026         opacity: if (VideoPlatform.isRecording) {
0027             return 0
0028         } else if (Selection.empty) {
0029             return 0.25
0030         } else {
0031             return 0.5
0032         }
0033         LayoutMirroring.enabled: false
0034         Behavior on opacity {
0035             NumberAnimation {
0036                 duration: Kirigami.Units.longDuration
0037                 easing.type: Easing.OutCubic
0038             }
0039         }
0040     }
0041     Overlay { // top / full overlay when nothing selected
0042         id: topOverlay
0043         anchors.top: parent.top
0044         anchors.left: parent.left
0045         anchors.right: parent.right
0046         anchors.bottom: selectionRectangle.visible ? selectionRectangle.top : parent.bottom
0047     }
0048     Overlay { // bottom
0049         id: bottomOverlay
0050         anchors.left: parent.left
0051         anchors.top: selectionRectangle.visible ? selectionRectangle.bottom : undefined
0052         anchors.right: parent.right
0053         anchors.bottom: parent.bottom
0054         visible: selectionRectangle.visible && height > 0
0055     }
0056     Overlay { // left
0057         anchors {
0058             left: topOverlay.left
0059             top: topOverlay.bottom
0060             right: selectionRectangle.visible ? selectionRectangle.left : undefined
0061             bottom: bottomOverlay.top
0062         }
0063         visible: selectionRectangle.visible && height > 0 && width > 0
0064     }
0065     Overlay { // right
0066         anchors {
0067             left: selectionRectangle.visible ? selectionRectangle.right : undefined
0068             top: topOverlay.bottom
0069             right: topOverlay.right
0070             bottom: bottomOverlay.top
0071         }
0072         visible: selectionRectangle.visible && height > 0 && width > 0
0073     }
0074 
0075     Rectangle {
0076         id: selectionRectangle
0077         color: "transparent"
0078         border.color: palette.active.highlight
0079         border.width: contextWindow.dprRound(1)
0080         visible: !Selection.empty
0081             && !VideoPlatform.isRecording
0082             && G.rectIntersects(Qt.rect(x,y,width,height), Qt.rect(0,0,parent.width, parent.height))
0083         x: Selection.x - border.width - root.viewportRect.x
0084         y: Selection.y - border.width - root.viewportRect.y
0085         width: Selection.width + border.width * 2
0086         height: Selection.height + border.width * 2
0087 
0088         LayoutMirroring.enabled: false
0089         LayoutMirroring.childrenInherit: true
0090     }
0091 
0092     SelectionBackground {
0093         visible: VideoPlatform.isRecording
0094         strokeWidth: selectionRectangle.border.width
0095         // We need to be a bit careful about staying out of the recorded area
0096         x: dprRound(Math.floor(Selection.x - strokeWidth - root.viewportRect.x))
0097         y: dprRound(Math.floor(Selection.y - strokeWidth - root.viewportRect.y))
0098         width: dprRound(Math.ceil(Selection.width + strokeWidth * 2))
0099         height: dprRound(Math.ceil(Selection.height + strokeWidth * 2))
0100     }
0101 
0102     Item {
0103         x: -root.viewportRect.x
0104         y: -root.viewportRect.y
0105         enabled: selectionRectangle.enabled
0106         visible: !VideoPlatform.isRecording
0107         component Handle: Rectangle {
0108             visible: enabled && selectionRectangle.visible
0109                 && SelectionEditor.dragLocation === SelectionEditor.None
0110                 && G.rectIntersects(Qt.rect(x,y,width,height), root.viewportRect)
0111             color: selectionRectangle.color
0112             width: Kirigami.Units.gridUnit
0113             height: width
0114             radius: width / 2
0115         }
0116 
0117         Handle {
0118             x: SelectionEditor.handlesRect.x
0119             y: SelectionEditor.handlesRect.y
0120         }
0121         Handle {
0122             x: SelectionEditor.handlesRect.x
0123             y: SelectionEditor.handlesRect.y + SelectionEditor.handlesRect.height/2 - height/2
0124         }
0125         Handle {
0126             x: SelectionEditor.handlesRect.x
0127             y: SelectionEditor.handlesRect.y + SelectionEditor.handlesRect.height - height
0128         }
0129         Handle {
0130             x: SelectionEditor.handlesRect.x + SelectionEditor.handlesRect.width/2 - width/2
0131             y: SelectionEditor.handlesRect.y
0132         }
0133         Handle {
0134             x: SelectionEditor.handlesRect.x + SelectionEditor.handlesRect.width/2 - width/2
0135             y: SelectionEditor.handlesRect.y + SelectionEditor.handlesRect.height - height
0136         }
0137         Handle {
0138             x: SelectionEditor.handlesRect.x + SelectionEditor.handlesRect.width - width
0139             y: SelectionEditor.handlesRect.y + SelectionEditor.handlesRect.height/2 - height/2
0140         }
0141         Handle {
0142             x: SelectionEditor.handlesRect.x + SelectionEditor.handlesRect.width - width
0143             y: SelectionEditor.handlesRect.y
0144         }
0145         Handle {
0146             x: SelectionEditor.handlesRect.x + SelectionEditor.handlesRect.width - width
0147             y: SelectionEditor.handlesRect.y + SelectionEditor.handlesRect.height - height
0148         }
0149     }
0150 
0151     Item { // separate item because it needs to be above the stuff defined above
0152         visible: !VideoPlatform.isRecording
0153         width: SelectionEditor.screensRect.width
0154         height: SelectionEditor.screensRect.height
0155         x: -root.viewportRect.x
0156         y: -root.viewportRect.y
0157 
0158         // Size ToolTip
0159         SizeLabel {
0160             id: ssToolTip
0161             readonly property int valignment: {
0162                 if (Selection.empty) {
0163                     return Qt.AlignVCenter
0164                 }
0165                 const margin = Kirigami.Units.mediumSpacing * 2
0166                 const w = width + margin
0167                 const h = height + margin
0168                 if (SelectionEditor.handlesRect.top >= h) {
0169                     return Qt.AlignTop
0170                 } else if (SelectionEditor.screensRect.height - SelectionEditor.handlesRect.bottom >= h) {
0171                     return Qt.AlignBottom
0172                 } else {
0173                     // At the bottom of the inside of the selection rect.
0174                     return Qt.AlignBaseline
0175                 }
0176             }
0177             readonly property bool normallyVisible: !Selection.empty
0178             Binding on x {
0179                 value: contextWindow.dprRound(Selection.horizontalCenter - ssToolTip.width / 2)
0180                 when: ssToolTip.normallyVisible
0181                 restoreMode: Binding.RestoreNone
0182             }
0183             Binding on y {
0184                 value: {
0185                     let v = 0
0186                     if (ssToolTip.valignment & Qt.AlignBaseline) {
0187                         v = Math.min(Selection.bottom, SelectionEditor.handlesRect.bottom - Kirigami.Units.gridUnit)
0188                             - ssToolTip.height - Kirigami.Units.mediumSpacing * 2
0189                     } else if (ssToolTip.valignment & Qt.AlignTop) {
0190                         v = SelectionEditor.handlesRect.top
0191                             - ssToolTip.height - Kirigami.Units.mediumSpacing * 2
0192                     } else if (ssToolTip.valignment & Qt.AlignBottom) {
0193                         v = SelectionEditor.handlesRect.bottom + Kirigami.Units.mediumSpacing * 2
0194                     } else {
0195                         v = (root.height - ssToolTip.height) / 2 - parent.y
0196                     }
0197                     return contextWindow.dprRound(v)
0198                 }
0199                 when: ssToolTip.normallyVisible
0200                 restoreMode: Binding.RestoreNone
0201             }
0202             visible: opacity > 0
0203             opacity: ssToolTip.normallyVisible
0204                 && G.rectIntersects(Qt.rect(x,y,width,height), root.viewportRect)
0205             Behavior on opacity {
0206                 NumberAnimation {
0207                     duration: Kirigami.Units.longDuration
0208                     easing.type: Easing.OutCubic
0209                 }
0210             }
0211             size: G.rawSize(Selection.size, SelectionEditor.devicePixelRatio) // TODO: real pixel size on wayland
0212             padding: Kirigami.Units.mediumSpacing * 2
0213             topPadding: padding - QmlUtils.fontMetrics.descent
0214             bottomPadding: topPadding
0215             background: FloatingBackground {
0216                 implicitWidth: Math.ceil(parent.contentWidth) + parent.leftPadding + parent.rightPadding
0217                 implicitHeight: Math.ceil(parent.contentHeight) + parent.topPadding + parent.bottomPadding
0218                 color: Qt.rgba(parent.palette.window.r,
0219                             parent.palette.window.g,
0220                             parent.palette.window.b, 0.85)
0221                 border.color: Qt.rgba(parent.palette.windowText.r,
0222                                     parent.palette.windowText.g,
0223                                     parent.palette.windowText.b, 0.2)
0224                 border.width: contextWindow.dprRound(1)
0225             }
0226         }
0227     }
0228 }