Warning, /multimedia/kdenlive/src/timeline2/view/qml/Clip.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 QtQuick.Controls 2.15 0010 import Kdenlive.Controls 1.0 0011 import QtQuick.Window 2.15 0012 import QtQml.Models 2.15 0013 import QtQml 2.15 0014 0015 import 'Timeline.js' as Logic 0016 import com.enums 1.0 0017 0018 Rectangle { 0019 id: clipRoot 0020 property real timeScale: 1 0021 property string clipName: '' 0022 property string tagColor: '' 0023 property string clipResource: '' 0024 property string mltService: '' 0025 property string effectNames 0026 property bool isStackEnabled 0027 property int modelStart 0028 property int mixDuration: 0 0029 property int mixCut: 0 0030 property int inPoint: 0 0031 property int outPoint: 0 0032 property int clipDuration: 0 0033 property int maxDuration: 0 0034 property bool isAudio: false 0035 property bool timeremap: false 0036 property int audioChannels 0037 property int audioStream: -1 0038 property bool multiStream: false 0039 property int aStreamIndex: 0 0040 property bool showKeyframes: false 0041 property bool isGrabbed: false 0042 property bool grouped: false 0043 property var markers 0044 property var keyframeModel 0045 property int clipState: 0 0046 property int clipStatus: 0 0047 property int itemType: 0 0048 property int fadeIn: 0 0049 property int fadeOut: 0 0050 property int binId: 0 0051 property int positionOffset: 0 0052 property var parentTrack 0053 property int trackIndex //Index in track repeater 0054 property int clipId: -1 //Id of the clip in the model 0055 property int trackId: -1 // Id of the parent track in the model 0056 property int fakeTid: -1 0057 property int fakePosition: 0 0058 property int originalTrackId: -1 0059 property int originalX: x 0060 property int originalDuration: clipDuration 0061 property int lastValidDuration: clipDuration 0062 property int draggedX: x 0063 property double xIntegerOffset: 0 0064 property bool selected: false 0065 property bool isLocked: parentTrack && parentTrack.isLocked === true 0066 property bool hasAudio 0067 property bool canBeAudio 0068 property bool canBeVideo 0069 property double speed: 1.0 0070 property color borderColor: "#000000" 0071 property string clipThumbId 0072 property bool forceReloadAudioThumb 0073 property bool isComposition: false 0074 property int slipOffset: boundValue(outPoint - maxDuration + 1, trimmingOffset, inPoint) 0075 property int scrollStart: scrollView.contentX - (clipRoot.modelStart * root.timeScale) 0076 visible: scrollView.width + clipRoot.scrollStart >= 0 && clipRoot.scrollStart < clipRoot.width 0077 property bool hideClipViews: !visible || clipRoot.width < root.minClipWidthForViews 0078 property int mouseXPos: mouseArea.mouseX 0079 width : Math.round(clipDuration * timeScale) 0080 opacity: dragProxyArea.drag.active && dragProxy.draggedItem == clipId ? 0.8 : 1.0 0081 enabled: !clipDropArea.containsDrag 0082 0083 signal trimmingIn(var clip, real newDuration, bool shiftTrim, bool controlTrim) 0084 signal trimmedIn(var clip, bool shiftTrim, bool controlTrim) 0085 signal initGroupTrim(int clipId) 0086 signal trimmingOut(var clip, real newDuration, bool shiftTrim, bool controlTrim) 0087 signal trimmedOut(var clip, bool shiftTrim, bool controlTrim) 0088 0089 onVisibleChanged: { 0090 if (clipRoot.visible) { 0091 updateLabelOffset() 0092 } 0093 } 0094 0095 onScrollStartChanged: { 0096 if (!clipRoot.visible) { 0097 return 0098 } 0099 updateLabelOffset() 0100 if (isAudio && thumbsLoader.item) { 0101 thumbsLoader.item.reload(1) 0102 } 0103 if (!clipRoot.hideClipViews && clipRoot.width > scrollView.width) { 0104 if (effectRow.item && effectRow.item.kfrCanvas) { 0105 effectRow.item.kfrCanvas.requestPaint() 0106 } 0107 } 0108 } 0109 0110 onIsGrabbedChanged: { 0111 if (clipRoot.isGrabbed) { 0112 grabItem() 0113 } else { 0114 timeline.showToolTip() 0115 mouseArea.focus = false 0116 } 0117 } 0118 0119 function itemHeight() { 0120 return clipRoot.height 0121 } 0122 0123 0124 function boundValue(min, val, max) { 0125 return Math.max(min, Math.min(val, max)) 0126 } 0127 0128 function grabItem() { 0129 clipRoot.forceActiveFocus() 0130 mouseArea.focus = true 0131 } 0132 0133 function resetSelection() { 0134 if (effectRow.visible) { 0135 effectRow.item.resetSelection() 0136 } 0137 } 0138 0139 function clearAndMove(offset) { 0140 controller.requestClearSelection() 0141 controller.requestClipMove(clipRoot.clipId, clipRoot.trackId, clipRoot.modelStart - offset, true, true, true) 0142 controller.requestAddToSelection(clipRoot.clipId) 0143 } 0144 0145 function doesContainMouse(pnt) { 0146 return pnt.x > 0.5 && pnt.x < clipRoot.width 0147 } 0148 0149 onClipResourceChanged: { 0150 if (itemType === ProducerType.Color) { 0151 color: Qt.darker(getColor(), 1.5) 0152 } 0153 } 0154 0155 onClipDurationChanged: { 0156 width = clipDuration * timeScale 0157 if (parentTrack && parentTrack.isAudio && thumbsLoader.item) { 0158 // Duration changed, we may need a different number of repeaters 0159 thumbsLoader.item.reload(1) 0160 } 0161 } 0162 0163 onModelStartChanged: { 0164 x = modelStart * timeScale 0165 xIntegerOffset = Math.ceil(x) - x 0166 } 0167 0168 onFakePositionChanged: { 0169 x = fakePosition * timeScale 0170 xIntegerOffset = Math.ceil(x) - x 0171 } 0172 onFakeTidChanged: { 0173 if (clipRoot.fakeTid > -1 && parentTrack) { 0174 if (clipRoot.parent != dragContainer) { 0175 var pos = clipRoot.mapToGlobal(clipRoot.x, clipRoot.y); 0176 clipRoot.parent = dragContainer 0177 pos = clipRoot.mapFromGlobal(pos.x, pos.y) 0178 clipRoot.x = pos.x 0179 clipRoot.y = pos.y 0180 } 0181 clipRoot.y = Logic.getTrackById(clipRoot.fakeTid).y 0182 clipRoot.height = Logic.getTrackById(clipRoot.fakeTid).height 0183 } else { 0184 clipRoot.height = Qt.binding(function () { 0185 return parentTrack.height 0186 }) 0187 } 0188 } 0189 0190 onForceReloadAudioThumbChanged: { 0191 // TODO: find a way to force reload of clip thumbs 0192 if (!isAudio) { 0193 return; 0194 } 0195 if (thumbsLoader.item) { 0196 thumbsLoader.item.reload(0) 0197 } 0198 } 0199 0200 onTimeScaleChanged: { 0201 x = modelStart * clipRoot.timeScale; 0202 xIntegerOffset = Math.ceil(x) - x 0203 width = clipDuration * clipRoot.timeScale; 0204 if (clipRoot.visible) { 0205 if (!clipRoot.hideClipViews) { 0206 if (effectRow.item && effectRow.item.kfrCanvas) { 0207 effectRow.item.kfrCanvas.requestPaint() 0208 } 0209 } 0210 } 0211 } 0212 0213 function updateLabelOffset() 0214 { 0215 nameContainer.anchors.leftMargin = clipRoot.scrollStart > 0 ? (mixContainer.width + labelRect.width > clipRoot.width ? mixContainer.width : Math.max(clipRoot.scrollStart, mixContainer.width + mixBackground.border.width)) : mixContainer.width + mixBackground.border.width 0216 } 0217 0218 /*border.color: (clipStatus === ClipStatus.StatusMissing || ClipStatus === ClipStatus.StatusWaiting || clipStatus === ClipStatus.StatusDeleting) ? "#ff0000" : selected ? root.selectionColor : grouped ? root.groupColor : borderColor 0219 border.width: isGrabbed ? 8 : 2*/ 0220 0221 function updateDrag() { 0222 var itemPos = mapToItem(tracksContainerArea, 0, 0, clipRoot.width, clipRoot.height) 0223 initDrag(clipRoot, itemPos, clipRoot.clipId, clipRoot.modelStart, clipRoot.trackId, false) 0224 } 0225 0226 function showClipInfo() { 0227 var text = i18n("%1 (%2-%3), Position: %4, Duration: %5".arg(clipRoot.clipName) 0228 .arg(timeline.simplifiedTC(clipRoot.inPoint)) 0229 .arg(timeline.simplifiedTC(clipRoot.outPoint)) 0230 .arg(timeline.simplifiedTC(clipRoot.modelStart)) 0231 .arg(timeline.simplifiedTC(clipRoot.clipDuration))) 0232 timeline.showToolTip(text) 0233 } 0234 0235 function getColor() { 0236 if (clipRoot.clipState === ClipState.Disabled) { 0237 return '#888' 0238 } 0239 if (clipRoot.tagColor) { 0240 return clipRoot.tagColor 0241 } 0242 if (itemType === ProducerType.Text) { 0243 return titleColor 0244 } 0245 if (itemType === ProducerType.Image) { 0246 return imageColor 0247 } 0248 if (itemType === ProducerType.SlideShow) { 0249 return slideshowColor 0250 } 0251 if (itemType === ProducerType.Color) { 0252 var color = clipResource.substring(clipResource.length - 9) 0253 if (color[0] === '#') { 0254 return color 0255 } 0256 return '#' + color.substring(color.length - 8, color.length - 2) 0257 } 0258 return isAudio? root.audioColor : root.videoColor 0259 } 0260 0261 /* function reparent(track) { 0262 console.log('TrackId: ',trackId) 0263 parent = track 0264 height = track.height 0265 parentTrack = track 0266 trackId = parentTrack.trackId 0267 console.log('Reparenting clip to Track: ', trackId) 0268 //generateWaveform() 0269 } 0270 */ 0271 property bool noThumbs: (isAudio || itemType === ProducerType.Color || mltService === '') 0272 property string baseThumbPath: noThumbs ? '' : 'image://thumbnail/' + clipThumbId 0273 0274 DropArea { //Drop area for clips 0275 anchors.fill: clipRoot 0276 keys: 'kdenlive/effect' 0277 property string dropData 0278 property string dropSource 0279 property int dropRow: -1 0280 onEntered: drag => { 0281 dropData = drag.getDataAsString('kdenlive/effect') 0282 dropSource = drag.getDataAsString('kdenlive/effectsource') 0283 updateDrag() 0284 } 0285 onDropped: drag => { 0286 console.log("Add effect: ", dropData) 0287 if (dropSource == '') { 0288 // drop from effects list 0289 controller.addClipEffect(clipRoot.clipId, dropData) 0290 if (proxy.seekOnDrop() && (proxy.position < clipRoot.modelStart || proxy.position > clipRoot.modelStart + clipRoot.clipDuration)) { 0291 // If timeline cursor is not inside clip, seek to drop position 0292 proxy.position = clipRoot.modelStart + drag.x / timeScale 0293 } 0294 } else { 0295 controller.copyClipEffect(clipRoot.clipId, dropSource) 0296 } 0297 dropSource = '' 0298 dropRow = -1 0299 drag.acceptProposedAction 0300 root.regainFocus(mapToItem(root, drag.x, drag.y)) 0301 //console.log('KFR VIEW VISIBLE: ', effectRow.visible, ', SOURCE: ', effectRow.source, '\n HIDEVIEW:', clipRoot.hideClipViews<<', UNDEFINED: ', (clipRoot.keyframeModel == undefined)) 0302 } 0303 onExited: { 0304 root.endDrag() 0305 } 0306 } 0307 MouseArea { 0308 id: mouseArea 0309 enabled: root.activeTool === ProjectTool.SelectTool || root.activeTool === ProjectTool.SlipTool || root.activeTool === ProjectTool.RippleTool 0310 anchors.fill: clipRoot 0311 acceptedButtons: Qt.RightButton 0312 hoverEnabled: root.activeTool === ProjectTool.SelectTool || root.activeTool === ProjectTool.RippleTool 0313 cursorShape: (trimInMouseArea.drag.active || trimOutMouseArea.drag.active)? Qt.SizeHorCursor : dragProxyArea.cursorShape 0314 property bool shiftSlip: false 0315 property bool controlSlip: false 0316 onPressed: mouse => { 0317 root.autoScrolling = false 0318 root.mainItemId = clipRoot.clipId 0319 if (mouse.button == Qt.RightButton) { 0320 if (timeline.selection.indexOf(clipRoot.clipId) === -1) { 0321 controller.requestAddToSelection(clipRoot.clipId, true) 0322 } 0323 root.clickFrame = Math.round(mouse.x / timeline.scaleFactor) 0324 root.showClipMenu(clipRoot.clipId) 0325 root.autoScrolling = timeline.autoScroll 0326 } 0327 } 0328 onReleased: { 0329 root.autoScrolling = timeline.autoScroll 0330 } 0331 Keys.onShortcutOverride: event => {event.accepted = clipRoot.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)} 0332 Keys.onLeftPressed: event => { 0333 var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1 0334 while((clipRoot.modelStart >= offset) && !controller.requestClipMove(clipRoot.clipId, clipRoot.trackId, clipRoot.modelStart - offset, true, true, true)) { 0335 offset++; 0336 } 0337 timeline.showToolTip(i18n("Position: %1", timeline.simplifiedTC(clipRoot.modelStart))); 0338 } 0339 Keys.onRightPressed: event => { 0340 var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1 0341 while(!controller.requestClipMove(clipRoot.clipId, clipRoot.trackId, clipRoot.modelStart + offset, true, true, true)) { 0342 offset++; 0343 } 0344 timeline.showToolTip(i18n("Position: %1", timeline.simplifiedTC(clipRoot.modelStart))); 0345 } 0346 Keys.onUpPressed: { 0347 var nextTrack = controller.getNextTrackId(clipRoot.trackId); 0348 while(!controller.requestClipMove(clipRoot.clipId, nextTrack, clipRoot.modelStart, true, true, true) && nextTrack !== controller.getNextTrackId(nextTrack)) { 0349 nextTrack = controller.getNextTrackId(nextTrack); 0350 } 0351 } 0352 Keys.onDownPressed: { 0353 var previousTrack = controller.getPreviousTrackId(clipRoot.trackId); 0354 while(!controller.requestClipMove(clipRoot.clipId, previousTrack, clipRoot.modelStart, true, true, true) && previousTrack !== controller.getPreviousTrackId(previousTrack)) { 0355 previousTrack = controller.getPreviousTrackId(previousTrack); 0356 } 0357 } 0358 Keys.onEscapePressed: { 0359 timeline.grabCurrent() 0360 //focus = false 0361 } 0362 onPositionChanged: mouse => { 0363 var mapped = parentTrack.mapFromItem(clipRoot, mouse.x, mouse.y).x 0364 root.mousePosChanged(Math.round(mapped / timeline.scaleFactor)) 0365 } 0366 onEntered: { 0367 if (clipRoot.clipId > -1) { 0368 var itemPos = mapToItem(tracksContainerArea, 0, 0, width, height) 0369 initDrag(clipRoot, itemPos, clipRoot.clipId, clipRoot.modelStart, clipRoot.trackId, false) 0370 } 0371 showClipInfo() 0372 } 0373 0374 onExited: { 0375 if (pressed) { 0376 root.endDrag() 0377 if (!trimInMouseArea.containsMouse && !trimOutMouseArea.containsMouse && !compInArea.containsMouse && !compOutArea.containsMouse) { 0378 timeline.showToolTip() 0379 } 0380 } 0381 } 0382 onWheel: wheel => zoomByWheel(wheel) 0383 0384 Loader { 0385 // Thumbs container 0386 id: thumbsLoader 0387 anchors.fill: parent 0388 anchors.leftMargin: parentTrack.isAudio ? xIntegerOffset : itemBorder.border.width + mixContainer.width 0389 anchors.rightMargin: parentTrack.isAudio ? clipRoot.width - Math.floor(clipRoot.width) : itemBorder.border.width 0390 anchors.topMargin: itemBorder.border.width 0391 anchors.bottomMargin: itemBorder.border.width 0392 //clip: true 0393 asynchronous: true 0394 visible: status == Loader.Ready 0395 source: (clipRoot.hideClipViews || clipRoot.itemType == 0 || clipRoot.itemType === ProducerType.Color) ? "" : parentTrack.isAudio ? (timeline.showAudioThumbnails ? "ClipAudioThumbs.qml" : "") : timeline.showThumbnails ? "ClipThumbs.qml" : "" 0396 onStatusChanged: { 0397 if (!parentTrack.isAudio && thumbsLoader.item) { 0398 thumbsLoader.item.initialSpeed = clipRoot.speed 0399 } 0400 } 0401 } 0402 0403 Rectangle { 0404 // Border rectangle 0405 color: 'transparent' 0406 id: itemBorder 0407 anchors.fill: parent 0408 border.color: (clipStatus === ClipStatus.StatusMissing || ClipStatus === ClipStatus.StatusWaiting || clipStatus === ClipStatus.StatusDeleting) ? "#ff0000" : clipRoot.selected ? root.selectionColor : grouped ? root.groupColor : borderColor 0409 border.width: isGrabbed ? 8 : 2 0410 } 0411 0412 Item { 0413 // Clipping container 0414 id: container 0415 anchors.fill: parent 0416 anchors.margins: itemBorder.border.width 0417 //clip: true 0418 property bool showDetails: (!clipRoot.selected || !effectRow.visible) && container.height > 2.2 * labelRect.height 0419 property bool handleVisible: clipRoot.width - width > 3 * root.baseUnit / 2 || width > 3 * root.baseUnit / 2 0420 0421 Item { 0422 // Mix indicator 0423 id: mixContainer 0424 anchors.left: parent.left 0425 anchors.top: parent.top 0426 anchors.bottom: parent.bottom 0427 width: clipRoot.mixDuration * root.timeScale 0428 onWidthChanged: { 0429 if (clipRoot.visible) { 0430 updateLabelOffset() 0431 } 0432 } 0433 0434 Rectangle { 0435 id: mixBackground 0436 property double mixPos: mixBackground.width - clipRoot.mixCut * clipRoot.timeScale 0437 property bool mixSelected: root.selectedMix == clipRoot.clipId 0438 anchors.top: parent.top 0439 anchors.bottom: parent.bottom 0440 anchors.left: parent.left 0441 anchors.right: parent.right 0442 visible: clipRoot.mixDuration > 0 0443 color: mixSelected ? root.selectionColor : "mediumpurple" 0444 Loader { 0445 id: shapeLoader 0446 source: clipRoot.mixDuration > 0 ? "MixShape.qml" : "" 0447 property bool valid: item !== null 0448 } 0449 0450 opacity: mixArea.containsMouse || trimInMixArea.pressed || trimInMixArea.containsMouse || mixSelected ? 1 : 0.7 0451 border.color: mixSelected ? root.selectionColor : "transparent" 0452 border.width: clipRoot.mixDuration > 0 ? 2 : 0 0453 MouseArea { 0454 // Mix click mouse area 0455 id: mixArea 0456 anchors.fill: parent 0457 hoverEnabled: true 0458 cursorShape: Qt.PointingHandCursor 0459 acceptedButtons: Qt.RightButton | Qt.LeftButton 0460 enabled: container.handleVisible && width > root.baseUnit * 0.8 0461 onPressed: mouse => { 0462 controller.requestMixSelection(clipRoot.clipId); 0463 root.autoScrolling = false 0464 if (mouse.button == Qt.RightButton) { 0465 root.clickFrame = Math.round(mouse.x / timeline.scaleFactor) 0466 root.showMixMenu(clipRoot.clipId) 0467 root.autoScrolling = timeline.autoScroll 0468 } 0469 } 0470 onEntered: { 0471 var text = i18n("Mix duration: %1, Cut at: %2".arg(timeline.simplifiedTC(clipRoot.mixDuration)) 0472 .arg(timeline.simplifiedTC(clipRoot.mixDuration - clipRoot.mixCut))) 0473 timeline.showToolTip(text) 0474 } 0475 } 0476 Rectangle { 0477 id: mixCutPos 0478 anchors.right: parent.right 0479 anchors.rightMargin: clipRoot.mixCut * clipRoot.timeScale 0480 anchors.top: parent.top 0481 anchors.bottom: parent.bottom 0482 width: 2 0483 color: "navy" 0484 } 0485 MouseArea { 0486 // Right mix resize handle 0487 id: trimInMixArea 0488 anchors.left: parent.left 0489 anchors.leftMargin: clipRoot.mixDuration * clipRoot.timeScale 0490 height: parent.height 0491 width: root.baseUnit / 2 0492 visible: root.activeTool === ProjectTool.SelectTool 0493 property int previousMix 0494 enabled: !isLocked && mixArea.enabled && (pressed || container.handleVisible) 0495 hoverEnabled: true 0496 drag.target: trimInMixArea 0497 drag.axis: Drag.XAxis 0498 drag.smoothed: false 0499 drag.maximumX: clipRoot.width 0500 drag.minimumX: (clipRoot.mixDuration - clipRoot.mixCut) * clipRoot.timeScale 0501 property bool sizeChanged: false 0502 cursorShape: (containsMouse ? Qt.SizeHorCursor : Qt.ClosedHandCursor) 0503 onPressed: { 0504 root.trimInProgress = true; 0505 previousMix = clipRoot.mixDuration 0506 root.autoScrolling = false 0507 mixOut.color = 'red' 0508 anchors.left = undefined 0509 parent.anchors.right = undefined 0510 mixCutPos.anchors.right = undefined 0511 } 0512 onReleased: mouse => { 0513 root.autoScrolling = timeline.autoScroll 0514 if (sizeChanged) { 0515 controller.resizeStartMix(clipRoot.clipId, Math.round(Math.max(0, x) / clipRoot.timeScale), mouse.modifiers & Qt.ShiftModifier) 0516 sizeChanged = false 0517 } 0518 anchors.left = parent.left 0519 parent.anchors.right = mixContainer.right 0520 mixBackground.anchors.bottom = mixContainer.bottom 0521 mixOut.color = itemBorder.border.color 0522 mixCutPos.anchors.right = mixCutPos.parent.right 0523 root.trimInProgress = false; 0524 } 0525 onPositionChanged: mouse => { 0526 if (mouse.buttons === Qt.LeftButton) { 0527 var currentFrame = Math.round(x / clipRoot.timeScale) 0528 if (currentFrame != previousMix) { 0529 parent.width = currentFrame * clipRoot.timeScale 0530 sizeChanged = true 0531 if (currentFrame > previousMix) { 0532 timeline.showToolTip(i18n("+%1, Mix duration: %2", timeline.simplifiedTC(currentFrame - previousMix), timeline.simplifiedTC(currentFrame))) 0533 } else { 0534 timeline.showToolTip(i18n("-%1, Mix duration: %2", timeline.simplifiedTC(previousMix - currentFrame), timeline.simplifiedTC(currentFrame))) 0535 } 0536 } else { 0537 timeline.showToolTip(i18n("Mix duration: %1", timeline.simplifiedTC(currentFrame))) 0538 } 0539 if (x < mixCutPos.x) { 0540 // This will delete the mix 0541 mixBackground.anchors.bottom = mixContainer.top 0542 } else { 0543 mixBackground.anchors.bottom = mixContainer.bottom 0544 } 0545 } 0546 } 0547 onEntered: { 0548 if (!pressed) { 0549 mixOut.color = 'red' 0550 timeline.showToolTip(i18n("Mix duration: %1", timeline.simplifiedTC(clipRoot.mixDuration))) 0551 } 0552 } 0553 onExited: { 0554 if (!pressed) { 0555 mixOut.color = itemBorder.border.color 0556 if (!mouseArea.containsMouse) { 0557 timeline.showToolTip() 0558 } else { 0559 clipRoot.showClipInfo() 0560 } 0561 } 0562 } 0563 Rectangle { 0564 id: mixOut 0565 width: itemBorder.border.width 0566 height: mixContainer.height 0567 color: itemBorder.border.color 0568 Drag.active: trimInMixArea.drag.active 0569 Drag.proposedAction: Qt.MoveAction 0570 visible: trimInMixArea.pressed || (root.activeTool === ProjectTool.SelectTool && !mouseArea.drag.active && parent.enabled) 0571 } 0572 } 0573 } 0574 0575 } 0576 0577 Repeater { 0578 // Clip markers 0579 model: markers 0580 delegate: 0581 Item { 0582 visible: markerBase.x >= 0 && markerBase.x < clipRoot.width 0583 Rectangle { 0584 id: markerBase 0585 width: 1 0586 height: container.height 0587 x: clipRoot.speed < 0 0588 ? (clipRoot.maxDuration - clipRoot.inPoint) * clipRoot.timeScale + (Math.round(model.frame / clipRoot.speed)) * clipRoot.timeScale - itemBorder.border.width 0589 : (Math.round(model.frame / clipRoot.speed) - clipRoot.inPoint) * clipRoot.timeScale - itemBorder.border.width; 0590 color: model.color 0591 ToolTip.visible: markerArea.containsMouse 0592 ToolTip.text: textMetrics.text 0593 ToolTip.delay: 1000 0594 ToolTip.timeout: 5000 0595 } 0596 Rectangle { 0597 visible: mlabel.visible 0598 opacity: 0.7 0599 x: markerBase.x 0600 radius: 2 0601 width: mlabel.width + 4 0602 height: mlabel.height 0603 y: mlabel.y 0604 color: model.color 0605 MouseArea { 0606 z: 10 0607 id: markerArea 0608 anchors.fill: parent 0609 acceptedButtons: Qt.LeftButton 0610 cursorShape: Qt.PointingHandCursor 0611 hoverEnabled: true 0612 onDoubleClicked: timeline.editMarker(clipRoot.clipId, model.frame) 0613 onClicked: proxy.position = clipRoot.modelStart + (clipRoot.speed < 0 0614 ? (clipRoot.maxDuration - clipRoot.inPoint) * clipRoot.timeScale + (Math.round(model.frame / clipRoot.speed)) 0615 : (Math.round(model.frame / clipRoot.speed) - clipRoot.inPoint)) 0616 } 0617 } 0618 TextMetrics { 0619 id: textMetrics 0620 font: miniFont 0621 text: model.comment 0622 elide: clipRoot.timeScale > 1 ? Text.ElideNone : Text.ElideRight 0623 elideWidth: root.maxLabelWidth 0624 } 0625 Text { 0626 id: mlabel 0627 visible: timeline.showMarkers && textMetrics.elideWidth > root.baseUnit && height < container.height && (markerBase.x > mlabel.width || container.height > 2 * height) 0628 text: textMetrics.elidedText 0629 font: miniFont 0630 x: markerBase.x + 1 0631 y: Math.min(label.height, container.height - height) 0632 color: 'white' 0633 } 0634 } 0635 } 0636 0637 MouseArea { 0638 // Left resize handle 0639 id: trimInMouseArea 0640 x: -itemBorder.border.width 0641 height: parent.height 0642 width: root.baseUnit / 2 0643 visible: enabled && (root.activeTool === ProjectTool.SelectTool || (root.activeTool === ProjectTool.RippleTool && clipRoot.mixDuration <= 0 && !controller.hasClipEndMix(clipRoot.clipId))) 0644 enabled: !isLocked && (pressed || (container.handleVisible && (mixArea.enabled || clipRoot.mixDuration == 0))) && clipRoot.clipId == dragProxy.draggedItem 0645 hoverEnabled: true 0646 drag.target: trimInMouseArea 0647 drag.axis: Drag.XAxis 0648 drag.smoothed: false 0649 property bool shiftTrim: false 0650 property bool controlTrim: false 0651 property bool sizeChanged: false 0652 cursorShape: (enabled && (containsMouse || pressed) ? Qt.SizeHorCursor : Qt.OpenHandCursor) 0653 onPressed: mouse => { 0654 root.autoScrolling = false 0655 root.trimInProgress = true; 0656 clipRoot.originalX = clipRoot.x 0657 clipRoot.originalDuration = clipDuration 0658 shiftTrim = mouse.modifiers & Qt.ShiftModifier 0659 controlTrim = mouse.modifiers & Qt.ControlModifier && itemType != ProducerType.Color && itemType != ProducerType.Timeline && itemType != ProducerType.Playlist && itemType != ProducerType.Image 0660 if (!shiftTrim && (clipRoot.grouped || controller.hasMultipleSelection())) { 0661 clipRoot.initGroupTrim(clipRoot.clipId) 0662 } 0663 if (root.activeTool === ProjectTool.RippleTool) { 0664 timeline.requestStartTrimmingMode(clipRoot.clipId, false, false); 0665 } 0666 trimIn.opacity = 0 0667 } 0668 onReleased: { 0669 root.autoScrolling = timeline.autoScroll 0670 x = -itemBorder.border.width 0671 if (sizeChanged) { 0672 clipRoot.trimmedIn(clipRoot, shiftTrim, controlTrim) 0673 sizeChanged = false 0674 if (!controlTrim && root.activeTool !== ProjectTool.RippleTool) { 0675 updateDrag() 0676 } else { 0677 root.endDrag() 0678 } 0679 } else { 0680 if (root.activeTool === ProjectTool.RippleTool) { 0681 timeline.requestEndTrimmingMode(); 0682 } 0683 root.groupTrimData = undefined 0684 } 0685 root.trimInProgress = false; 0686 } 0687 onDoubleClicked: { 0688 if (clipRoot.mixDuration == 0) { 0689 timeline.mixClip(clipRoot.clipId, -1) 0690 } 0691 } 0692 onPositionChanged: mouse => { 0693 if (mouse.buttons === Qt.LeftButton) { 0694 var currentFrame = Math.round((clipRoot.x + (x + itemBorder.border.width)) / clipRoot.timeScale) 0695 var currentClipPos = clipRoot.modelStart 0696 var delta = currentFrame - currentClipPos 0697 if (delta !== 0) { 0698 if (delta > 0 && (clipRoot.mixDuration > 0 && clipRoot.mixDuration - clipRoot.mixCut - delta < (clipRoot.mixCut == 0 ? 1 : 0))) { 0699 if (clipRoot.mixCut == 0 && clipRoot.mixDuration > 1) { 0700 delta = clipRoot.mixDuration - clipRoot.mixCut - 1 0701 } else if (clipRoot.mixCut > 0 && clipRoot.mixDuration > clipRoot.mixCut) { 0702 delta = clipRoot.mixDuration - clipRoot.mixCut 0703 } else { 0704 return 0705 } 0706 } 0707 var newDuration = 0; 0708 if (root.activeTool === ProjectTool.RippleTool) { 0709 newDuration = clipRoot.originalDuration - delta 0710 } else { 0711 if (maxDuration > 0 && delta < -inPoint && !(mouse.modifiers & Qt.ControlModifier)) { 0712 delta = -inPoint 0713 } 0714 newDuration = clipDuration - delta 0715 } 0716 sizeChanged = true 0717 clipRoot.trimmingIn(clipRoot, newDuration, shiftTrim, controlTrim) 0718 } 0719 } 0720 } 0721 onEntered: { 0722 if (!pressed && !root.isDragging()) { 0723 trimIn.opacity = 1 0724 var itemPos = mapToItem(tracksContainerArea, 0, 0, width, height) 0725 initDrag(clipRoot, itemPos, clipRoot.clipId, clipRoot.modelStart, clipRoot.trackId, false) 0726 var s = i18n("In:%1, Position:%2", timeline.simplifiedTC(clipRoot.inPoint),timeline.simplifiedTC(clipRoot.modelStart)) 0727 timeline.showToolTip(s) 0728 if (clipRoot.mixDuration == 0) { 0729 timeline.showKeyBinding(i18n("<b>Ctrl drag</b> to change speed, <b>Double click</b> to mix with adjacent clip")) 0730 } else { 0731 timeline.showKeyBinding(i18n("<b>Drag</b> to change mix duration")) 0732 } 0733 } 0734 } 0735 onExited: { 0736 trimIn.opacity = 0 0737 if (!pressed) { 0738 if (!mouseArea.containsMouse) { 0739 timeline.showToolTip() 0740 } else { 0741 clipRoot.showClipInfo() 0742 } 0743 if (!fadeInMouseArea.containsMouse) { 0744 timeline.showKeyBinding() 0745 } 0746 } 0747 } 0748 Rectangle { 0749 id: trimIn 0750 anchors.left: parent.left 0751 width: itemBorder.border.width 0752 height: parent.height 0753 color: 'lawngreen' 0754 opacity: 0 0755 Drag.active: trimInMouseArea.drag.active 0756 Drag.proposedAction: Qt.MoveAction 0757 visible: trimInMouseArea.pressed || ((root.activeTool === ProjectTool.SelectTool || (root.activeTool === ProjectTool.RippleTool && clipRoot.mixDuration <= 0)) && !mouseArea.drag.active && parent.enabled) 0758 0759 /*ToolTip { 0760 visible: trimInMouseArea.containsMouse && !trimInMouseArea.pressed 0761 delay: 1000 0762 timeout: 5000 0763 background: Rectangle { 0764 color: activePalette.alternateBase 0765 border.color: activePalette.light 0766 } 0767 contentItem: Label { 0768 color: activePalette.text 0769 font: miniFont 0770 text: i18n("In:%1\nPosition:%2", timeline.simplifiedTC(clipRoot.inPoint),timeline.simplifiedTC(clipRoot.modelStart)) 0771 } 0772 }*/ 0773 } 0774 } 0775 0776 MouseArea { 0777 // Right resize handle 0778 id: trimOutMouseArea 0779 anchors.right: parent.right 0780 anchors.rightMargin: -itemBorder.border.width 0781 anchors.top: parent.top 0782 height: parent.height 0783 width: root.baseUnit / 2 0784 hoverEnabled: true 0785 visible: enabled && (root.activeTool === ProjectTool.SelectTool || (root.activeTool === ProjectTool.RippleTool && clipRoot.mixDuration <= 0)) 0786 enabled: !isLocked && (pressed || container.handleVisible) && clipRoot.clipId == dragProxy.draggedItem 0787 property bool shiftTrim: false 0788 property bool controlTrim: false 0789 property bool sizeChanged: false 0790 cursorShape: (enabled && (containsMouse || pressed) ? Qt.SizeHorCursor : Qt.OpenHandCursor) 0791 drag.target: trimOutMouseArea 0792 drag.axis: Drag.XAxis 0793 drag.smoothed: false 0794 0795 onPressed: mouse => { 0796 root.autoScrolling = false 0797 root.trimInProgress = true; 0798 clipRoot.originalDuration = clipDuration 0799 anchors.right = undefined 0800 shiftTrim = mouse.modifiers & Qt.ShiftModifier 0801 controlTrim = mouse.modifiers & Qt.ControlModifier && itemType != ProducerType.Color && itemType != ProducerType.Timeline && itemType != ProducerType.Playlist && itemType != ProducerType.Image 0802 if (!shiftTrim && (clipRoot.grouped || controller.hasMultipleSelection())) { 0803 clipRoot.initGroupTrim(clipRoot.clipId) 0804 } 0805 if (root.activeTool === ProjectTool.RippleTool) { 0806 timeline.requestStartTrimmingMode(clipRoot.clipId, false, true); 0807 } 0808 0809 trimOut.opacity = 0 0810 } 0811 onReleased: { 0812 root.autoScrolling = timeline.autoScroll 0813 anchors.right = parent.right 0814 if (sizeChanged) { 0815 clipRoot.trimmedOut(clipRoot, shiftTrim, controlTrim) 0816 sizeChanged = false 0817 if (!controlTrim && root.activeTool !== ProjectTool.RippleTool) { 0818 updateDrag() 0819 } else { 0820 root.endDrag() 0821 } 0822 } else { 0823 if (root.activeTool === ProjectTool.RippleTool) { 0824 timeline.requestEndTrimmingMode(); 0825 } 0826 root.groupTrimData = undefined 0827 } 0828 root.trimInProgress = false; 0829 } 0830 onDoubleClicked: { 0831 timeline.mixClip(clipRoot.clipId, 1) 0832 } 0833 onPositionChanged: mouse => { 0834 if (mouse.buttons === Qt.LeftButton) { 0835 var newDuration = Math.round((x + width + itemBorder.border.width) / clipRoot.timeScale) 0836 if (maxDuration > 0 && (newDuration > maxDuration - inPoint) && !(mouse.modifiers & Qt.ControlModifier)) { 0837 newDuration = maxDuration - inPoint 0838 } 0839 if (newDuration != clipDuration) { 0840 sizeChanged = true 0841 clipRoot.trimmingOut(clipRoot, newDuration, shiftTrim, controlTrim) 0842 } 0843 } 0844 } 0845 onEntered: { 0846 if (!pressed && !root.isDragging()) { 0847 trimOut.opacity = 1 0848 var itemPos = mapToItem(tracksContainerArea, 0, 0, width, height) 0849 initDrag(clipRoot, itemPos, clipRoot.clipId, clipRoot.modelStart, clipRoot.trackId, false) 0850 var s = i18n("Out:%1, Position:%2", timeline.simplifiedTC(clipRoot.outPoint),timeline.simplifiedTC(clipRoot.modelStart + clipRoot.clipDuration)) 0851 timeline.showToolTip(s) 0852 if (!fadeOutMouseArea.containsMouse) { 0853 timeline.showKeyBinding(i18n("<b>Ctrl drag</b> to change speed, <b>Double click</b> to mix with adjacent clip")) 0854 } 0855 } 0856 } 0857 onExited: { 0858 trimOut.opacity = 0 0859 if (!pressed) { 0860 if (!mouseArea.containsMouse) { 0861 timeline.showToolTip() 0862 } else { 0863 var text = i18n("%1 (%2-%3), Position: %4, Duration: %5".arg(clipRoot.clipName) 0864 .arg(timeline.simplifiedTC(clipRoot.inPoint)) 0865 .arg(timeline.simplifiedTC(clipRoot.outPoint)) 0866 .arg(timeline.simplifiedTC(clipRoot.modelStart)) 0867 .arg(timeline.simplifiedTC(clipRoot.clipDuration))) 0868 timeline.showToolTip(text) 0869 } 0870 if (!fadeOutMouseArea.containsMouse) { 0871 timeline.showKeyBinding() 0872 } 0873 } 0874 } 0875 /*ToolTip { 0876 visible: trimOutMouseArea.containsMouse && !trimOutMouseArea.pressed 0877 delay: 1000 0878 timeout: 5000 0879 background: Rectangle { 0880 color: activePalette.alternateBase 0881 border.color: activePalette.light 0882 } 0883 contentItem: Label { 0884 color: activePalette.text 0885 font: miniFont 0886 text: i18n("Out: ") + timeline.simplifiedTC(clipRoot.outPoint) 0887 } 0888 }*/ 0889 Rectangle { 0890 id: trimOut 0891 anchors.right: parent.right 0892 width: itemBorder.border.width 0893 height: parent.height 0894 color: 'red' 0895 opacity: 0 0896 Drag.active: trimOutMouseArea.drag.active 0897 Drag.proposedAction: Qt.MoveAction 0898 visible: trimOutMouseArea.pressed || ((root.activeTool === ProjectTool.SelectTool || (root.activeTool === ProjectTool.RippleTool && clipRoot.mixDuration <= 0)) && !mouseArea.drag.active && parent.enabled) 0899 } 0900 } 0901 0902 TimelineTriangle { 0903 // Green fade in triangle 0904 id: fadeInTriangle 0905 fillColor: 'green' 0906 width: Math.min(clipRoot.fadeIn * clipRoot.timeScale, container.width) 0907 height: parent.height 0908 anchors.left: parent.left 0909 anchors.top: parent.top 0910 opacity: 0.4 0911 } 0912 0913 TimelineTriangle { 0914 // Red fade out triangle 0915 id: fadeOutCanvas 0916 fillColor: 'red' 0917 width: Math.min(clipRoot.fadeOut * clipRoot.timeScale, container.width) 0918 height: parent.height 0919 anchors.right: parent.right 0920 anchors.top: parent.top 0921 opacity: 0.4 0922 transform: Scale { xScale: -1; origin.x: fadeOutCanvas.width / 2} 0923 } 0924 0925 Item { 0926 // Clipping container for clip names 0927 id: nameContainer 0928 anchors.fill: parent 0929 anchors.leftMargin: clipRoot.scrollStart > 0 ? (mixContainer.width + labelRect.width > clipRoot.width ? mixContainer.width : Math.max(clipRoot.scrollStart, mixContainer.width + mixBackground.border.width)) : mixContainer.width + mixBackground.border.width 0930 clip: true 0931 Rectangle { 0932 // Debug: Clip Id background 0933 id: debugCidRect 0934 color: 'magenta' 0935 width: debugCid.width + (2 * itemBorder.border.width) 0936 height: debugCid.height 0937 visible: root.debugmode 0938 anchors.left: parent.left 0939 anchors.leftMargin: clipRoot.timeremap ? debugCidRect.height : 0 0940 Text { 0941 // Clip ID text 0942 id: debugCid 0943 text: clipRoot.clipId 0944 font: miniFont 0945 anchors { 0946 left: debugCidRect.left 0947 leftMargin: itemBorder.border.width 0948 } 0949 color: 'white' 0950 } 0951 } 0952 Rectangle { 0953 // Clip name background 0954 id: labelRect 0955 color: clipRoot.selected ? 'darkred' : '#66000000' 0956 width: label.width + (2 * itemBorder.border.width) 0957 height: label.height 0958 visible: clipRoot.width > root.baseUnit 0959 anchors.left: debugCidRect.visible ? debugCidRect.right : parent.left 0960 anchors.leftMargin: clipRoot.timeremap ? labelRect.height : 0 0961 Text { 0962 // Clip name text 0963 id: label 0964 property string clipNameString: (clipRoot.isAudio && clipRoot.multiStream) ? ((clipRoot.audioStream > 10000 ? 'Merged' : clipRoot.aStreamIndex) + '|' + clipName ) : clipName 0965 text: (clipRoot.speed != 1.0 ? ('[' + Math.round(clipRoot.speed*100) + '%] ') : '') + clipNameString 0966 font: miniFont 0967 anchors { 0968 left: labelRect.left 0969 leftMargin: itemBorder.border.width 0970 } 0971 color: 'white' 0972 //style: Text.Outline 0973 //styleColor: 'black' 0974 } 0975 } 0976 0977 Rectangle { 0978 // Offset info 0979 id: offsetRect 0980 color: 'darkgreen' 0981 width: offsetLabel.width + radius 0982 height: offsetLabel.height 0983 radius: height/3 0984 x: labelRect.width + 4 0985 y: 2 0986 visible: labelRect.visible && positionOffset != 0 0987 MouseArea { 0988 id: offsetArea 0989 hoverEnabled: true 0990 cursorShape: Qt.PointingHandCursor 0991 anchors.fill: parent 0992 onClicked: { 0993 clearAndMove(positionOffset) 0994 } 0995 onEntered: { 0996 var text = positionOffset < 0 ? i18n("Offset: -%1", timeline.simplifiedTC(-positionOffset)) : i18n("Offset: %1", timeline.simplifiedTC(positionOffset)) 0997 timeline.showToolTip(text) 0998 } 0999 onExited: { 1000 timeline.showToolTip() 1001 } 1002 Text { 1003 id: offsetLabel 1004 text: positionOffset 1005 font: miniFont 1006 anchors { 1007 horizontalCenter: parent.horizontalCenter 1008 topMargin: 1 1009 leftMargin: 1 1010 } 1011 color: 'white' 1012 style: Text.Outline 1013 styleColor: 'black' 1014 } 1015 } 1016 } 1017 1018 Rectangle { 1019 // effect names background 1020 id: effectsRect 1021 color: '#555555' 1022 width: effectLabel.width + effectsToggle.width + 4 1023 height: effectLabel.height 1024 anchors.top: labelRect.bottom 1025 anchors.left: labelRect.left 1026 visible: labelRect.visible && clipRoot.effectNames != '' && container.showDetails 1027 Rectangle { 1028 // effects toggle button background 1029 id: effectsToggle 1030 color: clipRoot.isStackEnabled ? '#fdbc4b' : 'black' 1031 visible: clipRoot.width > 2.5 * effectLabel.height 1032 width: visible ? effectsRect.height : 0 1033 height: effectsRect.height 1034 ToolButton { 1035 id: effectButton 1036 height: effectsRect.height 1037 width: effectsRect.height 1038 onClicked: { 1039 timeline.setEffectsEnabled(clipRoot.clipId, !clipRoot.isStackEnabled) 1040 } 1041 1042 icon { 1043 name: 'tools-wizard' 1044 color: clipRoot.isStackEnabled ? 'black' : 'white' 1045 height: effectLabel.height 1046 width: effectLabel.height 1047 } 1048 anchors { 1049 top: parent.top 1050 left: parent.left 1051 leftMargin: 1 1052 } 1053 } 1054 } 1055 Text { 1056 // Effect names text 1057 id: effectLabel 1058 text: clipRoot.effectNames 1059 font { 1060 family: miniFont.family 1061 pointSize: miniFont.pointSize 1062 strikeout: !clipRoot.isStackEnabled 1063 } 1064 visible: effectsRect.visible 1065 anchors { 1066 top: effectsToggle.top 1067 left: effectsToggle.right 1068 leftMargin: 2 1069 rightMargin: 2 1070 // + ((isAudio || !settings.timelineShowThumbnails) ? 0 : inThumbnail.width) + 1 1071 } 1072 color: 'white' 1073 //style: Text.Outline 1074 styleColor: 'black' 1075 } 1076 } 1077 Rectangle{ 1078 //proxy 1079 id: proxyRect 1080 color: '#fdbc4b' 1081 width: labelRect.height 1082 height: labelRect.height 1083 anchors.top: labelRect.top 1084 anchors.left: labelRect.right 1085 visible: !clipRoot.isAudio && clipRoot.clipStatus === ClipStatus.StatusProxy || clipRoot.clipStatus === ClipStatus.StatusProxyOnly 1086 Text { 1087 // Proxy P 1088 id: proxyLabel 1089 text: "P" 1090 font.pointSize: root.fontUnit +1 1091 visible: proxyRect.visible 1092 anchors { 1093 top: proxyRect.top 1094 left: proxyRect.left 1095 leftMargin: (labelRect.height-proxyLabel.width)/2 1096 topMargin: (labelRect.height-proxyLabel.height)/2 1097 } 1098 color: 'black' 1099 styleColor: 'black' 1100 } 1101 } 1102 Rectangle{ 1103 //remap 1104 id:remapRect 1105 color: '#cc0033' 1106 width: labelRect.height 1107 height: labelRect.height 1108 anchors.top: labelRect.top 1109 anchors.left: nameContainer.left 1110 visible: clipRoot.timeremap 1111 Text { 1112 // Remap R 1113 id: remapLabel 1114 text: "R" 1115 font.pointSize: root.fontUnit +1 1116 visible: remapRect.visible 1117 anchors { 1118 top: remapRect.top 1119 left: remapRect.left 1120 leftMargin: (labelRect.height-proxyLabel.width)/2 1121 topMargin: (labelRect.height-proxyLabel.height)/2 1122 } 1123 color: 'white' 1124 styleColor: 'white' 1125 } 1126 } 1127 } 1128 1129 Loader { 1130 // keyframes container 1131 id: effectRow 1132 clip: true 1133 anchors.fill: parent 1134 asynchronous: true 1135 visible: status == Loader.Ready && clipRoot.showKeyframes && clipRoot.keyframeModel && clipRoot.width > 2 * root.baseUnit 1136 source: clipRoot.hideClipViews || clipRoot.keyframeModel == undefined ? "" : "KeyframeView.qml" 1137 Binding { 1138 target: effectRow.item 1139 property: "kfrModel" 1140 value: clipRoot.hideClipViews ? undefined : clipRoot.keyframeModel 1141 when: effectRow.status == Loader.Ready && effectRow.item 1142 restoreMode: Binding.RestoreBindingOrValue 1143 } 1144 Binding { 1145 target: effectRow.item 1146 property: "selected" 1147 value: clipRoot.selected 1148 when: effectRow.status == Loader.Ready && effectRow.item 1149 restoreMode: Binding.RestoreBindingOrValue 1150 } 1151 Binding { 1152 target: effectRow.item 1153 property: "inPoint" 1154 value: clipRoot.inPoint 1155 when: effectRow.status == Loader.Ready && effectRow.item 1156 restoreMode: Binding.RestoreBindingOrValue 1157 } 1158 Binding { 1159 target: effectRow.item 1160 property: "outPoint" 1161 value: clipRoot.outPoint 1162 when: effectRow.status == Loader.Ready && effectRow.item 1163 restoreMode: Binding.RestoreBindingOrValue 1164 } 1165 Binding { 1166 target: effectRow.item 1167 property: "modelStart" 1168 value: clipRoot.modelStart 1169 when: effectRow.status == Loader.Ready && effectRow.item 1170 restoreMode: Binding.RestoreBindingOrValue 1171 } 1172 Binding { 1173 target: effectRow.item 1174 property: "scrollStart" 1175 value: clipRoot.scrollStart 1176 when: effectRow.status == Loader.Ready && effectRow.item 1177 restoreMode: Binding.RestoreBindingOrValue 1178 } 1179 Binding { 1180 target: effectRow.item 1181 property: "clipId" 1182 value: clipRoot.clipId 1183 when: effectRow.status == Loader.Ready && effectRow.item 1184 restoreMode: Binding.RestoreBindingOrValue 1185 } 1186 } 1187 Connections { 1188 target: effectRow.item 1189 function onSeek(position) { proxy.position = position } 1190 } 1191 } 1192 1193 states: [ 1194 State { 1195 name: 'locked' 1196 when: isLocked 1197 PropertyChanges { 1198 target: clipRoot 1199 color: root.lockedColor 1200 opacity: 0.8 1201 z: 0 1202 } 1203 }, 1204 State { 1205 name: 'normal' 1206 when: clipRoot.selected === false 1207 PropertyChanges { 1208 target: clipRoot 1209 color: Qt.darker(getColor(), 1.5) 1210 z: 0 1211 } 1212 }, 1213 State { 1214 name: 'selectedClip' 1215 when: clipRoot.selected === true 1216 PropertyChanges { 1217 target: clipRoot 1218 color: getColor() 1219 z: 3 1220 } 1221 } 1222 ] 1223 1224 MouseArea { 1225 // Add start composition area 1226 id: compInArea 1227 anchors.left: parent.left 1228 anchors.bottom: parent.bottom 1229 width: Math.min(root.baseUnit, container.height / 3) 1230 height: width 1231 hoverEnabled: true 1232 cursorShape: Qt.PointingHandCursor 1233 visible: !clipRoot.isAudio 1234 enabled: !clipRoot.isAudio && dragProxy.draggedItem === clipRoot.clipId && compositionIn.visible 1235 onPressed: { 1236 root.mainItemId = -1 1237 timeline.addCompositionToClip('', clipRoot.clipId, 0) 1238 } 1239 onEntered: { 1240 timeline.showKeyBinding(i18n("<b>Click</b> to add composition")) 1241 } 1242 onExited: { 1243 timeline.showKeyBinding() 1244 } 1245 Rectangle { 1246 // Start composition box 1247 id: compositionIn 1248 anchors.bottom: parent.bottom 1249 anchors.left: parent.left 1250 width: compInArea.containsMouse ? parent.width : 5 1251 height: width 1252 radius: width / 2 1253 visible: clipRoot.width > 4 * parent.width && mouseArea.containsMouse && !dragProxyArea.pressed 1254 color: Qt.darker('mediumpurple') 1255 border.width: 3 1256 border.color: 'mediumpurple' 1257 Behavior on width { NumberAnimation { duration: 100 } } 1258 } 1259 } 1260 1261 MouseArea { 1262 // Add end composition area 1263 id: compOutArea 1264 anchors.right: parent.right 1265 anchors.bottom: parent.bottom 1266 width: Math.min(root.baseUnit, container.height / 3) 1267 height: width 1268 hoverEnabled: true 1269 cursorShape: Qt.PointingHandCursor 1270 enabled: !clipRoot.isAudio && dragProxy.draggedItem === clipRoot.clipId && compositionOut.visible 1271 visible: !clipRoot.isAudio 1272 onPressed: { 1273 root.mainItemId = -1 1274 timeline.addCompositionToClip('', clipRoot.clipId, clipRoot.clipDuration - 1) 1275 } 1276 onEntered: { 1277 timeline.showKeyBinding(i18n("<b>Click</b> to add composition")) 1278 } 1279 onExited: { 1280 timeline.showKeyBinding() 1281 } 1282 Rectangle { 1283 // End composition box 1284 id: compositionOut 1285 anchors.bottom: parent.bottom 1286 anchors.right: parent.right 1287 width: compOutArea.containsMouse ? parent.height : 5 1288 height: width 1289 radius: width / 2 1290 visible: clipRoot.width > 4 * parent.width && mouseArea.containsMouse && !dragProxyArea.pressed 1291 color: Qt.darker('mediumpurple') 1292 border.width: 3 1293 border.color: 'mediumpurple' 1294 Behavior on width { NumberAnimation { duration: 100 } } 1295 } 1296 } 1297 1298 MouseArea { 1299 // Fade out drag zone 1300 id: fadeOutMouseArea 1301 anchors.right: parent.right 1302 anchors.rightMargin: clipRoot.fadeOut <= 0 ? 0 : fadeOutCanvas.width - width / 2 1303 anchors.top: parent.top 1304 width: Math.min(root.baseUnit, container.height / 3) 1305 height: width 1306 hoverEnabled: true 1307 cursorShape: Qt.PointingHandCursor 1308 drag.target: fadeOutMouseArea 1309 drag.axis: Drag.XAxis 1310 drag.minimumX: - Math.ceil(width / 2) 1311 drag.maximumX: container.width + Math.ceil(width / 4) 1312 visible: container.handleVisible && mouseArea.containsMouse && !dragProxyArea.pressed 1313 property int startFadeOut 1314 property int lastDuration: -1 1315 property int startMousePos 1316 property bool dragStarted: false 1317 property string fadeString: timeline.simplifiedTC(clipRoot.fadeOut) 1318 drag.smoothed: false 1319 onClicked: { 1320 if (clipRoot.fadeOut == 0) { 1321 timeline.adjustFade(clipRoot.clipId, 'fadeout', 0, -2) 1322 } 1323 } 1324 onPressed: { 1325 root.autoScrolling = false 1326 startFadeOut = clipRoot.fadeOut 1327 dragStarted = startFadeOut > 0 1328 startMousePos = mouse.x 1329 anchors.right = undefined 1330 fadeOutCanvas.opacity = 0.6 1331 } 1332 onReleased: { 1333 fadeOutCanvas.opacity = 0.4 1334 root.autoScrolling = timeline.autoScroll 1335 anchors.right = parent.right 1336 var duration = clipRoot.fadeOut 1337 timeline.adjustFade(clipRoot.clipId, 'fadeout', duration, startFadeOut) 1338 //bubbleHelp.hide() 1339 timeline.showToolTip() 1340 } 1341 onPositionChanged: mouse => { 1342 if (mouse.buttons === Qt.LeftButton) { 1343 if (!dragStarted && startMousePos - mouse.x < 3) { 1344 return 1345 } 1346 dragStarted = true 1347 var delta = clipRoot.clipDuration - Math.floor((x + width / 2 - itemBorder.border.width)/ clipRoot.timeScale) 1348 var duration = Math.max(0, delta) 1349 duration = Math.min(duration, clipRoot.clipDuration) 1350 if (lastDuration != duration) { 1351 lastDuration = duration 1352 timeline.adjustFade(clipRoot.clipId, 'fadeout', duration, -1) 1353 // Show fade duration as time in a "bubble" help. 1354 timeline.showToolTip(i18n("Fade out: %1", fadeString)) 1355 } 1356 } 1357 } 1358 onEntered: { 1359 if (!pressed) { 1360 if (clipRoot.fadeOut > 0) { 1361 timeline.showToolTip(i18n("Fade out: %1", fadeString)) 1362 } else { 1363 clipRoot.showClipInfo() 1364 } 1365 timeline.showKeyBinding(i18n("<b>Drag</b> to adjust fade, <b>Click</b> to add default duration fade")) 1366 } 1367 } 1368 onExited: { 1369 if (!pressed) { 1370 timeline.showKeyBinding() 1371 if (mouseArea.containsMouse) { 1372 clipRoot.showClipInfo() 1373 } else { 1374 timeline.showToolTip() 1375 } 1376 } 1377 } 1378 Rectangle { 1379 id: fadeOutControl 1380 anchors.top: parent.top 1381 anchors.right: clipRoot.fadeOut > 0 ? undefined : parent.right 1382 anchors.horizontalCenter: clipRoot.fadeOut > 0 ? parent.horizontalCenter : undefined 1383 width: fadeOutMouseArea.containsMouse || Drag.active ? parent.width : parent.width / 3 1384 height: width 1385 radius: width / 2 1386 color: 'darkred' 1387 border.width: 3 1388 border.color: 'red' 1389 enabled: !isLocked && !dragProxy.isComposition 1390 Drag.active: fadeOutMouseArea.drag.active 1391 Behavior on width { NumberAnimation { duration: 100 } } 1392 Rectangle { 1393 id: fadeOutMarker 1394 anchors.horizontalCenter: parent.horizontalCenter 1395 anchors.top: parent.top 1396 color: 'red' 1397 height: container.height 1398 width: 1 1399 visible : clipRoot.fadeOut > 0 && (fadeOutMouseArea.containsMouse || fadeOutMouseArea.drag.active) 1400 } 1401 } 1402 ToolTip.visible: (containsMouse || pressed || drag.active) 1403 ToolTip.delay: (pressed || drag.active) ? 0 : 1000 1404 ToolTip.text: fadeString 1405 } 1406 1407 MouseArea { 1408 // Fade in drag zone 1409 id: fadeInMouseArea 1410 anchors.left: container.left 1411 anchors.leftMargin: clipRoot.fadeIn <= 0 ? 0 : (fadeInTriangle.width - width / 3) 1412 anchors.top: parent.top 1413 width: Math.min(root.baseUnit, container.height / 3) 1414 height: width 1415 hoverEnabled: true 1416 cursorShape: Qt.PointingHandCursor 1417 drag.target: fadeInMouseArea 1418 drag.minimumX: - Math.ceil(width / 2) 1419 drag.maximumX: container.width - width / 2 1420 drag.axis: Drag.XAxis 1421 drag.smoothed: false 1422 property int startFadeIn 1423 property int startMousePos 1424 property bool dragStarted: false 1425 property string fadeString: timeline.simplifiedTC(clipRoot.fadeIn) 1426 visible: container.handleVisible && mouseArea.containsMouse && !dragProxyArea.pressed 1427 onClicked: { 1428 if (clipRoot.fadeIn == 0) { 1429 timeline.adjustFade(clipRoot.clipId, 'fadein', 0, -2) 1430 } 1431 } 1432 onPressed: mouse => { 1433 root.autoScrolling = false 1434 startFadeIn = clipRoot.fadeIn 1435 dragStarted = startFadeIn > 0 1436 startMousePos = mouse.x 1437 anchors.left = undefined 1438 fadeInTriangle.opacity = 0.6 1439 // parentTrack.clipSelected(clipRoot, parentTrack) TODO 1440 } 1441 onReleased: { 1442 root.autoScrolling = timeline.autoScroll 1443 fadeInTriangle.opacity = 0.4 1444 timeline.adjustFade(clipRoot.clipId, 'fadein', clipRoot.fadeIn, startFadeIn) 1445 //bubbleHelp.hide() 1446 timeline.showToolTip() 1447 anchors.left = container.left 1448 } 1449 onPositionChanged: mouse => { 1450 if (mouse.buttons === Qt.LeftButton) { 1451 if (!dragStarted && mouse.x - startMousePos < 3) { 1452 return 1453 } 1454 dragStarted = true 1455 var delta = Math.round((x + width / 2) / clipRoot.timeScale) 1456 var duration = Math.max(0, delta) 1457 duration = Math.min(duration, clipRoot.clipDuration - 1) 1458 if (duration != clipRoot.fadeIn) { 1459 timeline.adjustFade(clipRoot.clipId, 'fadein', duration, -1) 1460 // Show fade duration as time in a "bubble" help. 1461 timeline.showToolTip(i18n("Fade in: %1", fadeString)) 1462 } 1463 } 1464 } 1465 onEntered: { 1466 if (!pressed) { 1467 if (clipRoot.fadeIn > 0) { 1468 timeline.showToolTip(i18n("Fade in: %1", fadeString)) 1469 } else { 1470 clipRoot.showClipInfo() 1471 } 1472 timeline.showKeyBinding(i18n("<b>Drag</b> to adjust fade, <b>Click</b> to add default duration fade")) 1473 } 1474 } 1475 onExited: { 1476 if (!pressed) { 1477 timeline.showKeyBinding() 1478 if (mouseArea.containsMouse) { 1479 clipRoot.showClipInfo() 1480 } else { 1481 timeline.showToolTip() 1482 } 1483 } 1484 } 1485 Rectangle { 1486 id: fadeInControl 1487 anchors.top: parent.top 1488 anchors.left: clipRoot.fadeIn > 0 ? undefined : parent.left 1489 anchors.horizontalCenter: clipRoot.fadeIn > 0 ? parent.horizontalCenter : undefined 1490 width: fadeInMouseArea.containsMouse || Drag.active ? parent.width : parent.width / 3 1491 height: width 1492 radius: width / 2 1493 color: 'green' 1494 border.width: 3 1495 border.color: '#FF66FFFF' 1496 enabled: !isLocked && !dragProxy.isComposition 1497 Drag.active: fadeInMouseArea.drag.active 1498 Behavior on width { NumberAnimation { duration: 100 } } 1499 Rectangle { 1500 id: fadeInMarker 1501 anchors.horizontalCenter: parent.horizontalCenter 1502 anchors.top: parent.top 1503 color: '#FF66FFFF' 1504 height: container.height 1505 width: 1 1506 visible : clipRoot.fadeIn > 0 && (fadeInMouseArea.containsMouse || fadeInMouseArea.drag.active) 1507 } 1508 } 1509 ToolTip.visible: (containsMouse || pressed || drag.active) 1510 ToolTip.delay: (pressed || drag.active) ? 0 : 1000 1511 ToolTip.text: fadeString 1512 } 1513 1514 Rectangle { 1515 id: currentRegion 1516 color: slipControler.color 1517 anchors { 1518 right: container.right 1519 left: container.left 1520 top: slipControler.top 1521 } 1522 height: container.height / 2 1523 opacity: 0.7 1524 visible: slipControler.visible 1525 } 1526 Item { 1527 id: slipControler 1528 property color color: timeline.trimmingMainClip === clipId ? root.selectionColor : activePalette.highlight 1529 anchors.bottom: container.bottom 1530 height: container.height 1531 width: clipRoot.maxDuration * clipRoot.timeScale 1532 x: - (clipRoot.inPoint - slipOffset) * clipRoot.timeScale 1533 visible: root.activeTool === ProjectTool.SlipTool && clipRoot.selected && clipRoot.maxDuration > 0 // don't show for endless clips 1534 property int inPoint: clipRoot.inPoint 1535 property int outPoint: clipRoot.outPoint 1536 Rectangle { 1537 id: slipBackground 1538 anchors.fill: parent 1539 color: parent.color 1540 border.width: 2 1541 border.color: activePalette.highlightedText 1542 opacity: 0.3 1543 } 1544 Rectangle { 1545 id: currentRegionMoved 1546 color: parent.color 1547 x: slipBackground.x + slipControler.inPoint * clipRoot.timeScale + itemBorder.border.width 1548 anchors.bottom: parent.bottom 1549 height: parent.height / 2 1550 width: container.width 1551 opacity: 0.7 1552 } 1553 Text { 1554 id: slipLable 1555 text: i18n("Slip Clip") 1556 font: miniFont 1557 anchors.fill: parent 1558 verticalAlignment: Text.AlignVCenter 1559 horizontalAlignment: Text.AlignHCenter 1560 color: activePalette.highlightedText 1561 opacity: 1 1562 } 1563 } 1564 } 1565 }