VSE: Refactor meta operators

Move low level logic to module code and versioning logic to versioning code.

Metas strip position was handled in diffrent way compared to other strips.
This was introduced in c8b0d25794 as bugfix for T28158.
I disagree with such design. Meta strips should be handled in same way as
any other strips.

I have tested this change and haven't found any problems.
No problems after checking T28158 as well.
There should be no functional changes on user level.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D9972
This commit is contained in:
Richard Antalik 2021-03-02 12:34:03 +01:00
parent b3005bf688
commit e1f3996d74
Notes: blender-bot 2023-10-04 09:42:55 +02:00
Referenced by commit 41c0c79e31, VSE: Fix meta strip boundary can not be changed
7 changed files with 162 additions and 235 deletions

View File

@ -69,6 +69,8 @@
#include "SEQ_proxy.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
#include "SEQ_transform.h"
#include "BLO_readfile.h"
#include "readfile.h"
@ -332,6 +334,33 @@ static void seq_convert_transform_crop_lb_2(const Scene *scene,
}
}
static void seq_update_meta_disp_range(Scene *scene, Editing *ed)
{
LISTBASE_FOREACH_BACKWARD (MetaStack *, ms, &ed->metastack) {
/* Update ms->disp_range from meta. */
if (ms->disp_range[0] == ms->disp_range[1]) {
copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
}
/* Update meta strip endpoints. */
SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]);
SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]);
SEQ_transform_fix_single_image_seq_offsets(ms->parseq);
/* Recalculate effects using meta strip. */
LISTBASE_FOREACH (Sequence *, seq, ms->oldbasep) {
if (seq->seq2) {
seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
}
}
/* Ensure that active seqbase points to active meta strip seqbase. */
MetaStack *active_ms = SEQ_meta_stack_active_get(ed);
SEQ_seqbase_active_set(ed, &active_ms->parseq->seqbase);
}
}
void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
{
if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) {
@ -606,6 +635,10 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
seq_update_meta_disp_range(scene, SEQ_editing_get(scene, false));
}
}
}

View File

