kdenliveclipmonitor.qml 17.5 KB
Newer Older
1
import QtQuick.Controls 2.4
2 3
import QtQuick.Window 2.2
import Kdenlive.Controls 1.0
4
import QtQuick 2.11
5
import com.enums 1.0
6 7 8

Item {
    id: root
9
    objectName: "root"
10

11 12
    SystemPalette { id: activePalette }

13 14
    // default size, but scalable by user
    height: 300; width: 400
15
    property string markerText
16
    property int itemType: 0
17
    property point profile: controller.profile
18
    property double zoom
19 20
    property double scalex
    property double scaley
21
    // Zoombar properties
22
    // The start position of the zoomed area, between 0 and 1
23
    property double zoomStart: 0
24
    // The zoom factor (between 0 and 1). 0.5 means 2x zoom
25
    property double zoomFactor: 1
26
    // The pixel height of zoom bar, used to offset markers info
27
    property int zoomOffset: 0
28
    property bool showZoomBar: false
29 30 31 32 33 34 35
    property bool dropped: false
    property string fps: '-'
    property bool showMarkers: false
    property bool showTimecode: false
    property bool showFps: false
    property bool showSafezone: false
    property bool showAudiothumb: false
36
    property bool showToolbar: false
37
    property string clipName: controller.clipName
38
    property real baseUnit: fontMetrics.font.pixelSize
39 40 41 42
    property int duration: 300
    property int mouseRulerPos: 0
    property double frameSize: 10
    property double timeScale: 1
43 44 45
    property int overlayType: controller.overlayType
    property color overlayColor: 'cyan'
    property bool isClipMonitor: true
46
    property int dragType: 0
47
    
48 49
    FontMetrics {
        id: fontMetrics
50
        font: fixedFont
51 52
    }

53 54 55 56 57
    Timer {
        id: thumbTimer
        interval: 3000; running: false;
    }

58
    signal editCurrentMarker()
59

60
    onDurationChanged: {
61
        clipMonitorRuler.updateRuler()
62 63 64 65 66
        // Reset zoom on clip change
        root.zoomStart = 0
        root.zoomFactor = 1
        root.showZoomBar = false
        root.zoomOffset = 0
67
    }
68 69 70
    onWidthChanged: {
        clipMonitorRuler.updateRuler()
    }
71 72 73 74 75
    onClipNameChanged: {
        // Animate clip name
        clipNameLabel.opacity = 1
        showAnimate.restart()
    }
76

77 78 79 80
    function updatePalette() {
        clipMonitorRuler.forceRepaint()
    }

81
    function switchOverlay() {
82
        if (controller.overlayType >= 5) {
83 84 85 86 87 88
            controller.overlayType = 0
        } else {
            controller.overlayType = controller.overlayType + 1;
        }
        root.overlayType = controller.overlayType
    }
89

90 91 92 93 94 95 96 97
    MouseArea {
        id: barOverArea
        hoverEnabled: true
        acceptedButtons: Qt.NoButton
        anchors.fill: parent
    }
    SceneToolBar {
        id: sceneToolBar
98 99 100 101 102
        barContainsMouse: sceneToolBar.rightSide ? barOverArea.mouseX >= x - 10 : barOverArea.mouseX < x + width + 10
        onBarContainsMouseChanged: {
            sceneToolBar.opacity = 1
            sceneToolBar.visible = sceneToolBar.barContainsMouse
        }
103 104 105 106 107
        anchors {
            right: parent.right
            top: parent.top
            topMargin: 4
            rightMargin: 4
108
            leftMargin: 4
109 110
        }
    }
111

112
    Item {
113
        height: root.height - controller.rulerHeight
114 115 116 117 118 119
        width: root.width
        Item {
            id: frame
            objectName: "referenceframe"
            width: root.profile.x * root.scalex
            height: root.profile.y * root.scaley
120
            anchors.centerIn: parent
121

122 123 124 125 126
            Loader {
                anchors.fill: parent
                source: {
                    switch(root.overlayType)
                    {
127
                        case 0:
128
                            return '';
129
                        case 1:
130
                            return "OverlayStandard.qml";
131
                        case 2:
132
                            return "OverlayMinimal.qml";
133
                        case 3:
134
                            return "OverlayCenter.qml";
135
                        case 4:
136
                            return "OverlayCenterDiagonal.qml";
137
                        case 5:
138
                            return "OverlayThirds.qml";
139
                    }
140
                }
141 142
            }
        }
143 144 145
        Item {
            id: monitorOverlay
            anchors.fill: parent
146

147
            Item {
148
                id: audioThumb
149
                property bool stateVisible: (clipMonitorRuler.containsMouse || thumbMouseArea.containsMouse || thumbTimer.running || root.showZoomBar)
150
                property bool isAudioClip: controller.clipType == ProducerType.Audio
151 152 153
                anchors {
                    left: parent.left
                    bottom: parent.bottom
154
                    bottomMargin: root.zoomOffset
155
                }
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
                Label {
                    id: clipStreamLabel
                    font: fixedFont
                    anchors {
                        bottom: audioThumb.isAudioClip ? parent.bottom : parent.top
                        horizontalCenter: parent.horizontalCenter
                    }
                    color: "white"
                    text: controller.clipStream
                    background: Rectangle {
                        color: "#222277"
                    }
                    visible: text != ""
                    padding :4
                }
171
                height: isAudioClip ? parent.height : parent.height / 6
172 173
                //font.pixelSize * 3
                width: parent.width
174
                visible: root.showAudiothumb && (isAudioClip || controller.clipType == ProducerType.AV)
175

176
                states: [
177
                    State { when: audioThumb.stateVisible || audioThumb.isAudioClip;
178
                        PropertyChanges {   target: audioThumb; opacity: 1.0    } },
179
                    State { when: !audioThumb.stateVisible && !audioThumb.isAudioClip;
180
                        PropertyChanges {   target: audioThumb; opacity: 0.0    } }
181 182
                ]
                transitions: [ Transition {
183
                    NumberAnimation { property: "opacity"; duration: audioThumb.isAudioClip ? 0 : 500}
184
                } ]
185
                Rectangle {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
186
                    color: activePalette.base
187
                    opacity: audioThumb.isAudioClip ? 1 : 0.6
188 189 190 191 192 193
                    anchors.fill: parent
                }
                Rectangle {
                    color: "yellow"
                    opacity: 0.3
                    height: parent.height
194 195
                    x: controller.zoneIn * timeScale / root.zoomFactor - (audioThumb.width/root.zoomFactor * root.zoomStart)
                    width: (controller.zoneOut - controller.zoneIn) * timeScale / root.zoomFactor
196 197
                    visible: controller.zoneIn > 0 || controller.zoneOut < duration - 1
                }
198 199 200
                Repeater {
                    id: streamThumb
                    model: controller.audioThumb.length
201 202 203
                    onCountChanged: {
                        thumbTimer.start()
                    }
204 205 206 207 208 209 210 211 212
                    property double streamHeight: parent.height / streamThumb.count
                    Item {
                        anchors.fill: parent
                        Image {
                            anchors.left: parent.left
                            anchors.right: parent.right
                            height: streamThumb.streamHeight
                            y: model.index * height
                            source: controller.audioThumb[model.index]
213 214 215 216
                            transform: [
                                Translate { x: (-audioThumb.width * root.zoomStart)},
                                Scale {xScale: 1/root.zoomFactor}
                            ]
217 218 219 220 221 222 223 224 225 226
                            asynchronous: true
                        }
                        Rectangle {
                            width: parent.width
                            y: (model.index + 1) * streamThumb.streamHeight
                            height: 1
                            visible: streamThumb.count > 1 && model.index < streamThumb.count - 1
                            color: 'black'
                        }
                    }
227 228 229 230 231
                }
                Rectangle {
                    color: "red"
                    width: 1
                    height: parent.height
232
                    x: controller.position * timeScale / root.zoomFactor - (audioThumb.width/root.zoomFactor * root.zoomStart)
233
                }
234 235 236
                MouseArea {
                    id: thumbMouseArea
                    anchors.fill: parent
237
                    acceptedButtons: audioThumb.isAudioClip ? Qt.NoButton : Qt.LeftButton
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
238
                    hoverEnabled: true
239 240 241 242 243 244
                    onPressed: {
                        var pos = Math.max(mouseX, 0)
                        pos += audioThumb.width/root.zoomFactor * root.zoomStart
                        pos *= root.zoomFactor
                        controller.setPosition(Math.min(pos / root.timeScale, root.duration));
                    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
245
                    onPositionChanged: {
246
                        if (mouse.modifiers & Qt.ShiftModifier || (pressed && !audioThumb.isAudioClip)) {
247
                            var pos = Math.max(mouseX, 0)
248 249
                            pos += audioThumb.width/root.zoomFactor * root.zoomStart
                            pos *= root.zoomFactor
250
                            controller.setPosition(Math.min(pos / root.timeScale, root.duration));
251 252
                        }
                    }
253 254 255 256 257 258 259 260 261 262 263
                    onWheel: {
                        if (wheel.modifiers & Qt.ControlModifier) {
                            if (wheel.angleDelta.y < 0) {
                                // zoom out
                                clipMonitorRuler.zoomOutRuler(wheel.x)
                            } else {
                                // zoom in
                                clipMonitorRuler.zoomInRuler(wheel.x)
                            }
                        }
                    }
264
                }
265
            }
266 267 268 269 270 271 272 273 274 275 276 277 278
            Label {
                id: clipNameLabel
                font: fixedFont
                anchors {
                    top: parent.top
                    horizontalCenter: parent.horizontalCenter
                }
                color: "white"
                text: clipName
                background: Rectangle {
                    color: "#222277"
                }
                visible: clipName != ""
279
                padding :4
280 281 282 283 284 285 286
                SequentialAnimation {
                    id: showAnimate
                    running: false
                    NumberAnimation { target: clipNameLabel; duration: 3000 }
                    NumberAnimation { target: clipNameLabel; property: "opacity"; to: 0; duration: 1000 }
                }
            }
287

288
            Label {
289
                id: timecode
290 291
                font.family: fontMetrics.font.family
                font.pointSize: 1.5 * fontMetrics.font.pointSize
292
                objectName: "timecode"
293 294 295 296 297
                color: "#ffffff"
                padding: 2
                background: Rectangle {
                    color: "#66000000"
                }
298
                text: controller.toTimecode(controller.position)
299 300 301 302
                visible: root.showTimecode
                anchors {
                    right: parent.right
                    bottom: parent.bottom
303
                    bottomMargin: (audioThumb.stateVisible && !audioThumb.isAudioClip && audioThumb.visible) ? (audioThumb.height + root.zoomOffset) : root.zoomOffset
304
                }
305
            }
306
            Label {
307
                id: fpsdropped
308 309
                font.family: fontMetrics.font.family
                font.pointSize: 1.5 * fontMetrics.font.pointSize
310
                objectName: "fpsdropped"
311 312 313
                color: "#ffffff"
                padding: 2
                background: Rectangle {
314
                    color: root.dropped ? "#99ff0000" : "#66004400"
315
                }
316
                text: i18n("%1fps", root.fps)
317 318 319 320
                visible: root.showFps
                anchors {
                    right: timecode.visible ? timecode.left : parent.right
                    bottom: parent.bottom
321
                    bottomMargin: (audioThumb.stateVisible && !audioThumb.isAudioClip && audioThumb.visible) ? (audioThumb.height + root.zoomOffset) : root.zoomOffset
322
                }
323
            }
324 325 326 327 328 329
            Label {
                id: inPoint
                font: fixedFont
                anchors {
                    left: parent.left
                    bottom: parent.bottom
330
                    bottomMargin: root.zoomOffset
331 332 333 334 335 336 337
                }
                visible: root.showMarkers && controller.position == controller.zoneIn
                text: i18n("In Point")
                color: "white"
                background: Rectangle {
                    color: "#228b22"
                }
338
                padding:4
339 340 341 342 343 344 345 346
                horizontalAlignment: TextInput.AlignHCenter
            }
            Label {
                id: outPoint
                font: fixedFont
                anchors {
                    left: inPoint.visible ? inPoint.right : parent.left
                    bottom: parent.bottom
347
                    bottomMargin: root.zoomOffset
348
                }
349
                visible: root.showMarkers && controller.position + 1 == controller.zoneOut
350 351 352
                text: i18n("Out Point")
                color: "white"
                background: Rectangle {
353
                    color: "#770000"
354
                }
355
                padding: 4
356 357
                horizontalAlignment: TextInput.AlignHCenter
            }
358 359
            TextField {
                id: marker
360
                font: fixedFont
361 362
                objectName: "markertext"
                activeFocusOnPress: true
363
                text: controller.markerComment
364 365 366 367 368 369
                onEditingFinished: {
                    root.markerText = marker.displayText
                    marker.focus = false
                    root.editCurrentMarker()
                }
                anchors {
370
                    left: outPoint.visible ? outPoint.right : inPoint.visible ? inPoint.right : parent.left
371
                    bottom: parent.bottom
372
                    bottomMargin: root.zoomOffset
373 374
                }
                visible: root.showMarkers && text != ""
375 376 377
                height: inPoint.height
                width: fontMetrics.boundingRect(displayText).width + 10
                horizontalAlignment: displayText == text ? TextInput.AlignHCenter : TextInput.AlignLeft
378
                background: Rectangle {
379
                        color: "#990000ff"
380
                }
381 382
                color: "#ffffff"
                padding: 0
383
                maximumLength: 20
384
            }
385
        }
386

387 388
        Rectangle {
            // Audio or video only drag zone
389
            x: 2
390
            y: inPoint.visible || outPoint.visible || marker.visible ? parent.height - inPoint.height - height - 2 - root.zoomOffset : parent.height - height - 2 - root.zoomOffset
391 392 393 394
            width: childrenRect.width
            height: childrenRect.height
            color: Qt.rgba(activePalette.highlight.r, activePalette.highlight.g, activePalette.highlight.b, 0.7)
            radius: 4
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
395
            opacity: (dragAudioArea.containsMouse || dragVideoArea.containsMouse  || thumbMouseArea.containsMouse || (barOverArea.containsMouse && barOverArea.mouseY >= y)) ? 1 : 0
396
            visible: controller.clipHasAV
397 398 399 400 401 402 403 404
            onOpacityChanged: {
                if (opacity == 1) {
                    videoDragButton.x = 0
                    videoDragButton.y = 0
                    audioDragButton.x = videoDragButton.x + videoDragButton.width
                    audioDragButton.y = 0
                }
            }
405
            Row {
406 407 408 409
                id: dragRow
                ToolButton {
                    id: videoDragButton
                    icon.name: "kdenlive-show-video"
410 411 412
                    Drag.active: dragVideoArea.drag.active
                    Drag.dragType: Drag.Automatic
                    Drag.mimeData: {
413
                        "kdenlive/producerslist" : "V" + controller.clipId + "/" + controller.zoneIn + "/" + (controller.zoneOut - 1)
414
                    }
415 416 417 418 419 420
                    MouseArea {
                        id: dragVideoArea
                        hoverEnabled: true
                        anchors.fill: parent
                        propagateComposedEvents: true
                        cursorShape: Qt.PointingHand
421
                        drag.target: parent
422
                        onExited: {
423 424
                            parent.x = 0
                            parent.y = 0
425 426 427 428 429 430
                        }
                    }
                }
                ToolButton {
                    id: audioDragButton
                    icon.name: "audio-volume-medium"
431 432 433
                    Drag.active: dragAudioArea.drag.active
                    Drag.dragType: Drag.Automatic
                    Drag.mimeData: {
434
                        "kdenlive/producerslist" : "A" + controller.clipId + "/" + controller.zoneIn + "/" + (controller.zoneOut - 1)
435
                    }
436 437 438 439 440 441
                    MouseArea {
                        id: dragAudioArea
                        hoverEnabled: true
                        anchors.fill: parent
                        propagateComposedEvents: true
                        cursorShape: Qt.PointingHand
442
                        drag.target: parent
443
                        onExited: {
444 445
                            parent.x = videoDragButton.x + videoDragButton.width
                            parent.y = 0
446 447 448
                        }
                    }
                }
449 450
            }
        }
451
    }
452 453 454 455 456 457 458
    MonitorRuler {
        id: clipMonitorRuler
        anchors {
            left: root.left
            right: root.right
            bottom: root.bottom
        }
459
        height: controller.rulerHeight
460
    }
461
}