| Mapping Timeline position to Track position | |
| ------------------------------------------- | |
| TrackObject/TimelineObject basic properties (hereafter position): | |
| start | |
| duration | |
| in-point | |
| priority | |
| Use Cases: | |
| A TimelineObject tracks one or many TrackObject(s). | |
| When the TimelineObject position is modified we might need | |
| to cascade those changes to the controlled TrackObject(s) if those | |
| TrackObject(s) are 'locked' to the TimelineObject. | |
| If we modify the positions of a TrackObject that TrackObject is | |
| 'locked' to the TimelineObject, we need to ensure all the other | |
| co-related TrackObject belong to the same TimelineObject are moved in | |
| the same way. | |
| A TrackObject can be temporarily 'unlocked' from its TimelineObject, | |
| so as to move it independently, and then 'locked' back to it. This | |
| can allow moves, like shifting audio trackobject in relation to the | |
| video trackobject (to fix sync issues) and then 'lock' them back so | |
| as to be able to move them as one entity thereafter. | |
| When adding TimelineOverlay(s) or TimelineEffect(s) on a | |
| TimelineObject, we need to ensure the TrackObject(s) that those extra | |
| effects will create can be added with specific priority offsets, in | |
| such a way that they always end up "on top" of the TimelineObject's | |
| existing tracked TrackObject(s). | |
| When a controlled TrackObject is being moved when 'unlocked', we need | |
| to make sure the duration/height of the TimelineObject is updated | |
| accordingly. Ex : moving a TrackObject down by one priority should | |
| increase the TimelineObject "heigh" property by 1. | |
| A TimelineObject might want to have a tighter control over which | |
| Track(s) each of the TrackObjects it is controlling are going. This | |
| is more obvious in the case of timeline with multiple Tracks of the | |
| same kind, or if a TimelineObject can produce multiple TrackObjects | |
| of the same media type (ex: file with multiple audio tracks). | |
| Main Problem: | |
| There needs to be a mapping between the TimelineObject basic | |
| properties and its controlled TrackObject(s) position. | |
| Design: | |
| The TimelineObject listen to TrackObject 'notify' signals | |
| When it sets a property on its trackobjects, it 'ignores' all | |
| notifications that happen while setting them. | |
| Setting a property on a TrackObject will see its property changed, | |
| and then it emits a notify with the modified property. | |
| TrackObject::locked | |
| ges_track_object_set_locked() | |
| ges_track_object_is_locked() | |
| Mapping { | |
| GESTrackObject *object; | |
| gint64 start_offset; | |
| gint64 duration_offset; | |
| gint64 inpoint_offset; | |
| gint32 priority_offset; | |
| /* Track ??? */ | |
| } | |
| P : property | |
| V : value | |
| TimelineObject set_property(P,V) | |
| ignore_notifies = TRUE | |
| parent.P = V | |
| foreach child in trackobjects: | |
| if child.is_locked(): | |
| child.set_property(P, parent.P + mapping(child).P_offset) | |
| ignore_notifies = FALSE | |
| TimelineObject child 'notify::P' handler: | |
| if ignore_notifies: | |
| return | |
| if not child.is_locked(): | |
| mapping(child).P_offset = timeline.P - child.P | |
| else: | |
| TimelineObject.set_property(P, child value + mapping(child).P_offset) | |
| TrackObject set_property(P, V) | |
| update the property locally (P = V) | |
| emit 'notify::P' signal | |
| TODO : When do we resync the parent values to have minimal offsets ? |