Warning, /multimedia/kdenlive/src/timeline2/view/qml/Track.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2013-2016 Meltytech LLC 0003 SPDX-FileCopyrightText: 2013-2016 Dan Dennedy <dan@dennedy.org> 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 import QtQuick 2.15 0009 import QtQml.Models 2.15 0010 import com.enums 1.0 0011 0012 Item{ 0013 id: trackRoot 0014 property alias trackModel: trackModel.model 0015 property alias rootIndex : trackModel.rootIndex 0016 property bool isAudio 0017 property bool isLocked: false 0018 property int trackInternalId : -42 0019 property int trackThumbsFormat 0020 property int itemType: 0 0021 property var effectZones 0022 opacity: model.disabled ? 0.4 : 1 0023 0024 function clipAt(index) { 0025 return repeater.itemAt(index) 0026 } 0027 0028 function isClip(type) { 0029 return type != ProducerType.Composition && type != ProducerType.Track; 0030 } 0031 0032 width: clipRow.width 0033 0034 DelegateModel { 0035 id: trackModel 0036 delegate: Item { 0037 property var itemModel : model 0038 property bool clipItem: isClip(model.clipType) 0039 function calculateZIndex() { 0040 // Z order indicates the items that will be drawn on top. 0041 if (model.clipType == ProducerType.Composition) { 0042 // Compositions should be top, then clips 0043 return 50000; 0044 } 0045 0046 if (model.mixDuration > 0) { 0047 // Clips with mix should be ordered related to their position so that the right clip of a clip mix is always on top (the mix UI is drawn over the right clip) 0048 return Math.round(model.start / 25) + 1; 0049 } 0050 0051 if (root.activeTool === ProjectTool.SlipTool && model.selected) { 0052 return model.item === timeline.trimmingMainClip ? 2 : 1; 0053 } 0054 0055 if (root.activeTool === ProjectTool.RippleTool && model.item === timeline.trimmingMainClip) { 0056 return 1; 0057 } 0058 return 0; 0059 } 0060 z: calculateZIndex() 0061 Loader { 0062 id: loader 0063 Binding { 0064 target: loader.item 0065 property: "speed" 0066 value: model.speed 0067 when: loader.status == Loader.Ready && loader.item && clipItem 0068 } 0069 Binding { 0070 target: loader.item 0071 property: "timeScale" 0072 value: root.timeScale 0073 when: loader.status == Loader.Ready && loader.item 0074 } 0075 Binding { 0076 target: loader.item 0077 property: "fakeTid" 0078 value: model.fakeTrackId 0079 when: loader.status == Loader.Ready && loader.item && clipItem 0080 } 0081 Binding { 0082 target: loader.item 0083 property: "tagColor" 0084 value: model.tag 0085 when: loader.status == Loader.Ready && loader.item && clipItem 0086 } 0087 Binding { 0088 target: loader.item 0089 property: "fakePosition" 0090 value: model.fakePosition 0091 when: loader.status == Loader.Ready && loader.item && clipItem 0092 } 0093 Binding { 0094 target: loader.item 0095 property: "mixDuration" 0096 value: model.mixDuration 0097 when: loader.status == Loader.Ready && loader.item && clipItem 0098 } 0099 Binding { 0100 target: loader.item 0101 property: "mixCut" 0102 value: model.mixCut 0103 when: loader.status == Loader.Ready && loader.item && clipItem 0104 } 0105 Binding { 0106 target: loader.item 0107 property: "selected" 0108 value: model.selected 0109 when: loader.status == Loader.Ready && loader.item 0110 } 0111 Binding { 0112 target: loader.item 0113 property: "mltService" 0114 value: model.mlt_service 0115 when: loader.status == Loader.Ready && loader.item 0116 } 0117 Binding { 0118 target: loader.item 0119 property: "modelStart" 0120 value: model.start 0121 when: loader.status == Loader.Ready && loader.item 0122 } 0123 Binding { 0124 target: loader.item 0125 property: "fadeIn" 0126 value: model.fadeIn 0127 when: loader.status == Loader.Ready && clipItem 0128 } 0129 Binding { 0130 target: loader.item 0131 property: "positionOffset" 0132 value: model.positionOffset 0133 when: loader.status == Loader.Ready && clipItem 0134 } 0135 Binding { 0136 target: loader.item 0137 property: "effectNames" 0138 value: model.effectNames 0139 when: loader.status == Loader.Ready && clipItem 0140 } 0141 Binding { 0142 target: loader.item 0143 property: "isStackEnabled" 0144 value: model.isStackEnabled 0145 when: loader.status == Loader.Ready && clipItem 0146 } 0147 Binding { 0148 target: loader.item 0149 property: "clipStatus" 0150 value: model.clipStatus 0151 when: loader.status == Loader.Ready && clipItem 0152 } 0153 Binding { 0154 target: loader.item 0155 property: "fadeOut" 0156 value: model.fadeOut 0157 when: loader.status == Loader.Ready && clipItem 0158 } 0159 Binding { 0160 target: loader.item 0161 property: "showKeyframes" 0162 value: model.showKeyframes 0163 when: loader.status == Loader.Ready && loader.item 0164 } 0165 Binding { 0166 target: loader.item 0167 property: "isGrabbed" 0168 value: model.isGrabbed 0169 when: loader.status == Loader.Ready && loader.item 0170 } 0171 Binding { 0172 target: loader.item 0173 property: "keyframeModel" 0174 value: model.keyframeModel 0175 when: loader.status == Loader.Ready && loader.item 0176 } 0177 Binding { 0178 target: loader.item 0179 property: "aTrack" 0180 value: model.a_track 0181 when: loader.status == Loader.Ready && model.clipType == ProducerType.Composition 0182 } 0183 Binding { 0184 target: loader.item 0185 property: "trackHeight" 0186 value: root.trackHeight 0187 when: loader.status == Loader.Ready && model.clipType == ProducerType.Composition 0188 } 0189 Binding { 0190 target: loader.item 0191 property: "clipDuration" 0192 value: model.duration 0193 when: loader.status == Loader.Ready && loader.item 0194 } 0195 Binding { 0196 target: loader.item 0197 property: "inPoint" 0198 value: model.in 0199 when: loader.status == Loader.Ready && loader.item 0200 } 0201 Binding { 0202 target: loader.item 0203 property: "outPoint" 0204 value: model.out 0205 when: loader.status == Loader.Ready && loader.item 0206 } 0207 Binding { 0208 target: loader.item 0209 property: "grouped" 0210 value: model.grouped 0211 when: loader.status == Loader.Ready && loader.item 0212 } 0213 Binding { 0214 target: loader.item 0215 property: "clipName" 0216 value: model.name 0217 when: loader.status == Loader.Ready && loader.item 0218 } 0219 Binding { 0220 target: loader.item 0221 property: "clipResource" 0222 value: model.resource 0223 when: loader.status == Loader.Ready && clipItem 0224 } 0225 Binding { 0226 target: loader.item 0227 property: "clipState" 0228 value: model.clipState 0229 when: loader.status == Loader.Ready && clipItem 0230 } 0231 Binding { 0232 target: loader.item 0233 property: "maxDuration" 0234 value: model.maxDuration 0235 when: loader.status == Loader.Ready && clipItem 0236 } 0237 Binding { 0238 target: loader.item 0239 property: "clipThumbId" 0240 value: model.clipThumbId 0241 when: loader.status == Loader.Ready && clipItem 0242 } 0243 Binding { 0244 target: loader.item 0245 property: "forceReloadAudioThumb" 0246 value: model.reloadAudioThumb 0247 when: loader.status == Loader.Ready && clipItem 0248 } 0249 Binding { 0250 target: loader.item 0251 property: "binId" 0252 value: model.binId 0253 when: loader.status == Loader.Ready && clipItem 0254 } 0255 Binding { 0256 target: loader.item 0257 property: "timeremap" 0258 value: model.timeremap 0259 when: loader.status == Loader.Ready && clipItem 0260 } 0261 sourceComponent: { 0262 if (clipItem) { 0263 return clipDelegate 0264 } else if (model.clipType == ProducerType.Composition) { 0265 return compositionDelegate 0266 } else { 0267 // Track 0268 return undefined 0269 } 0270 } 0271 onLoaded: { 0272 item.clipId= model.item 0273 item.parentTrack = trackRoot 0274 if (clipItem) { 0275 console.log('loaded clip: ', model.start, ', ID: ', model.item, ', index: ', trackRoot.DelegateModel.itemsIndex,', TYPE:', model.clipType) 0276 item.isAudio= model.audio 0277 item.markers= model.markers 0278 item.hasAudio = model.hasAudio 0279 item.canBeAudio = model.canBeAudio 0280 item.canBeVideo = model.canBeVideo 0281 item.itemType = model.clipType 0282 item.audioChannels = model.audioChannels 0283 item.audioStream = model.audioStream 0284 item.multiStream = model.multiStream 0285 item.aStreamIndex = model.audioStreamIndex 0286 console.log('loaded clip with Astream: ', model.audioStream) 0287 } else if (model.clipType == ProducerType.Composition) { 0288 console.log('loaded composition: ', model.start, ', ID: ', model.item, ', index: ', trackRoot.DelegateModel.itemsIndex) 0289 //item.aTrack = model.a_track 0290 } else { 0291 console.log('loaded unwanted element: ', model.item, ', index: ', trackRoot.DelegateModel.itemsIndex) 0292 } 0293 item.trackId = model.trackId 0294 //item.selected= trackRoot.selection.indexOf(item.clipId) != -1 0295 //console.log(width, height); 0296 } 0297 } 0298 } 0299 } 0300 0301 Item { 0302 id: clipRow 0303 height: trackRoot.height 0304 Repeater { id: repeater; model: trackModel } 0305 } 0306 0307 Component { 0308 id: clipDelegate 0309 Clip { 0310 height: trackRoot.height 0311 onInitGroupTrim: clipId => { 0312 // We are resizing a group, remember coordinates of all elements 0313 root.groupTrimData = controller.getGroupData(clipId) 0314 } 0315 onTrimmingIn: (clip, newDuration, shiftTrim, controlTrim) => { 0316 if (root.activeTool === ProjectTool.SelectTool && controlTrim) { 0317 newDuration = controller.requestItemSpeedChange(clip.clipId, newDuration, false, root.snapping) 0318 if (!speedController.visible) { 0319 // Store original speed 0320 speedController.originalSpeed = clip.speed 0321 } 0322 clip.x += clip.width - (newDuration * root.timeScale) 0323 clip.width = newDuration * root.timeScale 0324 speedController.x = clip.x + clip.border.width 0325 speedController.width = Math.max(0, clip.width - 2 * clip.border.width) 0326 speedController.lastValidDuration = newDuration 0327 clip.speed = clip.originalDuration * speedController.originalSpeed / newDuration 0328 speedController.visible = true 0329 var delta = newDuration - clip.originalDuration 0330 var s = timeline.simplifiedTC(Math.abs(delta)) 0331 s = '%1:%2, %3:%4'.arg(i18n("Speed")) 0332 .arg(clip.speed) 0333 .arg(i18n("Duration")) 0334 .arg(timeline.simplifiedTC(newDuration)) 0335 timeline.showToolTip(s) 0336 return 0337 } 0338 var new_duration = 0; 0339 if (root.activeTool === ProjectTool.RippleTool) { 0340 console.log("In: Request for " + newDuration) 0341 new_duration = timeline.requestItemRippleResize(clip.clipId, newDuration, false, false, root.snapping, shiftTrim) 0342 timeline.requestStartTrimmingMode(clip.clipId, false, false); 0343 timeline.ripplePosChanged(new_duration, false); 0344 } else { 0345 new_duration = controller.requestItemResize(clip.clipId, newDuration, false, false, root.snapping, shiftTrim) 0346 } 0347 0348 if (new_duration > 0) { 0349 clip.lastValidDuration = new_duration 0350 clip.originalX = clip.draggedX 0351 // Show amount trimmed as a time in a "bubble" help. 0352 var delta = new_duration - clip.originalDuration 0353 var s = timeline.simplifiedTC(Math.abs(delta)) 0354 s = '%1%2, %3:%4'.arg((delta <= 0)? '+' : '-') 0355 .arg(s) 0356 .arg(i18n("In")) 0357 .arg(timeline.simplifiedTC(clip.inPoint)) 0358 timeline.showToolTip(s) 0359 //bubbleHelp.show(clip.x - 20, trackRoot.y + trackRoot.height, s) 0360 } 0361 } 0362 onTrimmedIn: (clip, shiftTrim, controlTrim) => { 0363 //bubbleHelp.hide() 0364 timeline.showToolTip(); 0365 if (shiftTrim || (root.groupTrimData == undefined/*TODO > */ || root.activeTool === ProjectTool.RippleTool /* < TODO*/) || controlTrim) { 0366 // We only resize one element 0367 if (root.activeTool === ProjectTool.RippleTool) { 0368 timeline.requestItemRippleResize(clip.clipId, clip.originalDuration, false, false, 0, shiftTrim) 0369 } else { 0370 controller.requestItemResize(clip.clipId, clip.originalDuration, false, false, 0, shiftTrim) 0371 } 0372 0373 if (root.activeTool === ProjectTool.SelectTool && controlTrim) { 0374 // Update speed 0375 speedController.visible = false 0376 controller.requestClipResizeAndTimeWarp(clip.clipId, speedController.lastValidDuration, false, root.snapping, shiftTrim, clip.originalDuration * speedController.originalSpeed / speedController.lastValidDuration) 0377 speedController.originalSpeed = 1 0378 } else { 0379 if (root.activeTool === ProjectTool.RippleTool) { 0380 timeline.requestItemRippleResize(clip.clipId, clip.lastValidDuration, false, true, 0, shiftTrim) 0381 timeline.requestEndTrimmingMode(); 0382 } else { 0383 controller.requestItemResize(clip.clipId, clip.lastValidDuration, false, true, 0, shiftTrim) 0384 } 0385 } 0386 } else { 0387 var updatedGroupData = controller.getGroupData(clip.clipId) 0388 controller.processGroupResize(root.groupTrimData, updatedGroupData, false) 0389 } 0390 root.groupTrimData = undefined 0391 } 0392 onTrimmingOut: (clip, newDuration, shiftTrim, controlTrim) => { 0393 if (root.activeTool === ProjectTool.SelectTool && controlTrim) { 0394 if (!speedController.visible) { 0395 // Store original speed 0396 speedController.originalSpeed = clip.speed 0397 } 0398 speedController.x = clip.x + clip.border.width 0399 newDuration = controller.requestItemSpeedChange(clip.clipId, newDuration, true, root.snapping) 0400 clip.width = newDuration * root.timeScale 0401 speedController.width = Math.max(0, clip.width - 2 * clip.border.width) 0402 speedController.lastValidDuration = newDuration 0403 clip.speed = clip.originalDuration * speedController.originalSpeed / newDuration 0404 speedController.visible = true 0405 var s = '%1:%2\%, %3:%4'.arg(i18n("Speed")) 0406 .arg(Math.round(clip.speed*100)) 0407 .arg(i18n("Duration")) 0408 .arg(timeline.simplifiedTC(newDuration)) 0409 timeline.showToolTip(s) 0410 return 0411 } 0412 var new_duration = 0; 0413 if (root.activeTool === ProjectTool.RippleTool) { 0414 console.log("Out: Request for " + newDuration) 0415 new_duration = timeline.requestItemRippleResize(clip.clipId, newDuration, true, false, root.snapping, shiftTrim) 0416 timeline.requestStartTrimmingMode(clip.clipId, false, true); 0417 timeline.ripplePosChanged(new_duration, true); 0418 } else { 0419 new_duration = controller.requestItemResize(clip.clipId, newDuration, true, false, root.snapping, shiftTrim) 0420 } 0421 if (new_duration > 0) { 0422 clip.lastValidDuration = new_duration 0423 // Show amount trimmed as a time in a "bubble" help. 0424 var delta = clip.originalDuration - new_duration 0425 var s = timeline.simplifiedTC(Math.abs(delta)) 0426 s = '%1%2, %3:%4'.arg((delta <= 0)? '+' : '-') 0427 .arg(s) 0428 .arg(i18n("Duration")) 0429 .arg(timeline.simplifiedTC(new_duration)) 0430 timeline.showToolTip(s); 0431 //bubbleHelp.show(clip.x + clip.width - 20, trackRoot.y + trackRoot.height, s) 0432 } 0433 } 0434 onTrimmedOut: (clip, shiftTrim, controlTrim) => { 0435 timeline.showToolTip(); 0436 //bubbleHelp.hide() 0437 if (shiftTrim || (root.groupTrimData == undefined/*TODO > */ || root.activeTool === ProjectTool.RippleTool /* < TODO*/) || controlTrim) { 0438 if (root.activeTool === ProjectTool.RippleTool) { 0439 timeline.requestItemRippleResize(clip.clipId, clip.originalDuration, true, false, 0, shiftTrim) 0440 } else { 0441 controller.requestItemResize(clip.clipId, clip.originalDuration, true, false, 0, shiftTrim) 0442 } 0443 0444 if (root.activeTool === ProjectTool.SelectTool && controlTrim) { 0445 speedController.visible = false 0446 // Update speed 0447 controller.requestClipResizeAndTimeWarp(clip.clipId, speedController.lastValidDuration, true, root.snapping, shiftTrim, clip.originalDuration * speedController.originalSpeed / speedController.lastValidDuration) 0448 speedController.originalSpeed = 1 0449 } else { 0450 if (root.activeTool === ProjectTool.RippleTool) { 0451 timeline.requestItemRippleResize(clip.clipId, clip.lastValidDuration, true, true, 0, shiftTrim) 0452 timeline.requestEndTrimmingMode(); 0453 } else { 0454 controller.requestItemResize(clip.clipId, clip.lastValidDuration, true, true, 0, shiftTrim) 0455 } 0456 } 0457 } else { 0458 var updatedGroupData = controller.getGroupData(clip.clipId) 0459 controller.processGroupResize(root.groupTrimData, updatedGroupData, true) 0460 } 0461 root.groupTrimData = undefined 0462 } 0463 } 0464 } 0465 Component { 0466 id: compositionDelegate 0467 Composition { 0468 displayHeight: Math.max(trackRoot.height / 2, trackRoot.height - (root.baseUnit * 2)) 0469 opacity: 0.8 0470 selected: root.timelineSelection.indexOf(clipId) != -1 0471 onTrimmingIn: (clip, newDuration) => { 0472 var new_duration = controller.requestItemResize(clip.clipId, newDuration, false, false, root.snapping) 0473 if (new_duration > 0) { 0474 clip.lastValidDuration = newDuration 0475 clip.originalX = clip.draggedX 0476 // Show amount trimmed as a time in a "bubble" help. 0477 var delta = clip.originalDuration - new_duration 0478 var s = timeline.simplifiedTC(Math.abs(delta)) 0479 s = i18n("%1%2, Duration = %3", ((delta <= 0)? '+' : '-') 0480 , s, timeline.simplifiedTC(new_duration)) 0481 timeline.showToolTip(s) 0482 } 0483 } 0484 onTrimmedIn: clip => { 0485 timeline.showToolTip() 0486 //bubbleHelp.hide() 0487 controller.requestItemResize(clip.clipId, clip.originalDuration, false, false, root.snapping) 0488 controller.requestItemResize(clip.clipId, clip.lastValidDuration, false, true, root.snapping) 0489 } 0490 onTrimmingOut: (clip, newDuration) => { 0491 var new_duration = controller.requestItemResize(clip.clipId, newDuration, true, false, root.snapping) 0492 if (new_duration > 0) { 0493 clip.lastValidDuration = newDuration 0494 // Show amount trimmed as a time in a "bubble" help. 0495 var delta = clip.originalDuration - new_duration 0496 var s = timeline.simplifiedTC(Math.abs(delta)) 0497 s = i18n("%1%2, Duration = %3", ((delta <= 0)? '+' : '-') 0498 , s, timeline.simplifiedTC(new_duration)) 0499 timeline.showToolTip(s) 0500 } 0501 } 0502 onTrimmedOut: clip => { 0503 timeline.showToolTip() 0504 //bubbleHelp.hide() 0505 controller.requestItemResize(clip.clipId, clip.originalDuration, true, false, root.snapping) 0506 controller.requestItemResize(clip.clipId, clip.lastValidDuration, true, true, root.snapping) 0507 } 0508 } 0509 } 0510 Rectangle { 0511 id: speedController 0512 anchors.bottom: parent.bottom 0513 color: activePalette.highlight //'#cccc0000' 0514 visible: false 0515 clip: true 0516 height: root.baseUnit * 1.5 0517 property int lastValidDuration: 0 0518 property real originalSpeed: 1 0519 Text { 0520 id: speedLabel 0521 text: i18n("Adjusting speed") 0522 font: miniFont 0523 anchors.fill: parent 0524 verticalAlignment: Text.AlignVCenter 0525 horizontalAlignment: Text.AlignHCenter 0526 color: activePalette.highlightedText 0527 } 0528 transitions: [ Transition { 0529 NumberAnimation { property: "opacity"; duration: 300} 0530 } ] 0531 } 0532 Repeater { 0533 model: effectZones 0534 Rectangle { 0535 x: effectZones[index].x * timeline.scaleFactor 0536 height: 2 0537 width: (effectZones[index].y - effectZones[index].x) * timeline.scaleFactor 0538 color: 'blueviolet' 0539 opacity: 1 0540 anchors.top: parent.top 0541 } 0542 } 0543 }