@ -1870,93 +1870,28 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot)
/** \name Toggle Meta Strip Operator
* \{ */
void recurs_sel_seq(Sequence *seqm)
{
Sequence *seq;
seq = seqm->seqbase.first;
while (seq) {
if (seqm->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) {
seq->flag &= ~SEQ_ALLSEL;
}
else if (seqm->flag & SELECT) {
seq->flag |= SELECT;
}
else {
seq->flag &= ~SEQ_ALLSEL;
}
if (seq->seqbase.first) {
recurs_sel_seq(seq);
}
seq = seq->next;
}
}
static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, false);
Sequence *last_seq = SEQ_select_active_get(scene);
MetaStack *ms;
Sequence *active_seq = SEQ_select_active_get(scene);
if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) {
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
/* Enter metastrip. */
ms = MEM_mallocN(sizeof(MetaStack), "metastack");
BLI_addtail(&ed->metastack, ms);
ms->parseq = last_seq;
ms->oldbasep = ed->seqbasep;
copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
ed->seqbasep = &last_seq->seqbase;
SEQ_meta_stack_alloc(ed, active_seq);
SEQ_seqbase_active_set(ed, &active_seq->seqbase);
SEQ_select_active_set(scene, NULL);
}
else {
/* Exit metastrip if possible. */
Sequence *seq;
if (BLI_listbase_is_empty(&ed->metastack)) {
return OPERATOR_CANCELLED;
}
ms = ed->metastack.last;
BLI_remlink(&ed->metastack, ms);
ed->seqbasep = ms->oldbasep;
/* For old files, update from meta. */
if (ms->disp_range[0] == ms->disp_range[1]) {
copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
}
/* Recalc all: the meta can have effects connected to it. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
SEQ_time_update_sequence(scene, seq);
}
/* 2.73+, keeping endpoints is important!
* Moving them around means you can't usefully use metas in a complex edit. */
#if 1
SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]);
SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]);
SEQ_transform_fix_single_image_seq_offsets(ms->parseq);
SEQ_time_update_sequence(scene, ms->parseq);
#else
if (SEQ_transform_test_overlap(ed->seqbasep, ms->parseq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, ms->parseq, scene);
}
#endif
MetaStack *ms = SEQ_meta_stack_active_get(ed);
SEQ_seqbase_active_set(ed, ms->oldbasep);
SEQ_select_active_set(scene, ms->parseq);
ms->parseq->flag |= SELECT;
recurs_sel_seq(ms->parseq);
MEM_freeN(ms);
SEQ_meta_stack_free(ed, ms);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@ -1990,48 +1925,44 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, false);
Sequence *active_seq = SEQ_select_active_get(scene);
ListBase *active_seqbase = SEQ_active_seqbase_get(ed);
Sequence *seq, *seqm, *next, *last_seq = SEQ_select_active_get(scene);
int channel_max = 1;
if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) {
if (SEQ_transform_seqbase_isolated_sel_check(active_seqbase) == false) {
BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
return OPERATOR_CANCELLED;
}
SEQ_prefetch_stop(scene);
/* Remove all selected from main list, and put in meta. */
int channel_max = 1, meta_start_frame = MAXFRAME, meta_end_frame = MINFRAME;
Sequence *seqm = SEQ_sequence_alloc(active_seqbase, 1, 1, SEQ_TYPE_META);
seqm = SEQ_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */
strcpy(seqm->name + 2, "MetaStrip");
seqm->flag = SELECT;
seq = ed->seqbasep->first;
while (seq) {
next = seq->next;
if (seq != seqm && (seq->flag & SELECT)) {
SEQ_relations_invalidate_cache_composite(scene, seq);
channel_max = max_ii(seq->machine, channel_max);
/* Sequence is moved within the same edit, no need to re-generate the UUID. */
BLI_remlink(ed->seqbasep, seq);
/* Remove all selected from main list, and put in meta.
* Sequence is moved within the same edit, no need to re-generate the UUID. */
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, active_seqbase) {
if (seq != seqm && seq->flag & SELECT) {
BLI_remlink(active_seqbase, seq);
BLI_addtail(&seqm->seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
channel_max = max_ii(seq->machine, channel_max);
meta_start_frame = min_ii(seq->startdisp, meta_start_frame);
meta_end_frame = max_ii(seq->enddisp, meta_end_frame);
}
seq = next;
}
seqm->machine = last_seq ? last_seq->machine : channel_max;
seqm->machine = active_seq ? active_seq->machine : channel_max;
strcpy(seqm->name + 2, "MetaStrip");
SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seqm);
seqm->start = meta_start_frame;
seqm->len = meta_end_frame - meta_start_frame;
SEQ_time_update_sequence(scene, seqm);
SEQ_select_active_set(scene, seqm);
if (SEQ_transform_test_overlap(ed->seqbasep, seqm)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seqm, scene);
if (SEQ_transform_test_overlap(active_seqbase, seqm)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm);
SEQ_relations_invalidate_cache_composite(scene, seqm);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -2058,95 +1989,43 @@ void SEQUENCER_OT_meta_make(wmOperatorType *ot)
/** \name UnMeta Strip Operator
* \{ */
static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
{
if (seq == seqm) {
return 1;
}
if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) {
return 1;
}
if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) {
return 1;
}
if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) {
return 1;
}
return 0;
}
static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall)
{
Sequence *seq, *seqn;
Sequence *last_seq = SEQ_select_active_get(scene);
seq = lb->first;
while (seq) {
seqn = seq->next;
if ((seq->flag & flag) || deleteall) {
BLI_remlink(lb, seq);
if (seq == last_seq) {
SEQ_select_active_set(scene, NULL);
}
if (seq->type == SEQ_TYPE_META) {
recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
}
SEQ_sequence_free(scene, seq, true);
}
seq = seqn;
}
}
static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene, false);
Sequence *active_seq = SEQ_select_active_get(scene);
Sequence *seq, *last_seq = SEQ_select_active_get(scene); /* last_seq checks (ed == NULL) */
if (last_seq == NULL || last_seq->type != SEQ_TYPE_META) {
if (active_seq == NULL || active_seq->type != SEQ_TYPE_META) {
return OPERATOR_CANCELLED;
}
SEQ_prefetch_stop(scene);
for (seq = last_seq->seqbase.first; seq != NULL; seq = seq->next) {
SEQ_relations_invalidate_cache_composite(scene, seq);
LISTBASE_FOREACH (Sequence *, seq, &active_seq->seqbase) {
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
/* This moves strips from meta to parent, sating within same edit and no new strips are
* allocated. If the UUID was unique already (as it should) it will stay unique.
* No need to re-generate the UUIDs. */
BLI_movelisttolist(ed->seqbasep, &last_seq->seqbase);
/* Remove all selected from meta, and put in main list.
* Sequence is moved within the same edit, no need to re-generate the UUID. */
BLI_movelisttolist(ed->seqbasep, &active_seq->seqbase);
BLI_listbase_clear(&active_seq->seqbase);
BLI_listbase_clear(&last_seq->seqbase);
ListBase *active_seqbase = SEQ_active_seqbase_get(ed);
SEQ_edit_flag_for_removal(scene, active_seqbase, active_seq);
SEQ_edit_remove_flagged_sequences(scene, active_seqbase);
BLI_remlink(ed->seqbasep, last_seq);
SEQ_sequence_free(scene, last_seq, true);
/* Empty meta strip, delete all effects depending on it. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq_depends_on_meta(seq, last_seq)) {
seq->flag |= SEQ_FLAG_DELETE;
}
}
recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0);
/* Test for effects and overlap
* don't use SEQ_CURRENT_BEGIN since that would be recursive. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
/* Test for effects and overlap. */
LISTBASE_FOREACH (Sequence *, seq, active_seqbase) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_OVERLAP;
if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
if (SEQ_transform_test_overlap(active_seqbase, seq)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seq, scene);
}
}
}
SEQ_sort(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;

View File

@ -360,6 +360,31 @@ static void select_neighbor_from_last(Scene *scene, int lr)
}
#endif
void recurs_sel_seq(Sequence *seq_meta)
{
Sequence *seq;
seq = seq_meta->seqbase.first;
while (seq) {
if (seq_meta->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) {
seq->flag &= ~SEQ_ALLSEL;
}
else if (seq_meta->flag & SELECT) {
seq->flag |= SELECT;
}
else {
seq->flag &= ~SEQ_ALLSEL;
}
if (seq->seqbase.first) {
recurs_sel_seq(seq);
}
seq = seq->next;
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -90,35 +90,17 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c
Scene *scene = t->scene;
int cfra = CFRA;
int left = SEQ_transform_get_left_handle_frame(seq, true);
int right = SEQ_transform_get_right_handle_frame(seq, true);
int left = SEQ_transform_get_left_handle_frame(seq, false);
int right = SEQ_transform_get_right_handle_frame(seq, false);
if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
*r_recursive = false;
*r_count = 0;
*r_flag = 0;
}
else if (seq->type == SEQ_TYPE_META) {
/* for meta's we only ever need to extend their children, no matter what depth
* just check the meta's are in the bounds */
if (t->frame_side == 'R' && right <= cfra) {
*r_recursive = false;
}
else if (t->frame_side == 'L' && left >= cfra) {
*r_recursive = false;
}
else {
*r_recursive = true;
}
*r_count = 1;
*r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
}
else {
*r_recursive = false; /* not a meta, so no thinking here */
*r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */
*r_recursive = false;
*r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */
*r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
if (t->frame_side == 'R') {
@ -183,26 +165,9 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c
else {
/* Nested, different rules apply */
#ifdef SEQ_TX_NESTED_METAS
*r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
*r_count = 1; /* ignore the selection for nested */
*r_recursive = (seq->type == SEQ_TYPE_META);
#else
if (seq->type == SEQ_TYPE_META) {
/* Meta's can only directly be moved between channels since they
* don't have their start and length set directly (children affect that)
* since this Meta is nested we don't need any of its data in fact.
* SEQ_time_update_sequence() will update its settings when run on the top-level meta. */
*r_flag = 0;
*r_count = 0;
*r_recursive = true;
}
else {
*r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
*r_count = 1; /* ignore the selection for nested */
*r_recursive = false;
}
#endif
}
}
}
@ -645,8 +610,6 @@ void createTransSeqData(TransInfo *t)
/* commented _only_ because the meta may have animation data which
* needs moving too T28158. */
#define SEQ_TX_NESTED_METAS
BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
{
if (seq->depth == 0) {
@ -693,17 +656,10 @@ static void flushTransSeq(TransInfo *t)
switch (tdsq->sel_flag) {
case SELECT:
#ifdef SEQ_TX_NESTED_METAS
if ((seq->depth != 0 || SEQ_transform_sequence_can_be_translated(seq))) {
/* for meta's, their children move */
seq->start = new_frame - tdsq->start_offset;
}
#else
if (seq->type != SEQ_TYPE_META && (seq->depth != 0 || seq_tx_test(seq))) {
/* for meta's, their children move */
seq->start = new_frame - tdsq->start_offset;
}
#endif
if (seq->depth == 0) {
seq->machine = round_fl_to_int(td2d->loc[1]);
CLAMP(seq->machine, 1, MAXSEQ);

View File

@ -62,8 +62,12 @@ struct Editing *SEQ_editing_get(struct Scene *scene, bool alloc);
struct Editing *SEQ_editing_ensure(struct Scene *scene);
void SEQ_editing_free(struct Scene *scene, const bool do_id_user);
struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed);
void SEQ_seqbase_active_set(struct Editing *ed, struct ListBase *seqbase);
struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type);
void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata);
struct MetaStack *SEQ_meta_stack_alloc(struct Editing *ed, struct Sequence *seq_meta);
struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms);
void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst);
struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src,

