Iterator¶
To make work with sets of strips easier, iterator system can be used.
Main design goal is to provide means to inline logic, instead of
creating callback functions. SeqCollection
structure defines a set
of strips and can be iterated on by SEQ_ITERATOR_FOREACH
macro,
similar to LISTBASE_FOREACH
macro. To create SeqCollection
, most
common queries are available, but custom functions can be created. Use
of this iterator system is encouraged everywhere where maximum possible
performance is not essential. Because SeqCollection
can be reused
multiple times and it can be passed as argument, it may be faster than
looping over strips multiple times.
For cases where logic may be complicated such as working on strips not
only selected by simple criteria, but also their relationships, there
are functions for combining, filtering and expanding SeqCollection
.
This way a bulk of logic responsible for selecting strips that are
operated on can be separated from functional logic which does change
their data.
Implementation should be well documented, but good example is for
example select_grouped_effect_link()
:
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
static bool select_grouped_effect_link(SeqCollection *strips,
ListBase *seqbase,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
/* Get collection of strips. */
SEQ_filter_selected_strips(strips);
const int selected_strip_count = SEQ_collection_len(strips);
SEQ_collection_expand(seqbase, strips, query_lower_channel_strips);
SEQ_collection_expand(seqbase, strips, SEQ_query_strip_effect_chain);
/* Check if other strips will be affected. */
const bool changed = SEQ_collection_len(strips) > selected_strip_count;
/* Actual logic. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
seq->flag |= SELECT;
}
return changed;
}
This function is supplied with collection of strips, contents depend on
whether operator is executed from preview where only visible strips are
considered, or timeline, in which case all strips will be included.
First collection is filtered to only selected strips. Number of strips
is saved for later comparison to check if this operation had any effect.
Function SEQ_collection_expand()
is used to expand original
collection. In practice this means that each strip in sequencer is
compared to each strip in provided collection. Callback query function
then does selection based on its internal logic. in case of
query_lower_channel_strips()
, strip is selected if it is visually
under strips from provided collection. in similar fashion, function
SEQ_query_strip_effect_chain
selects every strip, that has effect
relationship to strips in provided collection. These are quite
complicated selection criteria, that would be hard to parse if done by
plain LISTBASE_FOREACH
iterations. Finally collection is iterated
and operator logic is executed - strips are selected.
Note, implementation of this design may change a bit, for example
SEQ_query_strip_effect_chain
may become standalone function, that
will take SeqCollection
as argument. Function
SEQ_collection_expand()
is used mainly because it does include logic
to prevent infinite loops which are likely in more complicated queries.