diff --git a/Sources/objc/include/opentimelineio.h b/Sources/objc/include/opentimelineio.h index 880925a..b78f41c 100644 --- a/Sources/objc/include/opentimelineio.h +++ b/Sources/objc/include/opentimelineio.h @@ -135,6 +135,8 @@ bool item_trimmed_range_in_parent(CxxRetainer* self, CxxTimeRange*, CxxErrorStru CxxTimeRange item_range_in_parent(CxxRetainer* self, CxxErrorStruct*); CxxRationalTime item_transformed_time(CxxRetainer* self, CxxRationalTime, CxxRetainer* to_item, CxxErrorStruct*); CxxTimeRange item_transformed_time_range(CxxRetainer* self, CxxTimeRange, CxxRetainer* to_item, CxxErrorStruct*); +bool item_get_enabled(CxxRetainer* self); +void item_set_enabled(CxxRetainer* self, bool enabled); // MARK: - Transition CxxRationalTime transition_get_in_offset(CxxRetainer* self); diff --git a/Sources/objc/opentimelineio.mm b/Sources/objc/opentimelineio.mm index e109983..b750d0c 100644 --- a/Sources/objc/opentimelineio.mm +++ b/Sources/objc/opentimelineio.mm @@ -410,6 +410,16 @@ CxxTimeRange item_transformed_time_range(CxxRetainer* self, CxxTimeRange tr, Cxx &aeh.error_status)); } +bool item_get_enabled(CxxRetainer* self) { + auto item = SO_cast(self); + return item->enabled(); +} + +void item_set_enabled(CxxRetainer* self, bool enabled) { + auto item = SO_cast(self); + item->set_enabled(enabled); +} + // MARK: - Transition CxxRationalTime transition_get_in_offset(CxxRetainer* self) { return cxxRationalTime(SO_cast(self)->in_offset()); diff --git a/Sources/swift/Item.swift b/Sources/swift/Item.swift index b0348e9..f1296ee 100644 --- a/Sources/swift/Item.swift +++ b/Sources/swift/Item.swift @@ -20,6 +20,7 @@ public class Item : Composable { sourceRange: TimeRange? = nil, effects: [Effect]? = nil, markers: [Marker]? = nil, + enabled: Bool = true, metadata: ST? = nil) where ST.Element == Metadata.Dictionary.Element { self.init() metadataInit(name, metadata) @@ -32,14 +33,16 @@ public class Item : Composable { if let effects = effects { self.effects.set(contents: effects) } + self.enabled = enabled } public convenience init(name: String? = nil, sourceRange: TimeRange? = nil, effects: [Effect]? = nil, - markers: [Marker]? = nil) { + markers: [Marker]? = nil, + enabled: Bool = true) { self.init(name: name, sourceRange: sourceRange, effects: effects, markers: markers, - metadata: Metadata.Dictionary.none) + enabled: enabled, metadata: Metadata.Dictionary.none) } public var sourceRange: TimeRange? { @@ -56,6 +59,11 @@ public class Item : Composable { } } } + + public var enabled: Bool { + get { item_get_enabled(self) } + set { item_set_enabled(self, newValue) } + } lazy var _markersProperty = { create_item_markers_vector_property(self) }() lazy var _effectsProperty = { create_item_effects_vector_property(self) }() diff --git a/Tests/OpenTimelineIOTests/testSO.swift b/Tests/OpenTimelineIOTests/testSO.swift index 519b6a4..1e923cc 100644 --- a/Tests/OpenTimelineIOTests/testSO.swift +++ b/Tests/OpenTimelineIOTests/testSO.swift @@ -12,7 +12,7 @@ class testSO: XCTestCase { func otioFilePath(_ filename: String) -> String? { return Bundle.module.path(forResource: filename, ofType: "") } - + func uniqueTmpFileName(_ basename: String) -> URL { let r = UUID().uuidString let tmpFile = FileManager.default.temporaryDirectory.appendingPathComponent("otio-tmp-xctest-\(r).otio") @@ -23,7 +23,7 @@ class testSO: XCTestCase { let so0 = SerializableObject() XCTAssert(so0.schemaName == "SerializableObject") XCTAssert(so0.schemaVersion == 1) - + let path = otioFilePath("data/so1.otio") XCTAssert(path != nil) if (path == nil) { @@ -32,22 +32,22 @@ class testSO: XCTestCase { let so1 = try! SerializableObject.fromJSON(filename: path!) XCTAssert(so0.isEquivalent(to: so1)) - + let clip1 = Clip() clip1.name = "my-clip-1" - + let clip1String = try! clip1.toJSON() let clip2 = try! SerializableObject.fromJSON(string: clip1String) - + XCTAssertNotNil(clip2 as? Clip) XCTAssertNil(clip2 as? Gap) XCTAssert(clip1.isEquivalent(to: clip2)) - + let tmpFile = uniqueTmpFileName("t1") try! clip2.toJSON(url: tmpFile) XCTAssert(clip2.isEquivalent(to: try! SerializableObject.fromJSON(url: tmpFile))) try! FileManager.default.removeItem(at: tmpFile) - + XCTAssert(!so0.isUnknownSchema) XCTAssert(!clip2.isUnknownSchema) } @@ -64,7 +64,7 @@ class testSO: XCTestCase { let uso = so as! UnknownSchema XCTAssert(uso.originalSchemaVersion == 3 && uso.originalSchemaName == "BogusName") } - + func test_SerializableObjectWithMetadata() { let sowm = SerializableObjectWithMetadata() let clip = Clip() @@ -72,14 +72,14 @@ class testSO: XCTestCase { sowm.metadata["aString"] = "foo" sowm.metadata["aVector"] = Metadata.Vector(arrayLiteral: 3, "abc", clip) sowm.name = "sowm" - + let sowm2 = try! sowm.clone() as! SerializableObjectWithMetadata XCTAssert(sowm2.isEquivalent(to: sowm)) - + let sowm3 = SerializableObjectWithMetadata(name: sowm.name, metadata: sowm.metadata) let sowm4 = SerializableObjectWithMetadata(name: sowm3.name, metadata: sowm3.metadata.map { $0 }) XCTAssert(sowm3.isEquivalent(to: sowm4)) - + print(try! sowm.toJSON()) } @@ -88,8 +88,8 @@ class testSO: XCTestCase { c.name = "composable" c.metadata["abc"] = 8 // c.metadata["blah"] = c // Cycles in the graph are currently disallowed - - + + XCTAssert(c.parent == nil) let c2 = try! c.clone() as! Composable @@ -98,16 +98,16 @@ class testSO: XCTestCase { XCTAssert(c2.visible) XCTAssert(!c2.overlapping) XCTAssertNil(c2.parent) - + print(try! c.toJSON()) } - + func test_Marker() { let tr = TimeRange(startTime: RationalTime(value: 1, rate: 2), duration: RationalTime(value: 4, rate: 30)) let m = Marker(name: "marker", markedRange: tr, color: Marker.Color.pink.rawValue) m.metadata["abc"] = 9 - + let m2 = try! m.clone() as! Marker XCTAssert(m2.name == "marker") XCTAssert(m2.metadata["abc"] == 9) @@ -115,13 +115,13 @@ class testSO: XCTestCase { XCTAssert(m2.color == Marker.Color.pink.rawValue) XCTAssert(Marker().color == Marker.Color.green.rawValue) } - + func test_SerializableCollection() { let m1 = Marker(name: "marker1") let c1 = Clip(name: "clip1") let sc = SerializableCollection(name: "sc", children: [m1, c1], metadata: []) sc.metadata["abc"] = 10 - + let sc2 = try! sc.clone() as! SerializableCollection XCTAssert(sc2.name == "sc") XCTAssert(sc2.metadata["abc"] == 10) @@ -137,16 +137,16 @@ class testSO: XCTestCase { let child1 = Composable(name: "Composable1") let child2 = Composable(name: "Composable2") let child3 = Composable(name: "Composable3") - + XCTAssert(child1.parent == nil) assertErrorType(.illegalIndex, expr: {try c1.remove(index: 0) }) XCTAssert(c1.children.map { $0 } == []) try! c1.append(child: child1); XCTAssert(c1.children.map { $0 } == [child1]) - + XCTAssert(child1.parent === c1) - + assertErrorType(.childAlreadyParented, expr: {try c1.append(child: child1)}) try! c1.append(child: child2) XCTAssert(c1.children.map { $0 } == [child1, child2]) @@ -184,13 +184,13 @@ class testSO: XCTestCase { func test_item() { let item = Item(name: "item1") item.metadata["abc"] = 11 - + let item2 = Item(name: item.name, metadata: item.metadata) let item3 = Item() - + let item4 = Item(name: "item4") item4.metadata["xyz"] = 12 - + let item5 = item2; XCTAssert(item.isEquivalent(to: item2)) @@ -206,12 +206,21 @@ class testSO: XCTestCase { XCTAssert(item.visible) XCTAssert(!item.overlapping) + XCTAssertTrue(item.enabled) + item.enabled = false + XCTAssertFalse(item.enabled) + item.enabled = true + XCTAssertTrue(item.enabled) + + let disabledItem = Item(name: "disabled", enabled: false) + XCTAssertFalse(disabledItem.enabled) + assertErrorType(.notImplemented) { try _ = item.duration() } assertErrorType(.notImplemented) { try _ = item.availableRange() } assertErrorType(.notImplemented) { try _ = item.trimmedRange() } assertErrorType(.notImplemented) { try _ = item.visibleRange() } assertErrorType(.notAChild) { try _ = item.rangeInParent() } - + let tr = TimeRange(startTime: RationalTime(value: 10, rate: 12), duration: RationalTime(value: 14, rate: 24)) XCTAssert(try item.transformed(time: tr.startTime, toItem: item) == tr.startTime) XCTAssert(try item.transformed(timeRange: tr, toItem: item) == tr) @@ -233,7 +242,7 @@ class testSO: XCTestCase { let mr1 = MediaReference() let clip = Clip(name: "clipA", mediaReference: mr1) let c2 = try! clip.clone() - + XCTAssert(clip.isEquivalent(to: c2)) XCTAssert(clip.mediaReference === mr1) } @@ -242,28 +251,28 @@ class testSO: XCTestCase { let s1 = Stack(name: "my-stack") XCTAssert(s1.isEquivalent(to: try! s1.clone())) print(try! s1.rangeOfAllChildren()) - + let result = try! Algorithms.flatten(stack: s1) let result2 = try! Algorithms.flatten(tracks: [result]) print(result) print(result2) } - + func test_timeline() { let t1 = Timeline(name: "t1", globalStartTime: RationalTime(value: 3, rate: 12)) let t2 = Timeline(name: "t2") XCTAssert(t2.globalStartTime == nil) - + t2.globalStartTime = t1.globalStartTime XCTAssert(t2.globalStartTime == t1.globalStartTime) t2.globalStartTime = nil XCTAssert(t2.globalStartTime == nil) - + XCTAssert(t1.isEquivalent(to: try! t1.clone())) let t3 = try! t1.clone() as! Timeline XCTAssert(t3.isEquivalent(to: t1)) } - + func testD0() { var v = Metadata.Vector() for i in 0..<10 { @@ -277,7 +286,7 @@ class testSO: XCTestCase { // print("[\(i)]: \(value)") // } } - + /* func testD2() { let xx = SerializableObjectWithMetadata() @@ -287,9 +296,9 @@ class testSO: XCTestCase { md["a3"] = 3 md["a4"] = 4 md["a5"] = 5 - + print(xx.metadata) - + for (key, value) in xx.metadata { if let v: Int = value as? Int { if v >= 3 { @@ -302,37 +311,37 @@ class testSO: XCTestCase { print("------------") _ = Metadata.Dictionary(arrayLiteral: ("integer", 123), ("Double", 3.14159), ("Bool", true)) - + xx.metadata["keys"] = Metadata.Vector(contents: md.map { $0.0 }) xx.metadata["this_is_cool"] = Metadata.Vector(arrayLiteral: 1, 3, "alpha") let mv = Metadata.Vector(arrayLiteral: 1, 3, "alpha", md) xx.metadata["this_is_really_cool"] = Metadata.Vector(mv.compactMap { ($0 as? Int) == nil ? $0 : nil }) - + var c = xx.metadata["this_is_really_cool"] as! Metadata.Vector c.append(45678) - + let d = (xx.metadata["this_is_really_cool"] as? Metadata.Vector)?.description // c1.append(12345) // xx.metadata["legal?"] = (3, 4) - + print(try! xx.toJSON()) } */ - + func testD1() { let xx = Clip() - + if let a: Int64 = xx.metadata["abc"] { print("Yes, abc is: ", a) } xx.metadata["abc"] = 3.2498 xx.metadata["nested_copy"] = xx.metadata["nested"] - + if let b: Double = xx.metadata["abc"] { print("[2] Yes, abc is now: ", b) } - + if let r1: RationalTime = (xx.metadata["nested"] as? Metadata.Dictionary)?["r1"] { print("Got r1: ", r1) } @@ -342,8 +351,7 @@ class testSO: XCTestCase { catch { print("OOPS: ", error) } - + print(xx.metadata) } } -