Track.qml 13.6 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
            // 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 ) {
luyikei's avatar
luyikei committed
57
                    var leastDistance = magneticMargin;
58 59 60 61
                    // 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 );
luyikei's avatar
luyikei committed
62 63
                            if ( Math.abs( newX - mx ) < leastDistance ) {
                                leastDistance = Math.abs( newX - mx );
64 65
                                newX = mx;
                            }
luyikei's avatar
luyikei committed
66 67
                            else if ( Math.abs( newX + target.width - mx ) < leastDistance ) {
                                leastDistance = Math.abs( newX + target.width - mx );
68
                                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["uuid"];
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
            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;

199
                var toMove = selectedClips.concat();
200

201
                if ( dMode === dropMode.Move ) {
202
                    // Prepare newTrackId for all the selected clips
203
                    for ( var i = 0; i < toMove.length; ++i ) {
204
                        var target = findClipItem( toMove[i] );
205
                        if ( drag.source === target ) {
206
                            drag.source.parent.parent.z = ++maxZ;
207 208 209
                            var oldTrackId = target.newTrackId;
                            target.newTrackId = trackId;
                            for ( var j = 0; j < selectedClips.length; ++j ) {
210 211 212 213 214
                                if ( drag.source.uuid !== selectedClips[j] )
                                {
                                    var clip = findClipItem( selectedClips[j] );
                                    clip.newTrackId = Math.max( 0, trackId - oldTrackId + clip.trackId );
                                }
215
                            }
216
                        }
217 218 219 220 221 222
                        // Let's move to the new tracks
                        else if ( target.newTrackId !== target.trackId ) {
                                target.clipInfo["selected"] = true;
                                addClip( target.type, target.newTrackId, target.clipInfo );
                                removeClipFromTrack( target.type, target.trackId, target.uuid );
                        }
223
                    }
224

225 226
                    if ( drag.source.x !== findNewPosition( drag.source.x, drag.source, false ) )
                        deltaX = 0;
227 228
                    else
                        deltaX = drag.source.x - lastX;
229 230 231 232
                }
                else
                    deltaX = drag.x - lastX;

233 234
                while ( toMove.length > 0 ) {
                    target = findClipItem( toMove[0] );
235

236
                    var uuid = target.uuid;
237 238
                    var oldX = target.pixelPosition();
                    var newX = findNewPosition( Math.max( oldX + deltaX, 0 ), target, isMagneticMode );
luyikei's avatar
luyikei committed
239

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

245 246
                        if ( linkedClipItem ) {
                            var newLinkedClipX = findNewPosition( newX, linkedClipItem, isMagneticMode );
247

248 249
                            // If linked clip collides
                            if ( ptof( Math.abs( newLinkedClipX - newX ) ) !== 0 ) {
luyikei's avatar
luyikei committed
250

251 252 253 254
                                // 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
255

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

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

265 266 267 268
                            linkedClipItem.setPixelPosition( newX );
                            var ind = toMove.indexOf( linkedClipItem.uuid );
                            if ( ind > 0 )
                                toMove.splice( ind, 1 );
269
                        }
270
                    }
271

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

276 277 278
                    target.setPixelPosition( newX );
                    toMove.splice( 0, 1 );

279 280
                    // Scroll if needed
                    if ( drag.source === target || dMode === dropMode.New )
281
                        target.scrollToThis();
luyikei's avatar
luyikei committed
282
                }
luyikei's avatar
luyikei committed
283
                // END of while ( toMove.length > 0 )
284 285 286 287 288

                if ( dMode === dropMode.Move )
                    lastX = drag.source.x;
                else
                    lastX = drag.x;
luyikei's avatar
luyikei committed
289
            }
290
        }
luyikei's avatar
luyikei committed
291

292 293 294 295 296 297 298 299 300
        Repeater {
            id: repeater
            model: clips
            delegate: Clip {
                height: track.height - 3
                name: model.name
                trackId: model.trackId
                type: track.type
                uuid: model.uuid
301
                libraryUuid: model.libraryUuid
302
                position: model.position
303
                lastPosition: model.lastPosition
304 305 306
                begin: model.begin
                end: model.end
                clipInfo: model
luyikei's avatar
luyikei committed
307 308 309
            }
        }
    }
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

    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"
        }

339 340
        Text {
            id: trackText
341
            anchors.verticalCenter: parent.verticalCenter
342 343 344
            x: 10
            text: type + " " + ( trackId + 1 )
            color: "white"
345
            font.pointSize: 10
346
        }
347

348 349
        Row {
            anchors.verticalCenter: parent.verticalCenter
350
            x: trackText.y + trackText.contentWidth + 10
351
            spacing: 4
352 353 354 355 356 357 358 359

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

                onSelectedChanged: {
                    if ( selected === false ) {
360
                        workflow.showEffectStack( trackId );
361 362 363 364
                        selected = true;
                    }
                }
            }
365 366
        }
    }
luyikei's avatar
luyikei committed
367 368
}