Ruler.qml 10.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
21

22
Item {
23
    id: rulerRoot
24
    // The standard width for labels. Depends on format used (frame number or full timecode)
25
    property int labelSize: fontMetrics.boundingRect(timeline.timecode(36000)).width
26
27
28
29
    // 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
30
    property alias rulerZone : zone
31
    property int workingPreview : timeline.workingPreview
32
    property int labelMod: 1
33
    property bool useTimelineRuler : timeline.useRuler
34
    property int zoneHeight: Math.ceil(root.baseUnit / 2) + 1
35
    property bool showZoneLabels: false
36
    property bool resizeActive: false // Used to decide which mouse cursor we should display
37
    property var effectZones: timeline.masterEffectZones
38
    property int guideLabelHeight: timeline.showMarkers ? Math.round(fontMetrics.height) : 0
39
    property int previewHeight: Math.ceil(timecodeContainer.height / 5)
40
    
41
    function adjustStepSize() {
42
43
44
45
46
        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
47
        } else {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
48
            rulerRoot.tickSpacing = Math.floor(3 * root.fontUnit / timeline.scaleFactor) * timeline.scaleFactor
49
            rulerRoot.labelSpacing = (Math.floor(rulerRoot.labelSize/rulerRoot.tickSpacing) + 1) * rulerRoot.tickSpacing
50
        }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
51
52
        rulerRoot.labelMod = Math.max(1, Math.ceil((rulerRoot.labelSize + root.fontUnit) / rulerRoot.tickSpacing))
        //console.log('LABELMOD: ', Math.ceil((rulerRoot.labelSize + root.fontUnit) / rulerRoot.tickSpacing)))
53
        tickRepeater.model = Math.ceil(scrollView.width / rulerRoot.tickSpacing) + 2
54
55
    }

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
56
    function adjustFormat() {
57
        rulerRoot.labelSize = fontMetrics.boundingRect(timeline.timecode(36000)).width
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
58
        adjustStepSize()
59
        repaintRuler()
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
60
    }
61

62
63
64
    function repaintRuler() {
        // Enforce repaint
        tickRepeater.model = 0
65
        tickRepeater.model = Math.ceil(scrollView.width / rulerRoot.tickSpacing) + 2
66
    }
67

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

    Repeater {
        model: timeline.renderedChunks
84
        anchors.fill: parent
85
        delegate: Rectangle {
86
            x: modelData * timeline.scaleFactor
87
88
            anchors.bottom: parent.bottom
            anchors.bottomMargin: zoneHeight
89
            width: 25 * timeline.scaleFactor
90
            height: previewHeight
91
92
93
94
95
            color: 'darkgreen'
        }
    }
    Rectangle {
        id: working
96
        x: rulerRoot.workingPreview * timeline.scaleFactor
97
98
        anchors.bottom: parent.bottom
        anchors.bottomMargin: zoneHeight
99
        width: 25 * timeline.scaleFactor
100
        height: previewHeight
101
        color: 'orange'
102
        visible: rulerRoot.workingPreview > -1
103
    }
104
    
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    // Guides
    Repeater {
        model: guidesModel
        delegate:
        Item {
            id: guideRoot
            Rectangle {
                id: markerBase
                width: 1
                height: rulerRoot.height
                x: model.frame * timeline.scaleFactor
                color: model.color
                opacity: 0.8
                Rectangle {
                    visible: timeline.showMarkers
                    width: mlabel.contentWidth + 4
                    height: guideLabelHeight
                    anchors {
                        top: parent.top
                        left: parent.left
                    }
                    color: model.color
                    Text {
                        id: mlabel
                        text: model.comment
                        topPadding: -2
                        leftPadding: 2
                        rightPadding: 2
                        font: miniFont
                        color: activePalette.text
                    }
                    MouseArea {
                        z: 10
                        id: guideArea
                        anchors.fill: parent
                        acceptedButtons: Qt.LeftButton
                        cursorShape: Qt.PointingHandCursor
                        hoverEnabled: true
                        property int startX
                        drag.axis: Drag.XAxis
                        drag.target: guideRoot
                        onPressed: {
                            drag.target = guideRoot
                            startX = guideRoot.x
                        }
                        onReleased: {
                            if (startX != guideRoot.x) {
                                timeline.moveGuide(model.frame,  model.frame + guideRoot.x / timeline.scaleFactor)
                            }
                            drag.target = undefined
                        }
                        onPositionChanged: {
                            if (pressed) {
                                var frame = Math.round(model.frame + guideRoot.x / timeline.scaleFactor)
                                frame = controller.suggestSnapPoint(frame, root.snapping)
                                guideRoot.x = (frame - model.frame) * timeline.scaleFactor
                            }
                        }
                        drag.smoothed: false
                        onDoubleClicked: timeline.editGuide(model.frame)
                        onClicked: {
                            proxy.position = model.frame
                        }
                    }
                }
            }
        }
    }
    
