Skip to content

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.