Warning, /multimedia/kdenlive/src/timeline2/view/qml/SubTitle.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2020-2021 Jean-Baptiste Mardelle
0003     SPDX-FileCopyrightText: 2020 Sashmita Raghav
0004 
0005     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 import QtQuick 2.15
0008 import QtQuick.Controls 2.15
0009 import com.enums 1.0
0010 
0011 Item {
0012     id: subtitleRoot
0013     visible : true
0014     z: selected ? 30 : 20
0015     property int oldStartX
0016     property int startFrame
0017     property int endFrame
0018     property int subId
0019     property int duration : endFrame - startFrame
0020     property double tScale: root.timeScale
0021     property string subtitle
0022     property bool selected
0023     property bool isGrabbed: false
0024     height: subtitleTrack.height
0025     
0026     function editText()
0027     {
0028         subtitleBase.textEditBegin = true
0029     }
0030 
0031     onStartFrameChanged: {
0032         if (!subtitleClipArea.pressed) {
0033             subtitleClipArea.x = startFrame * root.timeScale
0034         }
0035     }
0036 
0037     onTScaleChanged: {
0038         subtitleClipArea.x = startFrame * root.timeScale;
0039     }
0040 
0041     onIsGrabbedChanged: {
0042         if (subtitleRoot.isGrabbed) {
0043             grabItem()
0044         } else {
0045             timeline.showToolTip()
0046             subtitleClipArea.focus = false
0047         }
0048     }
0049 
0050     onSelectedChanged: {
0051         if (!selected && isGrabbed) {
0052             //timeline.grabCurrent()
0053         }
0054         if (subtitleBase.textEditBegin) {
0055             // End editing on focus change
0056             subtitleBase.textEditBegin = false
0057         }
0058     }
0059 
0060     function grabItem() {
0061         subtitleClipArea.forceActiveFocus()
0062         subtitleClipArea.focus = true
0063     }
0064 
0065     MouseArea {
0066             // Clip shifting
0067             id: subtitleClipArea
0068             x: startFrame * root.timeScale
0069             height: parent.height
0070             width: subtitleBase.width
0071             hoverEnabled: true
0072             enabled: true
0073             property int newStart: -1
0074             property int diff: -1
0075             property int oldStartFrame
0076             property int snappedFrame
0077             // Used for continuous scrolling
0078             property int incrementalOffset
0079             property double delta: -1
0080             property double oldDelta: 0
0081             property bool startMove: false
0082             visible: root.activeTool === 0
0083             acceptedButtons: Qt.LeftButton | Qt.RightButton
0084             cursorShape: (pressed ? Qt.ClosedHandCursor : ((startMouseArea.drag.active || endMouseArea.drag.active)? Qt.SizeHorCursor: Qt.PointingHandCursor));
0085             drag.axis: Drag.XAxis
0086             drag.smoothed: false
0087             drag.minimumX: 0
0088             onEntered: {
0089                 console.log('ENTERED SUBTITLE MOUSE AREA')
0090                 timeline.showKeyBinding(i18n("<b>Double click</b> to edit text"))
0091             }
0092             onExited: {
0093                 timeline.showKeyBinding()
0094             }
0095             onPressed: mouse => {
0096                 console.log('ENTERED ITEM CLCKD:', subtitleRoot.subtitle, ' ID: ', subtitleRoot.subId, 'START FRM: ', subtitleRoot.startFrame)
0097                 root.autoScrolling = false
0098                 oldStartX = scrollView.contentX + mapToItem(scrollView, mouseX, 0).x
0099                 oldStartFrame = subtitleRoot.startFrame
0100                 snappedFrame = oldStartFrame
0101                 x = subtitleBase.x
0102                 startMove = mouse.button & Qt.LeftButton
0103                 if (startMove) {
0104                     root.subtitleMoving = true
0105                     root.subtitleItem = subtitleClipArea
0106                     incrementalOffset = 0
0107                 }
0108                 if (timeline.selection.indexOf(subtitleRoot.subId) === -1) {
0109                     controller.requestAddToSelection(subtitleRoot.subId, !(mouse.modifiers & Qt.ShiftModifier))
0110                     timeline.showAsset(subtitleRoot.subId);
0111                 } else if (mouse.modifiers & Qt.ShiftModifier) {
0112                     console.log('REMOVE FROM SELECTION!!!!')
0113                     controller.requestRemoveFromSelection(subtitleRoot.subId)
0114                 } else {
0115                     timeline.showAsset(subtitleRoot.subId)
0116                 }
0117                 timeline.activeTrack = -2
0118             }
0119             function checkOffset(offset) {
0120                 if (pressed && !subtitleBase.textEditBegin && startMove) {
0121                     incrementalOffset += offset
0122                     newStart = Math.max(0, oldStartFrame + (scrollView.contentX + mapToItem(scrollView,mouseX, 0).x + incrementalOffset - oldStartX)/ root.timeScale)
0123                     snappedFrame = controller.suggestSubtitleMove(subtitleRoot.subId, newStart, root.consumerPosition, root.snapping)
0124                     root.continuousScrolling(scrollView.contentX + mapToItem(scrollView, mouseX, 0).x + incrementalOffset, 0)
0125                 }
0126             }
0127             onPositionChanged: {
0128                 incrementalOffset = 0
0129                 checkOffset(0)
0130             }
0131             onReleased: mouse => {
0132                 root.autoScrolling = timeline.autoScroll
0133                 root.subtitleMoving = false
0134                 root.subtitleItem = undefined
0135                 if (subtitleBase.textEditBegin) {
0136                     mouse.accepted = false
0137                     return
0138                 }
0139                 if (startMove) {
0140                     startMove = false
0141                     if (subtitleBase.x < 0)
0142                         subtitleBase.x = 0
0143                     if (oldStartFrame != snappedFrame) {
0144                         console.log("old start frame",oldStartFrame/timeline.scaleFactor, "new frame after shifting ",oldStartFrame/timeline.scaleFactor + delta)
0145                         controller.requestSubtitleMove(subtitleRoot.subId, oldStartFrame, false, false);
0146                         controller.requestSubtitleMove(subtitleRoot.subId, snappedFrame, true, true, true);
0147                         x = snappedFrame * root.timeScale
0148                     }
0149                 }
0150                 console.log('RELEASED DONE\n\n_______________')
0151             }
0152             onClicked: mouse => {
0153                 if (mouse.button == Qt.RightButton) {
0154                     //console.log('RIGHT BUTTON CLICKED')
0155                     root.showSubtitleClipMenu()
0156                 }
0157             }
0158             onDoubleClicked: {
0159                 subtitleBase.textEditBegin = true
0160             }
0161             Keys.onShortcutOverride: event => {
0162                 event.accepted = subtitleRoot.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)
0163             }
0164             Keys.onLeftPressed: event => {
0165                 var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1
0166                 if (controller.requestSubtitleMove(subtitleRoot.subId, subtitleRoot.startFrame - offset, true, true)) {
0167                     timeline.showToolTip(i18n("Position: %1", timeline.simplifiedTC(subtitleRoot.startFrame)));
0168                 }
0169             }
0170             Keys.onRightPressed: event => {
0171                 var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1
0172                 if (controller.requestSubtitleMove(subtitleRoot.subId, subtitleRoot.startFrame + offset, true, true)) {
0173                     timeline.showToolTip(i18n("Position: %1", timeline.simplifiedTC(subtitleRoot.startFrame)));
0174                 }
0175             }
0176             /*Keys.onUpPressed: {
0177                 controller.requestClipMove(subtitleRoot.subId, controller.getNextTrackId(subtitleRoot.trackId), subtitleRoot.startFrame, true, true, true);
0178             }
0179             Keys.onDownPressed: {
0180                 controller.requestClipMove(subtitleRoot.subId, controller.getPreviousTrackId(subtitleRoot.trackId), subtitleRoot.startFrame, true, true, true);
0181             }*/
0182             Keys.onEscapePressed: {
0183                 timeline.grabCurrent()
0184                 //focus = false
0185             }
0186         }
0187     Item {
0188         id: subtitleBase
0189         property bool textEditBegin: false
0190         height: subtitleTrack.height
0191         width: duration * root.timeScale // to make width change wrt timeline scale factor
0192         x: startFrame * root.timeScale;
0193         clip: true
0194         TextField {
0195             id: subtitleEdit
0196             font: miniFont
0197             activeFocusOnPress: true
0198             selectByMouse: true
0199             onEditingFinished: {
0200                 subtitleEdit.focus = false
0201                 parent.textEditBegin = false
0202                 if (subtitleRoot.subtitle != subtitleEdit.text) {
0203                     subtitleModel.editSubtitle(subtitleRoot.subId, subtitleEdit.text, subtitleRoot.subtitle)
0204                 }
0205             }
0206             anchors.fill: parent
0207             //visible: timeScale >= 6
0208             enabled: parent.textEditBegin
0209             opacity: root.subtitlesDisabled ? 0.5 : 1
0210             onEnabledChanged: {
0211                 if (enabled) {
0212                     selectAll()
0213                     focus = true
0214                     forceActiveFocus()
0215                 }
0216             }
0217             text: subtitleRoot.subtitle
0218             height: subtitleBase.height
0219             width: subtitleBase.width
0220             wrapMode: TextField.WordWrap
0221             horizontalAlignment: displayText == text ? TextInput.AlignHCenter : TextInput.AlignLeft
0222             background: Rectangle {
0223                 color: root.subtitlesLocked ? "#ff6666" : enabled ? "#fff" : '#ccccff'
0224                 border {
0225                     color: subtitleRoot.selected ? root.selectionColor : "#000"
0226                     width: subtitleRoot.isGrabbed ? 8 : 2
0227                 }
0228             }
0229             color: 'black'
0230             padding: 0
0231         }
0232     }
0233     Item {
0234         // start position resize handle
0235         id: leftstart
0236         width: root.baseUnit / 2
0237         height: subtitleBase.height
0238         anchors.top: subtitleBase.top
0239         anchors.left: subtitleBase.left
0240         visible: true
0241         MouseArea {
0242             // Left resize handle to change start timing
0243             id: startMouseArea
0244             anchors.fill: parent
0245             hoverEnabled: true
0246             enabled: true
0247             visible: root.activeTool === 0
0248             property int newStart: subtitleRoot.startFrame
0249             property int newDuration: subtitleRoot.duration
0250             property int originalDuration: subtitleRoot.duration
0251             property int oldMouseX
0252             property int oldStartFrame: 0
0253             property bool shiftTrim: false
0254             acceptedButtons: Qt.LeftButton
0255             drag.axis: Drag.XAxis
0256             drag.smoothed: false
0257             cursorShape: containsMouse || pressed ? Qt.SizeHorCursor : Qt.ClosedHandCursor;
0258             drag.target: leftstart
0259             onPressed: mouse => {
0260                 root.autoScrolling = false
0261                 oldMouseX = mouseX
0262                 leftstart.anchors.left = undefined
0263                 oldStartFrame = subtitleRoot.startFrame // the original start frame of subtitle
0264                 originalDuration = subtitleRoot.duration
0265                 newDuration = subtitleRoot.duration
0266                 trimIn.opacity = 0
0267                 shiftTrim = mouse.modifiers & Qt.ShiftModifier
0268                 if (!shiftTrim && (controller.isInGroup(subtitleRoot.subId) || controller.hasMultipleSelection())) {
0269                     root.groupTrimData = controller.getGroupData(subtitleRoot.subId)
0270                 }
0271             }
0272             onPositionChanged: {
0273                 if (pressed) {
0274                     newDuration = subtitleRoot.endFrame - Math.round(leftstart.x / root.timeScale)
0275                     if (newDuration != originalDuration && subtitleBase.x >= 0) {
0276                         var frame = controller.requestItemResize(subtitleRoot.subId, newDuration , false, false, root.snapping, shiftTrim);
0277                         if (frame > 0) {
0278                             newStart = subtitleRoot.endFrame - frame
0279                         }
0280                     }
0281                 }
0282             }
0283             onReleased: {
0284                 //console.log('its RELEASED')
0285                 root.autoScrolling = timeline.autoScroll
0286                 leftstart.anchors.left = subtitleBase.left
0287                 if (oldStartFrame != newStart) {
0288                     if (shiftTrim || (root.groupTrimData == undefined || root.activeTool === ProjectTool.RippleTool)) {
0289                         controller.requestItemResize(subtitleRoot.subId, subtitleRoot.endFrame - oldStartFrame, false, false);
0290                         controller.requestItemResize(subtitleRoot.subId, subtitleRoot.endFrame - newStart, false, true, -1, shiftTrim);
0291                     } else {
0292                         var updatedGroupData = controller.getGroupData(subtitleRoot.subId)
0293                         controller.processGroupResize(root.groupTrimData, updatedGroupData, false)
0294                     }
0295                 }
0296                 root.groupTrimData = undefined
0297             }
0298             onEntered: {
0299                 if (!pressed) {
0300                     trimIn.opacity = 1
0301                     timeline.showKeyBinding(i18n("<b>Drag</b> to resize"))
0302                 }
0303             }
0304             onExited: {
0305                 trimIn.opacity = 0
0306                 if (!subtitleClipArea.containsMouse) {
0307                     timeline.showKeyBinding()
0308                 }
0309             }
0310 
0311             Rectangle {
0312                 id: trimIn
0313                 anchors.left: parent.left
0314                 width: 2
0315                 height: parent.height
0316                 color: 'lawngreen'
0317                 opacity: 0
0318                 Drag.active: startMouseArea.drag.active
0319                 Drag.proposedAction: Qt.MoveAction
0320                 //visible: startMouseArea.pressed
0321             }
0322         }
0323     }
0324     
0325     Item {
0326         // end position resize handle
0327         id: rightend
0328         width: root.baseUnit / 2
0329         height: subtitleBase.height
0330         //x: subtitleRoot.endFrame * timeScale
0331         anchors.right: subtitleBase.right
0332         anchors.top: subtitleBase.top
0333         //Drag.active: endMouseArea.drag.active
0334         //Drag.proposedAction: Qt.MoveAction
0335         visible: true
0336         MouseArea {
0337             // Right resize handle to change end timing
0338             id: endMouseArea
0339             anchors.fill: parent
0340             hoverEnabled: true
0341             enabled: true
0342             visible: root.activeTool === 0
0343             property bool sizeChanged: false
0344             property int oldMouseX
0345             acceptedButtons: Qt.LeftButton
0346             property int newDuration: subtitleRoot.duration
0347             property int originalDuration
0348             property bool shiftTrim: false
0349             cursorShape: containsMouse || pressed ? Qt.SizeHorCursor : Qt.ClosedHandCursor;
0350             drag.target: rightend
0351             drag.axis: Drag.XAxis
0352             drag.smoothed: false
0353 
0354             onPressed: mouse => {
0355                 root.autoScrolling = false
0356                 newDuration = subtitleRoot.duration
0357                 originalDuration = subtitleRoot.duration
0358                 //rightend.anchors.right = undefined
0359                 oldMouseX = mouseX
0360                 trimOut.opacity = 0
0361                 shiftTrim = mouse.modifiers & Qt.ShiftModifier
0362                 if (!shiftTrim && (controller.isInGroup(subtitleRoot.subId) || controller.hasMultipleSelection())) {
0363                     root.groupTrimData = controller.getGroupData(subtitleRoot.subId)
0364                 }
0365             }
0366             onPositionChanged: {
0367                 if (pressed) {
0368                     if ((mouseX != oldMouseX && duration > 1) || (duration <= 1 && mouseX > oldMouseX)) {
0369                         sizeChanged = true
0370                         //duration = subtitleBase.width + (mouseX - oldMouseX)/ timeline.scaleFactor
0371                         newDuration = Math.round((subtitleBase.width + mouseX - oldMouseX)/timeScale)
0372                         // Perform resize without changing model
0373                         var frame = controller.requestItemResize(subtitleRoot.subId, newDuration , true, false, root.snapping, shiftTrim);
0374                         if (frame > 0) {
0375                             newDuration = frame
0376                         }
0377                     }
0378                 }
0379             }
0380             onReleased: {
0381                 root.autoScrolling = timeline.autoScroll
0382                 rightend.anchors.right = subtitleBase.right
0383                 console.log(' GOT RESIZE: ', newDuration, ' > ', originalDuration)
0384                 if (mouseX != oldMouseX || sizeChanged) {
0385                     if (shiftTrim || (root.groupTrimData == undefined || root.activeTool === ProjectTool.RippleTool)) {
0386                         // Restore original size
0387                         controller.requestItemResize(subtitleRoot.subId, originalDuration , true, false);
0388                         // Perform real resize
0389                         controller.requestItemResize(subtitleRoot.subId, newDuration , true, true, -1, shiftTrim)
0390                     } else {
0391                         var updatedGroupData = controller.getGroupData(subtitleRoot.subId)
0392                         controller.processGroupResize(root.groupTrimData, updatedGroupData, true)
0393                     }
0394                     sizeChanged = false
0395                 }
0396                 root.groupTrimData = undefined
0397             }
0398             onEntered: {
0399                 console.log('ENTER MOUSE END AREA')
0400                 if (!pressed) {
0401                     trimOut.opacity = 1
0402                     timeline.showKeyBinding(i18n("<b>Drag</b> to resize"))
0403                 }
0404             }
0405             onExited: {
0406                 trimOut.opacity = 0
0407                 if (!subtitleClipArea.containsMouse) {
0408                     timeline.showKeyBinding()
0409                 }
0410             }
0411 
0412             Rectangle {
0413                 id: trimOut
0414                 anchors.right: parent.right
0415                 width: 2
0416                 height: parent.height
0417                 color: 'red'
0418                 opacity: 0
0419                 Drag.active: endMouseArea.drag.active
0420                 Drag.proposedAction: Qt.MoveAction
0421                 //visible: endMouseArea.pressed
0422             }
0423         }
0424     }
0425 }