174
    // Ruler marks
175
    Item {
176
        id: timecodeContainer
177
178
179
180
181
182
        anchors.top: parent.top
        anchors.topMargin: guideLabelHeight
        anchors.bottom: parent.bottom
        anchors.bottomMargin: zoneHeight
        anchors.left: parent.left
        anchors.right: parent.right
183
    Repeater {
184
        id: tickRepeater
185
        model: Math.ceil(scrollView.width / rulerRoot.tickSpacing) + 2
186
        property int offset: Math.floor(scrollView.contentX /rulerRoot.tickSpacing)
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
        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
                color: activePalette.windowText
                opacity: 0.5
            }
            Label {
                visible: parent.showText
                anchors.top: parent.top
202
                opacity: 0.7
203
                text: timeline.timecode(parent.realPos)
204
                font: miniFont
205
206
                color: activePalette.windowText
            }
207
208
        }
    }
209
210
211
212
213
214
215
216
217
218
    }
    
    // Guide zone delimiter
    Rectangle {
        width: rulerRoot.width
        height: 1
        anchors.top: parent.top
        anchors.topMargin: guideLabelHeight
        color: activePalette.shadow
    }
219

220
    // monitor zone
221
222
223
224
    Rectangle {
        width: rulerRoot.width
        height: 1
        anchors.bottom: parent.bottom
225
        anchors.bottomMargin: zoneHeight
226
227
228
229
230
231
232
233
        color: activePalette.shadow
        Rectangle {
            width: rulerRoot.width
            height: 1
            anchors.top: parent.bottom
            color: activePalette.light
        }
    }
234
    RulerZone {
235
        id: zone
236
237
238
239
240
241
242
243
244
245
        Binding {
            target: zone
            property: "frameIn"
            value: timeline.zoneIn
        }
        Binding {
            target: zone
            property: "frameOut"
            value: timeline.zoneOut
        }
246
247
        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)
248
        anchors.bottom: parent.bottom
249
        height: zoneHeight
250
251
252
        function updateZone(start, end, update)
        {
            timeline.updateZone(start, end, update)
253
        }
254
    }
255
256
257
258
259
260
261
262
263
264
265
266
267
    // Effect zone
    RulerZone {
        id: effectZone
        Binding {
            target: effectZone
            property: "frameIn"
            value: timeline.effectZone.x
        }
        Binding {
            target: effectZone
            property: "frameOut"
            value: timeline.effectZone.y
        }
268
        color: Qt.rgba(148, 0, 211,0.7)
269
        anchors.bottom: parent.bottom
270
        height: zoneHeight
271
272
273
274
275
        function updateZone(start, end, update)
        {
            timeline.updateEffectZone(start, end, update)
        }
    }
276
277
278
279
280
281
282
    Repeater {
        model: effectZones
        Rectangle {
            x: effectZones[index].x * timeline.scaleFactor
            height: 2
            width: (effectZones[index].y - effectZones[index].x) * timeline.scaleFactor
            color: 'blueviolet'
283
            opacity: 0.8
284
285
286
            anchors.bottom: parent.bottom
        }
    }
287
288
}