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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user