engine: timeline edit primitives round 2 (split/ripple-delete/trim/move)

All four are undoable and reuse the timeline/ command classes verbatim
(BlockSplitCommand, TrackRippleRemoveAreaCommand, BlockTrimCommand,
ReplaceBlockWithGap+PlaceBlock), with undo/redo assertions covering
split halves, media-in alignment on trim, ripple shift amounts, and
full restoration on undo
This commit is contained in:
2026-07-20 07:52:07 +08:00
parent b9b5ad09f7
commit 1ab7fa49a0
3 changed files with 462 additions and 14 deletions
+65
View File
@@ -278,6 +278,71 @@ OAKENGINE_API int oakengine_clip_get_range(const OakEngineClip *self,
int64_t *in, int64_t *out,
int64_t *media_in);
/* ---- Editing primitives, round 2: split / ripple delete / trim / move ----
*
* All four are undoable like the other editing primitives and report
* failures through oakengine_sequence_last_error(). Clips are addressed by
* (track_type, track_index, clip_index) exactly like
* oakengine_sequence_clip_at() (gap blocks are skipped). All times are
* frame timestamps in the sequence's frame-rate timebase.
*/
/**
* @brief Split the addressed clip in two at timeline `time` (undoable;
* olive::BlockSplitCommand).
*
* `time` must lie strictly inside the clip's range. The left part keeps the
* clip's in-point, the right part starts at `time` with its media in-point
* advanced accordingly (the engine's split semantics). Returns OAKENGINE_OK
* or a negative code (OAKENGINE_E_NOT_FOUND for a missing clip,
* OAKENGINE_E_INVALID for a time outside the clip).
*/
OAKENGINE_API int oakengine_sequence_split_clip(OakEngineSequence *seq,
int track_type,
int track_index,
int clip_index, int64_t time);
/**
* @brief Delete the addressed clip and shift all following clips on the
* track left by its length (undoable;
* olive::TrackRippleRemoveAreaCommand).
*/
OAKENGINE_API int oakengine_sequence_ripple_delete_clip(OakEngineSequence *seq,
int track_type,
int track_index,
int clip_index);
/**
* @brief Change the clip's timeline range (undoable; olive::BlockTrimCommand,
* the application's trim command).
*
* Pass the current value for the end that should stay unchanged; changing
* both ends is applied as an in-trim followed by an out-trim in one
* undoable command. Requires new_out > new_in and new_in >= 0. When the
* in-point moves, the clip's media in-point moves with it (the engine's
* set_length_and_media_in() alignment); adjacent gaps absorb the difference
* (the engine's trim semantics, adjacent clips are not rolled). The clip
* handle must still be on a track.
*/
OAKENGINE_API int oakengine_clip_trim(OakEngineClip *clip, int64_t new_in,
int64_t new_out);
/**
* @brief Move the addressed clip to start at `new_in` on the same track
* (undoable).
*
* Length and media in-point are preserved; the old spot is filled with a
* gap (olive::TrackReplaceBlockWithGapCommand) and the clip is placed at
* the destination (olive::TrackPlaceBlockCommand, which ripples whatever
* was there). Moving across tracks is a later milestone. `new_in` must be
* >= 0.
*/
OAKENGINE_API int oakengine_sequence_move_clip(OakEngineSequence *seq,
int track_type,
int track_index,
int clip_index,
int64_t new_in);
#ifdef __cplusplus
}
#endif