Skip to content

Commit 9bbf0cf

Browse files
committed
Nicer timeline ruler
1 parent b0029d8 commit 9bbf0cf

File tree

2 files changed

+47
-32
lines changed

2 files changed

+47
-32
lines changed

OpenTimelineIO-Sample/OpenTimelineIO-Reader/Views/ContentView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ struct ContentView: View
124124
.lineLimit(1)
125125
.font(.system(size: 10))
126126

127-
Slider(value: $secondsToPixels, in: 10...300)
127+
Slider(value: $secondsToPixels, in: 10...1000)
128128
.controlSize(.mini)
129129
.frame(width: 200)
130130
}

OpenTimelineIO-Sample/OpenTimelineIO-Reader/Views/TimeRulerView.swift

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,52 +23,57 @@ struct TimeRulerView: View
2323
let safeRange = getSafeRange()
2424
let startSeconds = safeRange.startTime.toSeconds()
2525
let endSeconds = safeRange.endTimeInclusive().toSeconds()
26-
26+
27+
// Draw playhead
28+
drawPlayhead(context: context, currentTime: currentTime, secondsToPixels: secondsToPixels, size: size)
29+
2730
// Draw ticks (including frame-level ticks)
2831
drawTicks(context: context, startSeconds: startSeconds, endSeconds: endSeconds, secondsToPixels: secondsToPixels, size: size)
2932

30-
// Draw playhead
31-
drawPlayhead(context: context, currentTime: currentTime, secondsToPixels: secondsToPixels, size: size)
3233
}
3334
.frame(width: self.getSafeWidth())
3435
}
3536
func drawTicks(context: GraphicsContext, startSeconds: Double, endSeconds: Double, secondsToPixels: Double, size: CGSize)
3637
{
37-
self.drawFrameTicks(context: context, startSeconds: startSeconds, endSeconds: endSeconds, secondsToPixels: secondsToPixels, size: size)
38-
self.drawSecondTicks(context: context, startSeconds: startSeconds, endSeconds: endSeconds, secondsToPixels: secondsToPixels, size: size)
39-
38+
if self.secondsToPixels > 100
39+
{
40+
self.drawFrameTicks(context: context, startSeconds: startSeconds, endSeconds: endSeconds, secondsToPixels: secondsToPixels, size: size)
41+
}
42+
43+
self.drawSecondTicks(context: context, startSeconds: startSeconds, endSeconds: endSeconds, secondsToPixels: secondsToPixels, size: size)
4044
}
4145

4246
func drawSecondTicks(context: GraphicsContext, startSeconds: Double, endSeconds: Double, secondsToPixels: Double, size: CGSize)
4347
{
4448
let maxPixelX = size.width
4549

4650
let frameRate = getFrameRate() // Get the frame rate of the timeline
47-
let frameDuration = 1.0 / frameRate // Duration of one frame in seconds
51+
// let frameDuration = 1.0 / frameRate // Duration of one frame in seconds
4852

4953
for timeInSeconds in stride(from: startSeconds, through: endSeconds, by: 1)
5054
{
51-
print(timeInSeconds)
5255
let positionX = (timeInSeconds - startSeconds) * secondsToPixels
5356

5457
// Skip if out of canvas bounds
5558
guard positionX >= 0, positionX <= maxPixelX else { continue }
5659

57-
let tickHeight = 10.0
58-
60+
let tickHeight = 9.0
5961

6062
// Determine if it's an hour, minute, second, or frame tick
6163
let seconds = timeInSeconds.truncatingRemainder(dividingBy: 60)
6264
let minutes = (timeInSeconds / 60).truncatingRemainder(dividingBy: 60)
6365
let hours = (timeInSeconds / 3600).truncatingRemainder(dividingBy: 24)
64-
let label = String(format: "%02d:%02d:%02d", Int(hours), Int(minutes), Int(seconds))
66+
let label = String(format: "%02d:%02d:%02d:00", Int(hours), Int(minutes), Int(seconds))
6567

6668
// Draw tick line
6769
let tickRect = CGRect(x: positionX, y: size.height - tickHeight, width: 1, height: tickHeight)
6870
context.fill(Path(tickRect), with: .color(.white))
6971

7072
// Draw label if it's an hour or minute
73+
if self.secondsToPixels > 50
74+
{
7175
context.draw(Text(label).font(.system(size: 10)).foregroundStyle(.white), at: CGPoint(x: positionX + 2, y: size.height - tickHeight - 10))
76+
}
7277
}
7378
}
7479

