Fix: VSE Slip Strips operator doesn't move effect strips inside of a meta strip. #113200

Merged
Richard Antalik merged 4 commits from ok_what/blender:vse-slip-effect-bug into main 2023-12-21 18:05:07 +01:00
3 changed files with 101 additions and 111 deletions

View File

@ -480,74 +480,34 @@ void SEQUENCER_OT_snap(wmOperatorType *ot)
* \{ */
struct SlipData {
int init_mouse[2];
float init_mouseloc[2];
TransSeq *ts;
int previous_offset;
Sequence **seq_array;
bool *trim;
int num_seq;
bool slow;
int slow_offset; /* Offset at the point where offset was turned on. */
NumInput num_input;
};
static void transseq_backup(TransSeq *ts, Sequence *seq)
static void slip_add_sequences(ListBase *seqbasep, Sequence **seq_array)
{
ts->content_start = SEQ_time_start_frame_get(seq);
ts->start = seq->start;
ts->machine = seq->machine;
ts->startofs = seq->startofs;
ts->endofs = seq->endofs;
ts->anim_startofs = seq->anim_startofs;
ts->anim_endofs = seq->anim_endofs;
ts->len = seq->len;
}
static void transseq_restore(TransSeq *ts, Sequence *seq)
{
seq->start = ts->start;
seq->machine = ts->machine;
seq->startofs = ts->startofs;
seq->endofs = ts->endofs;
seq->anim_startofs = ts->anim_startofs;
seq->anim_endofs = ts->anim_endofs;
seq->len = ts->len;
}
static int slip_add_sequences_recursive(
ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim)
{
int num_items = 0;
int i = 0;
LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
if (!do_trim || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
seq_array[offset + num_items] = seq;
trim[offset + num_items] = do_trim && ((seq->type & SEQ_TYPE_EFFECT) == 0);
num_items++;
if (seq->type == SEQ_TYPE_META) {
/* Trim the sub-sequences. */
num_items += slip_add_sequences_recursive(
&seq->seqbase, seq_array, trim, num_items + offset, false);
}
if (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT)) {
seq_array[i] = seq;
i++;
}
}
return num_items;
}
static int slip_count_sequences_recursive(ListBase *seqbasep, bool first_level)
static int slip_count_sequences(ListBase *seqbasep)
{
int trimmed_sequences = 0;
LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
if (!first_level || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
if (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT)) {
trimmed_sequences++;
if (seq->type == SEQ_TYPE_META) {
/* Trim the sub-sequences. */
trimmed_sequences += slip_count_sequences_recursive(&seq->seqbase, false);
}
}
}
@ -563,8 +523,8 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
int num_seq;
View2D *v2d = UI_view2d_fromcontext(C);
/* Recursively count the trimmed elements. */
num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
/* Count the amount of elements to trim. */
num_seq = slip_count_sequences(ed->seqbasep);
if (num_seq == 0) {
return OPERATOR_CANCELLED;
@ -572,10 +532,9 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
data = MEM_cnew<SlipData>("trimdata");
op->customdata = static_cast<void *>(data);
data->ts = MEM_cnew_array<TransSeq>(num_seq, "trimdata_transform");
data->seq_array = MEM_cnew_array<Sequence *>(num_seq, "trimdata_sequences");
data->trim = MEM_cnew_array<bool>(num_seq, "trimdata_trim");
data->num_seq = num_seq;
data->previous_offset = 0;
initNumInput(&data->num_input);
data->num_input.idx_max = 0;
@ -583,15 +542,10 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
data->num_input.unit_sys = USER_UNIT_NONE;
data->num_input.unit_type[0] = 0;
slip_add_sequences_recursive(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (int i = 0; i < num_seq; i++) {
transseq_backup(data->ts + i, data->seq_array[i]);
}
slip_add_sequences(ed->seqbasep, data->seq_array);
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
copy_v2_v2_int(data->init_mouse, event->mval);
copy_v2_v2(data->init_mouseloc, mouseloc);
data->slow = false;
@ -604,7 +558,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_RUNNING_MODAL;
}
static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
static void sequencer_slip_strips(Scene *scene, SlipData *data, int delta)

I guess this function is not recursive anymore?

I guess this function is not recursive anymore?
{
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
@ -614,11 +568,7 @@ static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
continue;
}
seq->start = data->ts[i].start + offset;
if (data->trim[i]) {
seq->startofs = data->ts[i].startofs - offset;
seq->endofs = data->ts[i].endofs + offset;
}
SEQ_time_slip_strip(scene, seq, delta);
}
for (int i = data->num_seq - 1; i >= 0; i--) {
@ -627,26 +577,31 @@ static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
}
}
/* Make sure, that each strip contains at least 1 frame of content. */
static void sequencer_slip_apply_limits(const Scene *scene, SlipData *data, int *offset)
/* Make sure, that each strip contains at least 1 frame of content.
* Returns clamped offset relative to current strip positions. */
static int sequencer_slip_apply_limits(const Scene *scene, SlipData *data, int *offset)
{
int delta_offset = *offset - data->previous_offset;
for (int i = 0; i < data->num_seq; i++) {
if (data->trim[i]) {
Sequence *seq = data->seq_array[i];
int seq_content_start = data->ts[i].start + *offset;
int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
int diff = 0;
Sequence *seq = data->seq_array[i];
int seq_content_start = SEQ_time_start_frame_get(seq) + delta_offset;
int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
int diff = 0;
if (seq_content_start >= SEQ_time_right_handle_frame_get(scene, seq)) {
diff = SEQ_time_right_handle_frame_get(scene, seq) - seq_content_start - 1;
}
if (seq_content_end <= SEQ_time_left_handle_frame_get(scene, seq)) {
diff = SEQ_time_left_handle_frame_get(scene, seq) - seq_content_end + 1;
}
*offset += diff;
if (seq_content_start >= SEQ_time_right_handle_frame_get(scene, seq)) {
diff = SEQ_time_right_handle_frame_get(scene, seq) - seq_content_start - 1;
}
if (seq_content_end <= SEQ_time_left_handle_frame_get(scene, seq)) {
diff = SEQ_time_left_handle_frame_get(scene, seq) - seq_content_end + 1;
}
*offset += diff;
delta_offset += diff;
}
data->previous_offset = *offset;
return delta_offset;
}
static int sequencer_slip_exec(bContext *C, wmOperator *op)
@ -655,8 +610,8 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
Editing *ed = SEQ_editing_get(scene);
int offset = RNA_int_get(op->ptr, "offset");
/* Recursively count the trimmed elements. */
int num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
/* Count the amount of elements to trim. */
int num_seq = slip_count_sequences(ed->seqbasep);
if (num_seq == 0) {
return OPERATOR_CANCELLED;
@ -664,23 +619,15 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
SlipData *data = MEM_cnew<SlipData>("trimdata");
op->customdata = static_cast<void *>(data);
data->ts = MEM_cnew_array<TransSeq>(num_seq, "trimdata_transform");
data->seq_array = MEM_cnew_array<Sequence *>(num_seq, "trimdata_sequences");
data->trim = MEM_cnew_array<bool>(num_seq, "trimdata_trim");
data->num_seq = num_seq;
slip_add_sequences_recursive(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (int i = 0; i < num_seq; i++) {
transseq_backup(data->ts + i, data->seq_array[i]);
}
slip_add_sequences(ed->seqbasep, data->seq_array);
sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_recursively(scene, data, offset);
sequencer_slip_strips(scene, data, offset);
MEM_freeN(data->seq_array);
MEM_freeN(data->trim);
MEM_freeN(data->ts);
MEM_freeN(data);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@ -708,7 +655,6 @@ static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData *
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SlipData *data = (SlipData *)op->customdata;
ScrArea *area = CTX_wm_area(C);
@ -721,12 +667,13 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
applyNumInput(&data->num_input, &offset_fl);
int offset = round_fl_to_int(offset_fl);
sequencer_slip_apply_limits(scene, data, &offset);
const int delta_offset = sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
sequencer_slip_recursively(scene, data, offset);
sequencer_slip_strips(scene, data, delta_offset);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_RUNNING_MODAL;
@ -753,12 +700,13 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
offset = mouseloc[0] - data->init_mouseloc[0];
sequencer_slip_apply_limits(scene, data, &offset);
const int delta_offset = sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
sequencer_slip_recursively(scene, data, offset);
sequencer_slip_strips(scene, data, delta_offset);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
}
break;
@ -768,8 +716,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
case EVT_RETKEY:
case EVT_SPACEKEY: {
MEM_freeN(data->seq_array);
MEM_freeN(data->trim);
MEM_freeN(data->ts);
MEM_freeN(data);
op->customdata = nullptr;
if (area) {
@ -782,18 +728,10 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
case EVT_ESCKEY:
case RIGHTMOUSE: {
for (int i = 0; i < data->num_seq; i++) {
transseq_restore(data->ts + i, data->seq_array[i]);
}
for (int i = 0; i < data->num_seq; i++) {
Sequence *seq = data->seq_array[i];
SEQ_add_reload_new_file(bmain, scene, seq, false);
}
int offset = RNA_int_get(op->ptr, "offset");
sequencer_slip_strips(scene, data, -offset);
MEM_freeN(data->seq_array);
MEM_freeN(data->ts);
MEM_freeN(data->trim);
MEM_freeN(data);
op->customdata = nullptr;
@ -830,12 +768,13 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
applyNumInput(&data->num_input, &offset_fl);
int offset = round_fl_to_int(offset_fl);
sequencer_slip_apply_limits(scene, data, &offset);
const int delta_offset = sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
sequencer_slip_recursively(scene, data, offset);
sequencer_slip_strips(scene, data, delta_offset);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
}

View File

@ -120,7 +120,10 @@ void SEQ_time_start_frame_set(const Scene *scene, Sequence *seq, int timeline_fr
* \note this function is currently only used internally and in versioning code.
*/
void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta);
/**
* Move contents of a strip without moving the strip handles.
*/
void SEQ_time_slip_strip(const Scene *scene, Sequence *seq, int delta);
/**
* Get difference between scene and movie strip frame-rate.
*/

View File

@ -576,3 +576,51 @@ void seq_time_translate_handles(const Scene *scene, Sequence *seq, const int off
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
static void seq_time_slip_strip_ex(const Scene *scene, Sequence *seq, int delta, bool recursed)
{
if (delta == 0) {
return;
}
/* Skip effect strips where the length is dependent on another strip,
* as they are calculated with #seq_time_update_effects_strip_range. */
if (seq->seq1 != nullptr || seq->seq2 != nullptr) {
return;
}
/* Effects only have a start frame and a length, so unless we're inside
* a meta strip, there's no need to do anything. */
if (!recursed && (seq->type & SEQ_TYPE_EFFECT)) {
return;
}
/* Move strips inside meta strip. */
if (seq->type == SEQ_TYPE_META) {
/* If the meta strip has no contents, don't do anything. */
if (BLI_listbase_is_empty(&seq->seqbase)) {
return;
}
LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
seq_time_slip_strip_ex(scene, seq_child, delta, true);
ok_what marked this conversation as resolved
Review

Please use LISTBASE_FOREACH macro

Please use `LISTBASE_FOREACH` macro
}
}
seq->start = seq->start + delta;
if (!recursed) {
seq->startofs = seq->startofs - delta;
seq->endofs = seq->endofs + delta;
}
/* Only to make files usable in older versions. */
seq->startdisp = SEQ_time_left_handle_frame_get(scene, seq);
seq->enddisp = SEQ_time_right_handle_frame_get(scene, seq);
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
seq_time_update_effects_strip_range(scene, effects);
}
void SEQ_time_slip_strip(const Scene *scene, Sequence *seq, int delta)
{
seq_time_slip_strip_ex(scene, seq, delta, false);
}