Warning, /multimedia/kdenlive/src/timeline2/view/qml/Composition.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2017 Jean-Baptiste Mardelle 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 This file is part of Kdenlive. See www.kdenlive.org. 0005 Based on work by Dan Dennedy <dan@dennedy.org> (Shotcut) 0006 */ 0007 0008 import QtQuick 2.15 0009 import QtQuick.Controls 2.15 0010 import QtQml.Models 2.15 0011 import QtQuick.Window 2.15 0012 import 'Timeline.js' as Logic 0013 0014 Item { 0015 id: compositionRoot 0016 property real timeScale: 1 0017 property string clipName: '' 0018 property string clipResource: '' 0019 property string mltService: '' 0020 property int modelStart 0021 property int displayHeight: 0 0022 property var parentTrack: trackRoot 0023 property int inPoint: 0 0024 property int outPoint: 0 0025 property int clipDuration: 0 0026 property bool isAudio: false 0027 property bool showKeyframes: false 0028 property var itemType: 0 0029 property bool isGrabbed: false 0030 property var keyframeModel 0031 property bool grouped: false 0032 property int binId: 0 0033 property int trackHeight 0034 property int trackIndex //Index in track repeater 0035 property int trackId: -42 //Id in the model 0036 property int aTrack: -1 0037 property int clipId //Id of the clip in the model 0038 property int originalTrackId: trackId 0039 property bool isComposition: true 0040 property int originalX: x 0041 property int originalDuration: clipDuration 0042 property int lastValidDuration: clipDuration 0043 property int draggedX: x 0044 property bool selected: false 0045 property double speed: 1.0 0046 property color color: displayRect.color 0047 property color borderColor: 'black' 0048 property bool hideCompoViews: !visible || width < root.minClipWidthForViews 0049 property int scrollStart: scrollView.contentX - (compositionRoot.modelStart * root.timeScale) 0050 visible: scrollView.width + compositionRoot.scrollStart >= 0 && compositionRoot.scrollStart < compositionRoot.width 0051 0052 property int mouseXPos: mouseArea.mouseX 0053 // We set coordinates to ensure the item can be found using childAt in timeline.qml getItemAtPosq 0054 property int trackOffset: 5 0055 y: trackOffset 0056 height: 5 0057 enabled: !compoArea.containsDrag 0058 0059 0060 signal trimmingIn(var clip, real newDuration) 0061 signal trimmedIn(var clip) 0062 signal trimmingOut(var clip, real newDuration) 0063 signal trimmedOut(var clip) 0064 0065 onScrollStartChanged: { 0066 if (!compositionRoot.visible) { 0067 return 0068 } 0069 updateLabelOffset() 0070 if (!compositionRoot.hideClipViews && compositionRoot.width > scrollView.width) { 0071 if (effectRow.item && effectRow.item.kfrCanvas) { 0072 effectRow.item.kfrCanvas.requestPaint() 0073 } 0074 } 0075 } 0076 0077 /*onKeyframeModelChanged: { 0078 if (effectRow.item && effectRow.item.keyframecanvas) { 0079 effectRow.item.keyframecanvas.requestPaint() 0080 } 0081 }*/ 0082 0083 onModelStartChanged: { 0084 x = modelStart * timeScale; 0085 } 0086 0087 onIsGrabbedChanged: { 0088 if (compositionRoot.isGrabbed) { 0089 grabItem() 0090 } 0091 } 0092 0093 function itemHeight() { 0094 return displayRect.height 0095 } 0096 0097 function grabItem() { 0098 compositionRoot.forceActiveFocus() 0099 mouseArea.focus = true 0100 } 0101 0102 function resetSelection() { 0103 if (effectRow.visible) { 0104 effectRow.item.resetSelection() 0105 } 0106 } 0107 0108 function doesContainMouse(pnt) { 0109 return pnt.x >= 0 && pnt.x < displayRect.width && (pnt.y > displayRect.y - trackOffset) 0110 } 0111 0112 onTrackIdChanged: { 0113 compositionRoot.parentTrack = Logic.getTrackById(trackId) 0114 compositionRoot.y = compositionRoot.originalTrackId == -1 || trackId == originalTrackId ? 0 : parentTrack.y - Logic.getTrackById(compositionRoot.originalTrackId).y; 0115 } 0116 onClipDurationChanged: { 0117 width = clipDuration * timeScale; 0118 } 0119 onTimeScaleChanged: { 0120 x = modelStart * timeScale; 0121 width = clipDuration * timeScale; 0122 if (compositionRoot.visible) { 0123 updateLabelOffset() 0124 if (!compositionRoot.hideClipViews) { 0125 if (effectRow.item && effectRow.item.kfrCanvas) { 0126 effectRow.item.kfrCanvas.requestPaint() 0127 } 0128 } 0129 } 0130 } 0131 0132 function updateLabelOffset() 0133 { 0134 labelRect.anchors.leftMargin = compositionRoot.scrollStart > 0 ? (labelRect.width > compositionRoot.width ? 0 : compositionRoot.scrollStart) : 0 0135 } 0136 0137 /* function reparent(track) { 0138 parent = track 0139 isAudio = track.isAudio 0140 parentTrack = track 0141 displayHeight = track.height / 2 0142 compositionRoot.trackId = parentTrack.trackId 0143 } 0144 */ 0145 function updateDrag() { 0146 console.log('XXXXXXXXXXXXXXX\n\nXXXXXXXXXXXXX \nUPDATING COMPO DRAG') 0147 var itemPos = mapToItem(tracksContainerArea, 0, displayRect.y, displayRect.width, displayRect.height) 0148 initDrag(compositionRoot, itemPos, compositionRoot.clipId, compositionRoot.modelStart, compositionRoot.trackId, true) 0149 } 0150 0151 Rectangle { 0152 id: displayRect 0153 anchors.top: compositionRoot.top 0154 anchors.right: compositionRoot.right 0155 anchors.left: compositionRoot.left 0156 anchors.topMargin: displayHeight - compositionRoot.trackOffset 0157 height: parentTrack.height - displayHeight 0158 color: Qt.darker('mediumpurple') 0159 border.color: grouped ? root.groupColor : mouseArea.containsMouse ? activePalette.highlight : borderColor 0160 border.width: isGrabbed ? 8 : 2 0161 opacity: dragProxyArea.drag.active && dragProxy.draggedItem == clipId ? 0.5 : 1.0 0162 onWidthChanged: { 0163 console.log('TRIM AREA ENABLED: ',trimOutMouseArea.enabled) 0164 } 0165 0166 /*Drag.active: mouseArea.drag.active 0167 Drag.proposedAction: Qt.MoveAction*/ 0168 0169 states: [ 0170 State { 0171 name: 'normal' 0172 when: !compositionRoot.selected 0173 PropertyChanges { 0174 target: compositionRoot 0175 z: 0 0176 } 0177 }, 0178 State { 0179 name: 'selected' 0180 when: compositionRoot.selected 0181 PropertyChanges { 0182 target: compositionRoot 0183 z: 1 0184 } 0185 PropertyChanges { 0186 target: displayRect 0187 height: parentTrack.height - displayHeight + Math.min(Logic.getTrackHeightByPos(Logic.getTrackIndexFromId(parentTrack.trackInternalId) + 1) / 3, root.baseUnit) 0188 color: 'mediumpurple' 0189 border.color: root.selectionColor 0190 } 0191 } 0192 ] 0193 transitions: Transition { 0194 NumberAnimation { 0195 properties: "height"; 0196 easing.type: Easing.InOutQuad; 0197 duration: 150; 0198 } 0199 } 0200 MouseArea { 0201 id: mouseArea 0202 anchors.fill: parent 0203 acceptedButtons: Qt.RightButton 0204 enabled: root.activeTool === 0 0205 hoverEnabled: root.activeTool === 0 0206 Keys.onShortcutOverride: event => {event.accepted = compositionRoot.isGrabbed && (event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Up || event.key === Qt.Key_Down || event.key === Qt.Key_Escape)} 0207 Keys.onLeftPressed: event => { 0208 var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1 0209 controller.requestCompositionMove(compositionRoot.clipId, compositionRoot.originalTrackId, compositionRoot.modelStart - offset, true, true) 0210 } 0211 Keys.onRightPressed: event => { 0212 var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1 0213 controller.requestCompositionMove(compositionRoot.clipId, compositionRoot.originalTrackId, compositionRoot.modelStart + offset, true, true) 0214 } 0215 Keys.onUpPressed: { 0216 controller.requestCompositionMove(compositionRoot.clipId, controller.getNextTrackId(compositionRoot.originalTrackId), compositionRoot.modelStart, true, true) 0217 } 0218 Keys.onDownPressed: { 0219 controller.requestCompositionMove(compositionRoot.clipId, controller.getPreviousTrackId(compositionRoot.originalTrackId), compositionRoot.modelStart, true, true) 0220 } 0221 Keys.onEscapePressed: { 0222 timeline.grabCurrent() 0223 } 0224 cursorShape: (trimInMouseArea.drag.active || trimOutMouseArea.drag.active)? Qt.SizeHorCursor : dragProxyArea.cursorShape 0225 0226 onPressed: mouse => { 0227 root.autoScrolling = false 0228 compositionRoot.forceActiveFocus(); 0229 root.mainItemId = compositionRoot.clipId 0230 if (mouse.button == Qt.RightButton) { 0231 if (timeline.selection.indexOf(compositionRoot.clipId) === -1) { 0232 controller.requestAddToSelection(compositionRoot.clipId, true) 0233 } 0234 root.showCompositionMenu() 0235 } 0236 } 0237 onReleased: { 0238 root.autoScrolling = timeline.autoScroll 0239 } 0240 onEntered: { 0241 var itemPos = mapToItem(tracksContainerArea, 0, 0, width, height) 0242 initDrag(compositionRoot, itemPos, compositionRoot.clipId, compositionRoot.modelStart, compositionRoot.trackId, true) 0243 var s = i18n("%1, Position: %2, Duration: %3".arg(label.text).arg(timeline.simplifiedTC(compositionRoot.modelStart)).arg(timeline.simplifiedTC(compositionRoot.clipDuration))) 0244 timeline.showToolTip(s) 0245 } 0246 onExited: { 0247 endDrag() 0248 if (!trimInMouseArea.containsMouse && !trimOutMouseArea.containsMouse) { 0249 timeline.showToolTip() 0250 } 0251 } 0252 onDoubleClicked: mouse => { 0253 if (mouse.modifiers & Qt.ShiftModifier) { 0254 if (keyframeModel && showKeyframes) { 0255 // Add new keyframe 0256 var xPos = Math.round(mouse.x / timeline.scaleFactor) 0257 var yPos = (compositionRoot.height - mouse.y) / compositionRoot.height 0258 keyframeModel.addKeyframe(xPos + compositionRoot.inPoint, yPos) 0259 } else { 0260 proxy.position = compositionRoot.x / timeline.scaleFactor 0261 } 0262 } else { 0263 timeline.editItemDuration(clipId) 0264 } 0265 } 0266 onPositionChanged: mouse => { 0267 if (parentTrack) { 0268 var mapped = parentTrack.mapFromItem(compositionRoot, mouse.x, mouse.y).x 0269 root.mousePosChanged(Math.round(mapped / timeline.scaleFactor)) 0270 } 0271 } 0272 onWheel: wheel => zoomByWheel(wheel) 0273 0274 MouseArea { 0275 id: trimInMouseArea 0276 x: enabled ? -displayRect.border.width : 0 0277 height: parent.height 0278 width: root.baseUnit / 2 0279 visible: enabled && root.activeTool === 0 0280 enabled: !compositionRoot.grouped && (pressed || displayRect.width > 3 * width) 0281 hoverEnabled: true 0282 cursorShape: (enabled && (containsMouse || pressed) ? Qt.SizeHorCursor : Qt.OpenHandCursor) 0283 drag.target: trimInMouseArea 0284 drag.axis: Drag.XAxis 0285 drag.smoothed: false 0286 onPressed: { 0287 root.autoScrolling = false 0288 root.trimInProgress = true; 0289 compositionRoot.originalX = compositionRoot.x 0290 compositionRoot.originalDuration = clipDuration 0291 anchors.left = undefined 0292 trimIn.opacity = 0 0293 } 0294 onReleased: { 0295 root.autoScrolling = timeline.autoScroll 0296 anchors.left = parent.left 0297 compositionRoot.trimmedIn(compositionRoot) 0298 trimIn.opacity = 0 0299 updateDrag() 0300 root.trimInProgress = false; 0301 } 0302 onPositionChanged: mouse => { 0303 if (mouse.buttons === Qt.LeftButton) { 0304 var delta = Math.round(x / timeScale) 0305 if (delta < -modelStart) { 0306 delta = -modelStart 0307 } 0308 if (delta !== 0) { 0309 var newDuration = compositionRoot.clipDuration - delta 0310 compositionRoot.trimmingIn(compositionRoot, newDuration) 0311 } 0312 } 0313 } 0314 onEntered: { 0315 if (!pressed) { 0316 trimIn.opacity = 1 0317 timeline.showKeyBinding(i18n("<b>Drag</b> to resize")) 0318 } 0319 } 0320 onExited: { 0321 trimIn.opacity = 0 0322 if (!mouseArea.containsMouse) { 0323 timeline.showToolTip() 0324 } 0325 if (!trimInMouseArea.containsMouse) { 0326 timeline.showKeyBinding() 0327 } 0328 } 0329 Rectangle { 0330 id: trimIn 0331 anchors.left: parent.left 0332 width: displayRect.border.width 0333 height: parent.height 0334 color: 'lawngreen' 0335 opacity: 0 0336 Drag.active: trimInMouseArea.drag.active 0337 Drag.proposedAction: Qt.MoveAction 0338 visible: trimInMouseArea.pressed || (root.activeTool === 0 && !mouseArea.drag.active && parent.enabled) 0339 } 0340 } 0341 0342 MouseArea { 0343 id: trimOutMouseArea 0344 anchors.right: parent.right 0345 anchors.rightMargin: enabled ? -displayRect.border.width : 0 0346 height: displayRect.height 0347 width: root.baseUnit / 2 0348 hoverEnabled: true 0349 cursorShape: (enabled && (containsMouse || pressed) ? Qt.SizeHorCursor : Qt.OpenHandCursor) 0350 drag.target: trimOutMouseArea 0351 drag.axis: Drag.XAxis 0352 drag.smoothed: false 0353 visible: enabled && root.activeTool === 0 0354 enabled: !compositionRoot.grouped && (pressed || displayRect.width > 3 * width) 0355 0356 onPressed: { 0357 root.autoScrolling = false 0358 root.trimInProgress = true; 0359 compositionRoot.originalDuration = clipDuration 0360 anchors.right = undefined 0361 trimOut.opacity = 0 0362 } 0363 onReleased: { 0364 root.autoScrolling = timeline.autoScroll 0365 anchors.right = parent.right 0366 compositionRoot.trimmedOut(compositionRoot) 0367 updateDrag() 0368 root.trimInProgress = false; 0369 } 0370 onPositionChanged: mouse => { 0371 if (mouse.buttons === Qt.LeftButton) { 0372 var newDuration = Math.round((x + width) / timeScale) 0373 compositionRoot.trimmingOut(compositionRoot, newDuration) 0374 } 0375 } 0376 onEntered: { 0377 if (!pressed) { 0378 trimOut.opacity = 1 0379 timeline.showKeyBinding(i18n("<b>Drag</b> to resize")) 0380 } 0381 } 0382 onExited: { 0383 trimOut.opacity = 0 0384 if (!mouseArea.containsMouse) { 0385 timeline.showToolTip() 0386 } 0387 if (!trimOutMouseArea.containsMouse) { 0388 timeline.showKeyBinding() 0389 } 0390 } 0391 Rectangle { 0392 id: trimOut 0393 anchors.right: parent.right 0394 width: displayRect.border.width 0395 height: parent.height 0396 color: 'red' 0397 opacity: 0 0398 Drag.active: trimOutMouseArea.drag.active 0399 Drag.proposedAction: Qt.MoveAction 0400 visible: trimOutMouseArea.pressed || (root.activeTool === 0 && !mouseArea.drag.active && parent.enabled) 0401 } 0402 } 0403 Item { 0404 // clipping container 0405 id: container 0406 anchors.fill: parent 0407 anchors.margins: displayRect.border.width 0408 clip: true 0409 Rectangle { 0410 // Debug: Clip Id background 0411 id: debugCidRect 0412 color: 'magenta' 0413 width: debugCid.width 0414 height: debugCid.height 0415 visible: root.debugmode 0416 anchors.left: labelRect.right 0417 Text { 0418 // Composition ID text 0419 id: debugCid 0420 text: compositionRoot.clipId 0421 font: miniFont 0422 anchors { 0423 top: debugCidRect.top 0424 left: debugCidRect.left 0425 topMargin: 1 0426 leftMargin: 1 0427 } 0428 color: 'white' 0429 } 0430 } 0431 Rectangle { 0432 // text background 0433 id: labelRect 0434 anchors.top: parent.top 0435 anchors.left: parent.left 0436 anchors.leftMargin: compositionRoot.scrollStart > 0 ? (labelRect.width > compositionRoot.width ? 0 : compositionRoot.scrollStart) : 0 0437 color: compositionRoot.aTrack > -1 ? 'yellow' : 'lightgray' 0438 visible: compositionRoot.width > root.baseUnit 0439 width: label.width + 2 0440 height: label.height 0441 Text { 0442 id: label 0443 text: clipName + (compositionRoot.aTrack > -1 ? ' > ' + timeline.getTrackNameFromMltIndex(compositionRoot.aTrack) : '') 0444 font: miniFont 0445 anchors { 0446 top: labelRect.top 0447 left: labelRect.left 0448 topMargin: 1 0449 leftMargin: 1 0450 } 0451 color: 'black' 0452 } 0453 } 0454 } 0455 Loader { 0456 // keyframes container 0457 id: effectRow 0458 clip: true 0459 anchors.fill: parent 0460 //asynchronous: true 0461 visible: status == Loader.Ready && compositionRoot.showKeyframes && compositionRoot.keyframeModel && compositionRoot.width > 2 * root.baseUnit 0462 source: compositionRoot.hideClipViews || compositionRoot.keyframeModel == undefined ? "" : "KeyframeView.qml" 0463 Binding { 0464 target: effectRow.item 0465 property: "kfrModel" 0466 value: compositionRoot.hideClipViews ? undefined : compositionRoot.keyframeModel 0467 when: effectRow.status == Loader.Ready && effectRow.item 0468 } 0469 Binding { 0470 target: effectRow.item 0471 property: "selected" 0472 value: compositionRoot.selected 0473 when: effectRow.status == Loader.Ready && effectRow.item 0474 } 0475 Binding { 0476 target: effectRow.item 0477 property: "inPoint" 0478 value: 0 0479 when: effectRow.status == Loader.Ready && effectRow.item 0480 } 0481 Binding { 0482 target: effectRow.item 0483 property: "outPoint" 0484 value: compositionRoot.clipDuration 0485 when: effectRow.status == Loader.Ready && effectRow.item 0486 } 0487 Binding { 0488 target: effectRow.item 0489 property: "modelStart" 0490 value: compositionRoot.modelStart 0491 when: effectRow.status == Loader.Ready && effectRow.item 0492 } 0493 Binding { 0494 target: effectRow.item 0495 property: "scrollStart" 0496 value: compositionRoot.scrollStart 0497 when: effectRow.status == Loader.Ready && effectRow.item 0498 } 0499 Binding { 0500 target: effectRow.item 0501 property: "clipId" 0502 value: compositionRoot.clipId 0503 when: effectRow.status == Loader.Ready && effectRow.item 0504 } 0505 } 0506 Connections { 0507 target: effectRow.item 0508 function onSeek(position) { proxy.position = position } 0509 } 0510 } 0511 } 0512 }