@@ -78,23 +83,25 @@ struct TimeRulerView: View
7883

7984
let frameRate = getFrameRate() // Get the frame rate of the timeline
8085
let frameDuration = 1.0 / frameRate // Duration of one frame in seconds
81-
82-
for timeInSeconds in stride(from: startSeconds, through: endSeconds, by: frameDuration)
86+
87+
for frameNum in stride(from: 1, through: Int((endSeconds - startSeconds) * frameRate), by: 1)
8388
{
84-
let positionX = (timeInSeconds - startSeconds) * secondsToPixels
89+
let positionX = Double(frameNum) * frameDuration * secondsToPixels
8590

8691
// Skip if out of canvas bounds
8792
guard positionX >= 0, positionX <= maxPixelX else { continue }
8893

89-
let tickHeight = 5.0
94+
let tickHeight = 4.0
9095

91-
92-
93-
9496
// Draw tick line
9597
let tickRect = CGRect(x: positionX, y: size.height - tickHeight, width: 1, height: tickHeight)
9698
context.fill(Path(tickRect), with: .color(.white))
97-
99+
100+
if self.secondsToPixels > 400
101+
{
102+
context.draw(Text(String(frameNum)).font(.system(size: 10)).foregroundStyle(.white), at: CGPoint(x: positionX, y: size.height - tickHeight - 5))
103+
104+
}
98105
}
99106
}
100107

@@ -113,33 +120,41 @@ struct TimeRulerView: View
113120

114121

115122
let playheadPositionX = currentTime.toSeconds() * secondsToPixels
116-
let playheadRect = CGRect(x: playheadPositionX, y: 10, width: 2, height: size.height-10)
123+
let playheadRect = CGRect(x: playheadPositionX, y: 20, width: 1, height: size.height-20)
124+
// context.fill(Path(playheadRect), with: .color(.orange))
125+
126+
// context.draw( resolved , in: playheadRect)
127+
context.draw(Text("\(Image(systemName: "arrowtriangle.down.fill"))").font(.system(size: 13)).foregroundStyle(.orange), at: CGPoint(x: playheadPositionX + 0.5, y: 15))
128+
117129
context.fill(Path(playheadRect), with: .color(.orange))
118-
context.draw(Text(currentTimeLabel).font(.system(size: 10)).foregroundStyle(.orange), at: CGPoint(x: playheadPositionX, y: 5))
130+
131+
context.draw( Text(currentTimeLabel).font(.system(size: 10)).foregroundStyle(.orange) , at: CGPoint(x: playheadPositionX, y: 5))
119132

120133
}
121134

122135
// New function to get frame rate of the timeline
123-
func getFrameRate() -> Double {
124-
do {
125-
let rate = try timeline.globalStartTime?.rate ?? 24.0 // Default to 24 fps if unavailable
136+
func getFrameRate() -> Double
137+
{
138+
let rate = timeline.globalStartTime?.rate ?? 24.0 // Default to 24 fps if unavailable
126139
return rate
127-
} catch {
128-
return 24.0 // Fallback to default frame rate
129-
}
130140
}
131141

132-
func getSafeRange() -> OpenTimelineIO.TimeRange {
142+
func getSafeRange() -> OpenTimelineIO.TimeRange
143+
{
133144
var range: OpenTimelineIO.TimeRange
134-
do {
145+
do
146+
{
135147
range = try TimeRange(startTime: timeline.globalStartTime ?? RationalTime(), duration: timeline.duration())
136-
} catch {
148+
}
149+
catch
150+
{
137151
range = TimeRange()
138152
}
139153
return range
140154
}
141155

142-
func getSafeWidth() -> CGFloat {
156+
func getSafeWidth() -> CGFloat
157+
{
143158
return self.getSafeRange().duration.toSeconds() * self.secondsToPixels
144159
}
145160
}

0 commit comments

Comments
 (0)