Ruler.qml 11.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * Copyright (c) 2013 Meltytech, LLC
 * Author: Dan Dennedy <dan@dennedy.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

19
20
import QtQuick 2.11
import QtQuick.Controls 2.4
Julius Künzel's avatar
Julius Künzel committed
21
import com.enums 1.0
22

23
Item {
24
    id: rulerRoot
25
    // The standard width for labels. Depends on format used (frame number or full timecode)
26
    property int labelSize: fontMetrics.boundingRect(timeline.timecode(36000)).width
27
28
29
30
    // The spacing between labels. Depends on labelSize
    property real labelSpacing: labelSize
    // The space we want between each ticks in the ruler
    property real tickSpacing: timeline.scaleFactor
31
    property alias rulerZone : zone
32
    property int workingPreview : timeline.workingPreview
33
    property int labelMod: 1
34
    property bool useTimelineRuler : timeline.useRuler
35
    property int zoneHeight: Math.ceil(root.baseUnit / 2) + 1
36
    property bool showZoneLabels: false
37
    property bool resizeActive: false // Used to decide which mouse cursor we should display
38
39
    property bool hoverGuide: false
    property int cursorShape: resizeActive ? Qt.SizeHorCursor : hoverGuide ? Qt.PointingHandCursor : Qt.ArrowCursor
40
    property var effectZones: timeline.masterEffectZones
41
    property int guideLabelHeight: timeline.showMarkers ? fontMetrics.height + 2 : 0
42
    property int previewHeight: Math.ceil(timecodeContainer.height / 5)
43
    property color dimmedColor: (activePalette.text.r + activePalette.text.g + activePalette.text.b > 1.5) ? Qt.darker(activePalette.text, 1.3) : Qt.lighter(activePalette.text, 1.3)
44
    
45
    function adjustStepSize() {
46
47
48
49
50
        if (timeline.scaleFactor > 19) {
            // Frame size >= 20 pixels
            rulerRoot.tickSpacing = timeline.scaleFactor
            // labelSpacing cannot be smaller than 1 frame
            rulerRoot.labelSpacing = timeline.scaleFactor > rulerRoot.labelSize * 1.3 ? timeline.scaleFactor : Math.floor(rulerRoot.labelSize/timeline.scaleFactor) * timeline.scaleFactor
51
        } else {
52
            rulerRoot.tickSpacing = Math.floor(3 * root.baseUnit / timeline.scaleFactor) * timeline.scaleFactor
53
            rulerRoot.labelSpacing = (Math.floor(rulerRoot.labelSize/rulerRoot.tickSpacing) + 1) * rulerRoot.tickSpacing
54
        }
55
        rulerRoot.labelMod = Math.max(1, Math.ceil((rulerRoot.labelSize + root.baseUnit) / rulerRoot.tickSpacing))
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
56
        //console.log('LABELMOD: ', Math.ceil((rulerRoot.labelSize + root.fontUnit) / rulerRoot.tickSpacing)))
57
        tickRepeater.model = Math.ceil(rulercontainer.width / rulerRoot.tickSpacing) + 2
58
59
    }

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
60
    function adjustFormat() {
61
        rulerRoot.labelSize = fontMetrics.boundingRect(timeline.timecode(36000)).width
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
62
        adjustStepSize()
63
        repaintRuler()
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
64
    }
65

66
67
68
    function repaintRuler() {
        // Enforce repaint
        tickRepeater.model = 0
69
        tickRepeater.model = Math.ceil(rulercontainer.width / rulerRoot.tickSpacing) + 2
70
    }
71

72
    // Timeline preview stuff
73
74
    Repeater {
        model: timeline.dirtyChunks
75
        anchors.fill: parent
76
        delegate: Rectangle {
77
            x: modelData * timeline.scaleFactor
78
79
            anchors.bottom: parent.bottom
            anchors.bottomMargin: zoneHeight
80
            width: 25 * timeline.scaleFactor
81
            height: previewHeight
82
83
84
85
86
87
            color: 'darkred'
        }
    }

    Repeater {
        model: timeline.renderedChunks
88
        anchors.fill: parent
89
        delegate: Rectangle {
90
            x: modelData * timeline.scaleFactor
91
92
            anchors.bottom: parent.bottom
            anchors.bottomMargin: zoneHeight
93
            width: 25 * timeline.scaleFactor
94
            height: previewHeight
95
96
97
98
99
            color: 'darkgreen'
        }
    }
    Rectangle {
        id: working
100
        x: rulerRoot.workingPreview * timeline.scaleFactor
101
102
        anchors.bottom: parent.bottom
        anchors.bottomMargin: zoneHeight
103
        width: 25 * timeline.scaleFactor
104
        height: previewHeight
105
        color: 'orange'
106
        visible: rulerRoot.workingPreview > -1
107
    }
108

109
110
111
112
113
114
    // Guides
    Repeater {
        model: guidesModel
        delegate:
        Item {
            id: guideRoot
115
116
            property bool activated : proxy.position == model.frame
            z: activated ? 20 : 10
117
118
119
120
121
            Rectangle {
                id: markerBase
                width: 1
                height: rulerRoot.height
                x: model.frame * timeline.scaleFactor
122
                color: guideRoot.activated ? Qt.lighter(model.color, 1.3) : model.color
123
                property int markerId: model.id
124
125
126
127
                Rectangle {
                    visible: timeline.showMarkers
                    width: mlabel.contentWidth + 4
                    height: guideLabelHeight
128
                    radius: timeline.guidesLocked ? 0 : height / 4
129
                    color: markerBase.color
130
131
132
133
                    anchors {
                        top: parent.top
                        left: parent.left
                    }
134
135
136
137
138
139
140
141
142
143
                    Rectangle {
                        // Shadow delimiting marker start
                        width: 1
                        height: guideLabelHeight
                        color: activePalette.dark
                        anchors {
                            right: parent.left
                        }
                    }

144
145
146
                    Text {
                        id: mlabel
                        text: model.comment
147
                        bottomPadding: 2
148
149
150
                        leftPadding: 2
                        rightPadding: 2
                        font: miniFont
151
                        color: '#000'
152
153
154
155
                    }
                    MouseArea {
                        z: 10
                        id: guideArea
156
157
158
159
                        anchors.left: parent.left
                        anchors.top: parent.top
                        width: parent.width
                        height: parent.height
160
161
162
                        acceptedButtons: Qt.LeftButton
                        cursorShape: Qt.PointingHandCursor
                        hoverEnabled: true
163
164
                        property int prevFrame
                        property int xOffset: 0
165
166
                        drag.axis: Drag.XAxis
                        onPressed: {
167
168
169
                            prevFrame = model.frame
                            xOffset = mouseX
                            anchors.left = undefined
170
171
                        }
                        onReleased: {
172
173
174
175
                            if (prevFrame != model.frame) {
                                var newFrame = model.frame
                                timeline.moveGuideWithoutUndo(markerBase.markerId,  prevFrame)
                                timeline.moveGuide(prevFrame, newFrame)
176
                            }
177
                            anchors.left = parent.left
178
179
180
                        }
                        onPositionChanged: {
                            if (pressed) {
181
                                var newFrame = Math.round(model.frame + (mouseX - xOffset) / timeline.scaleFactor)
182
                                newFrame = controller.suggestSnapPoint(newFrame, mouse.modifiers & Qt.ShiftModifier ? -1 : root.snapping)
183
                                timeline.moveGuideWithoutUndo(markerBase.markerId,  newFrame)
184
185
186
187
188
                            }
                        }
                        drag.smoothed: false
                        onDoubleClicked: timeline.editGuide(model.frame)
                        onClicked: {
189
190
191
                            if (root.activeTool !== ProjectTool.SlipTool) {
                                proxy.position = model.frame
                            }
192
                        }
193
194
195
196
197
198
                        onEntered: {
                            rulerRoot.hoverGuide = true
                        }
                        onExited: {
                            rulerRoot.hoverGuide = false
                        }
199
200
201
202
203
204
                    }
                }
            }
        }
    }
    
205
    // Ruler marks
206
    Item {
207
        id: timecodeContainer
208
209
210
211
212
213
        anchors.top: parent.top
        anchors.topMargin: guideLabelHeight
        anchors.bottom: parent.bottom
        anchors.bottomMargin: zoneHeight
        anchors.left: parent.left
        anchors.right: parent.right
214
    Repeater {
215
        id: tickRepeater
216
        model: Math.ceil(rulercontainer.width / rulerRoot.tickSpacing) + 2
217
        property int offset: Math.floor(scrollView.contentX /rulerRoot.tickSpacing)
218
219
220
221
222
223
224
225
226
        Item {
            property int realPos: (tickRepeater.offset + index) * rulerRoot.tickSpacing / timeline.scaleFactor
            x: realPos * timeline.scaleFactor
            height: parent.height
            property bool showText: (tickRepeater.offset + index)%rulerRoot.labelMod == 0
            Rectangle {
                anchors.bottom: parent.bottom
                height: parent.showText ? 8 : 4
                width: 1
227
                color: dimmedColor
228
229
230
231
232
            }
            Label {
                visible: parent.showText
                anchors.top: parent.top
                text: timeline.timecode(parent.realPos)
233
                font: miniFont
234
                color: dimmedColor
235
            }
236
237
        }
    }
238
239
    }
    
240
    RulerZone {
241
        id: zone
242
243
244
245
246
247
248
249
250
251
        Binding {
            target: zone
            property: "frameIn"
            value: timeline.zoneIn
        }
        Binding {
            target: zone
            property: "frameOut"
            value: timeline.zoneOut
        }
252
253
        color: useTimelineRuler ? Qt.rgba(activePalette.highlight.r,activePalette.highlight.g,activePalette.highlight.b,0.9) :
        Qt.rgba(activePalette.highlight.r,activePalette.highlight.g,activePalette.highlight.b,0.5)
254
        anchors.bottom: parent.bottom
255
        height: zoneHeight
256
257
258
        function updateZone(start, end, update)
        {
            timeline.updateZone(start, end, update)
259
        }
260
    }
261
262
263
264
265
266

    // Master effect zones
    Repeater {
        model: effectZones
        Rectangle {
            x: effectZones[index].x * timeline.scaleFactor
267
            height: zoneHeight - 1
268
269
270
            width: (effectZones[index].y - effectZones[index].x) * timeline.scaleFactor
            color: "blueviolet"
            anchors.bottom: parent.bottom
271
            opacity: 0.4
272
273
274
        }
    }

275
276
277
278
279
280
281
282
283
284
285
286
287
    // Effect zone
    RulerZone {
        id: effectZone
        Binding {
            target: effectZone
            property: "frameIn"
            value: timeline.effectZone.x
        }
        Binding {
            target: effectZone
            property: "frameOut"
            value: timeline.effectZone.y
        }
288
        color: "orchid"
289
        anchors.bottom: parent.bottom
290
        height: zoneHeight - 1
291
        opacity: 0.7
292
293
294
295
296
        function updateZone(start, end, update)
        {
            timeline.updateEffectZone(start, end, update)
        }
    }
297
298
}