View File

@ -344,6 +344,58 @@ ListBase *SEQ_active_seqbase_get(const Editing *ed)
return ed->seqbasep;
}
/**
* Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
*
* \param ed: sequence editor data
* \param seqbase: ListBase with strips
*/
void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase)
{
ed->seqbasep = seqbase;
}
/**
* Create and initialize MetaStack, append it to ed->metastack ListBase
*
* \param ed: sequence editor data
* \param seq_meta: meta strip
* \return pointer to created meta stack
*/
MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
{
MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack");
BLI_addtail(&ed->metastack, ms);
ms->parseq = seq_meta;
ms->oldbasep = ed->seqbasep;
copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
return ms;
}
/**
* Free MetaStack and remoove it from ed->metastack ListBase
*
* \param ed: sequence editor data
* \param ms: meta stack
*/
void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
{
BLI_remlink(&ed->metastack, ms);
MEM_freeN(ms);
}
/**
* Get MetaStack that coresponds to current level that is being viewed
*
* \param ed: sequence editor data
* \return pointer to meta stack
*/
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
return ed->metastack.last;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -164,7 +164,6 @@ void SEQ_time_update_sequence_bounds(Scene *scene, Sequence *seq)
void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
{
Sequence *seqm;
int min, max;
/* check all metas recursively */
seqm = seq->seqbase.first;
@ -212,27 +211,6 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq)
}
}
else {
if (seq->type == SEQ_TYPE_META) {
seqm = seq->seqbase.first;
if (seqm) {
min = MAXFRAME * 2;
max = -MAXFRAME * 2;
while (seqm) {
if (seqm->startdisp < min) {
min = seqm->startdisp;
}
if (seqm->enddisp > max) {
max = seqm->enddisp;
}
seqm = seqm->next;
}
seq->start = min + seq->anim_startofs;
seq->len = max - min;
seq->len -= seq->anim_startofs;
seq->len -= seq->anim_endofs;
}
seq_update_sound_bounds_recursive(scene, seq);
}
SEQ_time_update_sequence_bounds(scene, seq);
}
}