Track.qml 14.7 KB
Newer Older
luyikei's avatar
luyikei committed
1 2 3 4
import QtQuick 2.0

Item {
    id: track
5
    width: parent.width
luyikei's avatar
luyikei committed
6 7 8 9 10 11 12
    height: trackHeight
    z: 10

    property int trackId
    property string type
    property ListModel clips

13 14 15 16 17 18
    Rectangle {
        id: clipArea
        x: trackInfo.width
        color: "#222222"
        height: parent.height
        width: track.width - initPosOfCursor
luyikei's avatar
luyikei committed
19

luyikei's avatar
luyikei committed
20
        Rectangle {
21 22 23 24 25 26 27 28 29
            color: "#666666"
            height: 1
            width: parent.width
            anchors.bottom: clipArea.bottom

            Component.onCompleted: {
                if ( track.type === "Video" && track.trackId == 0 )
                {
                    color = "#111111";
luyikei's avatar
luyikei committed
30 31
                }
            }
32
        }
luyikei's avatar
luyikei committed
33

34 35 36 37
        DropArea {
            id: dropArea
            anchors.fill: parent
            keys: ["Clip", "vlmc/uuid"]
luyikei's avatar
luyikei committed
38

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
            // Enum for drop mode
            readonly property var dropMode: {
                "New": 0,
                "Move": 1,
            }
            readonly property int magneticMargin: 25

            property string currentUuid
            property var aClipInfo: null
            property var vClipInfo: null

            property int lastX: 0
            property int deltaX: 0

            function findNewPosition( newX, target, useMagneticMode ) {
                var oldX = target.pixelPosition();

                if ( useMagneticMode === true ) {
                    var leastDestance = magneticMargin;
                    // Check two times
                    for ( var k = 0; k < 2; ++k ) {
                        for ( var j = 0; j < markers.count; ++j ) {
                            var mx = ftop( markers.get( j ).position );
                            if ( Math.abs( newX - mx ) < leastDestance ) {
                                leastDestance = Math.abs( newX - mx );
                                newX = mx;
                            }
                            else if ( Math.abs( newX + target.width - mx ) < leastDestance ) {
                                leastDestance = Math.abs( newX + target.width - mx );
                                newX = mx - target.width;
69 70 71
                            }
                        }
                    }
72
                }
73

74 75 76 77 78 79
                // Collision detection
                var isCollided = true;
                var currentTrack = trackContainer( target.type )["tracks"].get( target.newTrackId );
                if ( currentTrack )
                    var clips = currentTrack["clips"];
                else
80
                    return oldX;
81 82 83 84 85 86 87 88 89 90 91 92
                for ( j = 0; j < clips.count + 2 && isCollided; ++j ) {
                    isCollided = false;
                    for ( k = 0; k < clips.count; ++k ) {
                        var clip = clips.get( k );
                        if ( clip.uuid === target.uuid )
                            continue;
                        var sw = target.width; // Width of the source clip
                        var cx = ftop( clip["position"] );
                        var cw = ftop( clip["end"] - clip["begin"] + 1);
                        // Set a right position
                        //
                        // HACK: If magnetic mode, consider clips bigger.
93 94 95
                        var clipMargin = useMagneticMode ? magneticMargin : 0;
                        if ( cx  + cw > newX && newX + sw > cx )
                            isCollided = true;
96

97 98 99 100 101 102 103 104 105 106
                        cw += clipMargin * 2
                        cx -= clipMargin
                        if ( cx + cw > newX && newX + sw > cx ) {
                            if ( cx > newX ) {
                                if ( cx - sw > 0 )
                                    newX = cx - sw + clipMargin;
                                else
                                    newX = oldX;
                            } else {
                                newX = cx + cw - clipMargin;
107 108
                            }
                        }
109 110
                        if ( isCollided )
                            break;
111
                    }
112
                }
113

114 115 116 117 118 119
                if ( isCollided ) {
                    for ( k = 0; k < clips.count; ++k ) {
                        clip = clips.get( k );
                        cx = ftop( clip["position"] );
                        cw = ftop( clip["end"] - clip["begin"] + 1);
                        newX = Math.max( newX, cx + cw );
120
                    }
121
                }
122 123
                return newX;
            }
124

125 126 127 128
            onDropped: {
                if ( drop.keys.indexOf( "vlmc/uuid" ) >= 0 ) {
                    aClipInfo = findClipFromTrack( "Audio", trackId, "audioUuid" );
                    vClipInfo = findClipFromTrack( "Video", trackId, "videoUuid" );
129
                    var pos = 0;
130
                    if ( aClipInfo ) {
131
                        pos = aClipInfo["position"];
132
                        removeClipFromTrack( "Audio", trackId, "audioUuid" );
133 134 135
                    }
                    if ( vClipInfo ) {
                        pos = vClipInfo["position"];
136
                        removeClipFromTrack( "Video", trackId, "videoUuid" );
luyikei's avatar
luyikei committed
137
                    }
138
                    workflow.addClip( drop.getDataAsString("vlmc/uuid"), trackId, pos, false );
139 140 141 142 143 144
                    currentUuid = "";
                    aClipInfo = null;
                    vClipInfo = null;
                    clearSelectedClips();
                    adjustTracks( "Audio" );
                    adjustTracks( "Video" );
luyikei's avatar
luyikei committed
145
                }
146
            }
luyikei's avatar
luyikei committed
147

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
            onExited: {
                if ( currentUuid !== "" ) {
                    removeClipFromTrack( "Audio", trackId, "audioUuid" );
                    removeClipFromTrack( "Video", trackId, "videoUuid" );
                }
            }

            onEntered: {
                if ( drag.keys.indexOf( "vlmc/uuid" ) >= 0 ) {
                    clearSelectedClips();
                    if ( currentUuid === drag.getDataAsString( "vlmc/uuid" ) ) {
                        if ( aClipInfo )
                        {
                            aClipInfo["position"] = ptof( drag.x );
                            aClipInfo = addClip( "Audio", trackId, aClipInfo );
luyikei's avatar
luyikei committed
163
                        }
164 165 166 167
                        if ( vClipInfo )
                        {
                            vClipInfo["position"] = ptof( drag.x );
                            vClipInfo = addClip( "Video", trackId, vClipInfo );
luyikei's avatar
luyikei committed
168 169
                        }
                    }
170
                    else {
171
                        var newClipInfo = workflow.libraryClipInfo( drag.getDataAsString( "vlmc/uuid" ) );
172
                        currentUuid = "" + newClipInfo["libraryUuid"];
173 174 175 176 177 178 179 180 181 182 183
                        newClipInfo["position"] = ptof( drag.x );
                        if ( newClipInfo["audio"] ) {
                            newClipInfo["uuid"] = "audioUuid";
                            aClipInfo = addClip( "Audio", trackId, newClipInfo );
                        }
                        if ( newClipInfo["video"] ) {
                            newClipInfo["uuid"] = "videoUuid";
                            vClipInfo = addClip( "Video", trackId, newClipInfo );
                        }
                    }
                    lastX = drag.x;
luyikei's avatar
luyikei committed
184
                }
185 186 187
                else
                    lastX = drag.source.x;
            }
luyikei's avatar
luyikei committed
188

189 190 191 192 193 194 195 196 197 198 199
            onPositionChanged: {
                // If resizing, ignore
                if ( drag.source.resizing === true )
                    return;

                if ( drag.keys.indexOf( "vlmc/uuid" ) >= 0 )
                    var dMode = dropMode.New;
                else
                    dMode = dropMode.Move;

                if ( dMode === dropMode.Move ) {
200 201 202 203 204 205 206 207 208 209
                    // Prepare newTrackId for all the selected clips
                    for ( var i = 0; i < selectedClips.length; ++i ) {
                        var target = selectedClips[i];
                        if ( drag.source === target ) {
                            var oldTrackId = target.newTrackId;
                            target.newTrackId = trackId;
                            for ( var j = 0; j < selectedClips.length; ++j ) {
                                if ( drag.source !== selectedClips[j] )
                                    selectedClips[j].newTrackId = Math.max( 0, trackId - oldTrackId + selectedClips[j].trackId );
                            }
210
                        }
211
                    }
212

213
                    drag.source.scrollToThis();
214

215 216 217 218 219 220 221 222 223 224
                    if ( drag.source.x !== findNewPosition( drag.source.x, drag.source, false ) )
                        deltaX = 0;
                    else {
                        // Optimization: Delta delta X should be 0
                        if ( ptof( deltaX ) === ptof( drag.source.x - lastX ) && drag.source.x !== 0 ) {
                            lastX = drag.source.x;
                            return;
                        }
                        else
                            deltaX = drag.source.x - lastX;
luyikei's avatar
luyikei committed
225
                    }
226 227 228 229
                }
                else
                    deltaX = drag.x - lastX;

230
                sortSelectedClips();
231 232
                var alreadyCalculated = []; // Uuids of clips being already set new x position.
                for ( i = 0; i < selectedClips.length; ++i ) {
233
                    target = selectedClips[i];
234

235 236
                    var uuid = target.uuid;
                    if ( alreadyCalculated.indexOf( uuid ) < 0 ) {
237 238
                        var oldX = target.pixelPosition();
                        var newX = Math.max( oldX + deltaX, 0 );
239

240
                        newX = findNewPosition( newX, target, isMagneticMode );
luyikei's avatar
luyikei committed
241

242
                        // Let's find newX of the linked clip
243 244 245
                        for ( j = 0; j < target.linkedClips.length; ++j )
                        {
                            var linkedClipItem = findClipItem( target.linkedClips[j] );
246

247 248
                            if ( linkedClipItem ) {
                                var newLinkedClipX = findNewPosition( newX, linkedClipItem, isMagneticMode );
249

250
                                // If linked clip collides
251
                                if ( ptof( Math.abs( newLinkedClipX - newX ) ) !== 0 ) {
252

253 254 255 256
                                    // Recalculate target's newX
                                    // This time, don't use magnets
                                    newX = findNewPosition( newLinkedClipX, target, false );
                                    newLinkedClipX = findNewPosition( newX, target, false );
luyikei's avatar
luyikei committed
257

258
                                    // And if newX collides again, we don't move
259
                                    if ( ptof( Math.abs( newLinkedClipX - newX ) ) !== 0 )
260 261
                                        newX = oldX;
                                }
luyikei's avatar
luyikei committed
262

263 264
                                if ( length < ptof( newX + linkedClipItem.width ) ) {
                                    length = ptof( newX + linkedClipItem.width );
265
                                }
luyikei's avatar
luyikei committed
266

267
                                linkedClipItem.setPixelPosition( newX );
268
                                alreadyCalculated.push( target.linkedClips[j] );
luyikei's avatar
luyikei committed
269
                            }
270
                        }
luyikei's avatar
luyikei committed
271

272 273
                        if ( length < ptof( newX + target.width ) ) {
                            length = ptof( newX + target.width );
274
                        }
275

276 277 278 279 280 281 282 283 284
                        // Recalculate deltaX in case of drag.source being moved
                        if ( drag.source === target ) {
                            if ( oldTrackId === target.newTrackId )
                                deltaX = newX - oldX;
                            else
                                // Don't move other clips if drag.source's track is changed
                                deltaX = 0;
                        }

285 286 287 288 289 290
                        target.setPixelPosition( newX );
                        alreadyCalculated.push( target.uuid );
                    }

                    // Scroll if needed
                    if ( drag.source === target || dMode === dropMode.New )
291
                        target.scrollToThis();
292 293 294 295 296

                    // Let's move to the new tracks
                    if ( dMode === dropMode.Move ) {
                        if ( target.newTrackId !== target.trackId ) {
                            drag.source.parent.parent.z = ++maxZ;
297
                            if ( drag.source.uuid !== uuid ) {
298 299
                                target.clipInfo["selected"] = true;
                                addClip( target.type, target.newTrackId, target.clipInfo );
300
                                removeClipFromTrack( target.type, target.trackId, uuid );
301
                                --i;
luyikei's avatar
luyikei committed
302 303 304 305
                            }
                        }
                    }
                }
306 307 308 309 310 311
                // END of for ( var i = 0; i < selectedClips.length; ++i )

                if ( dMode === dropMode.Move )
                    lastX = drag.source.x;
                else
                    lastX = drag.x;
luyikei's avatar
luyikei committed
312
            }
313
        }
luyikei's avatar
luyikei committed
314

315 316 317 318 319 320 321 322 323
        Repeater {
            id: repeater
            model: clips
            delegate: Clip {
                height: track.height - 3
                name: model.name
                trackId: model.trackId
                type: track.type
                uuid: model.uuid
324
                libraryUuid: model.libraryUuid
325
                position: model.position
326
                lastPosition: model.lastPosition
327 328 329
                begin: model.begin
                end: model.end
                clipInfo: model
luyikei's avatar
luyikei committed
330 331 332
            }
        }
    }
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361

    Rectangle {
        id: trackInfo
        x: sView.flickableItem.contentX
        width: initPosOfCursor
        height: parent.height
        color: "#444444"

        Rectangle {
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
            color: "#111111"
        }

        Rectangle {
            width: 1
            height: parent.height
            anchors.left: parent.left
            color: "#111111"
        }

        Rectangle {
            width: 1
            height: parent.height
            anchors.right: parent.right
            color: "#111111"
        }

362 363
        Text {
            id: trackText
364
            anchors.verticalCenter: parent.verticalCenter
365 366 367
            x: 10
            text: type + " " + ( trackId + 1 )
            color: "white"
368
            font.pointSize: 10
369
        }
370

371 372
        Row {
            anchors.verticalCenter: parent.verticalCenter
373
            x: trackText.y + trackText.contentWidth + 10
374
            spacing: 4
375 376 377 378 379 380 381 382

            PropertyButton {
                id: fxButton
                text: "Fx"
                selected: true

                onSelectedChanged: {
                    if ( selected === false ) {
383
                        workflow.showEffectStack( trackId );
384 385 386 387
                        selected = true;
                    }
                }
            }
388 389
        }
    }
luyikei's avatar
luyikei committed
390 391
}