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

When slipping meta strip, effect position was not updated. These updates
are limited to VSE core code, so function `SEQ_time_slip_strip()` was
added to resolve this issue.

This also simplifies operator code, so it does not have to deal with
recursion and doesn't need to hold quite detailed strip state for when
operator is cancelled.

Pull Request: https://projects.blender.org/blender/blender/pulls/113200
This commit is contained in:
ok_what
2023-12-21 18:04:56 +01:00
committed by Richard Antalik
parent 548b45d13b
commit 04efca91f9
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)
{
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);
}
}
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);
}