1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edanimation
22  */
23 
24 /* This file contains a system used to provide a layer of abstraction between sources
25  * of animation data and tools in Animation Editors. The method used here involves
26  * generating a list of edit structures which enable tools to naively perform the actions
27  * they require without all the boiler-plate associated with loops within loops and checking
28  * for cases to ignore.
29  *
30  * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
31  * the Graph Editor also uses this for its channel list and for determining which curves
32  * are being edited. Likewise, the NLA Editor also uses this for its channel list and in
33  * its operators.
34  *
35  * Note: much of the original system this was based on was built before the creation of the RNA
36  * system. In future, it would be interesting to replace some parts of this code with RNA queries,
37  * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this
38  * system, so if any such work does occur, it should only be used for the internals used here...
39  *
40  * -- Joshua Leung, Dec 2008 (Last revision July 2009)
41  */
42 
43 #include <string.h>
44 
45 #include "DNA_anim_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_brush_types.h"
48 #include "DNA_cachefile_types.h"
49 #include "DNA_camera_types.h"
50 #include "DNA_gpencil_types.h"
51 #include "DNA_hair_types.h"
52 #include "DNA_key_types.h"
53 #include "DNA_lattice_types.h"
54 #include "DNA_layer_types.h"
55 #include "DNA_light_types.h"
56 #include "DNA_linestyle_types.h"
57 #include "DNA_mask_types.h"
58 #include "DNA_material_types.h"
59 #include "DNA_mesh_types.h"
60 #include "DNA_meta_types.h"
61 #include "DNA_movieclip_types.h"
62 #include "DNA_node_types.h"
63 #include "DNA_object_force_types.h"
64 #include "DNA_object_types.h"
65 #include "DNA_particle_types.h"
66 #include "DNA_pointcloud_types.h"
67 #include "DNA_scene_types.h"
68 #include "DNA_screen_types.h"
69 #include "DNA_sequence_types.h"
70 #include "DNA_simulation_types.h"
71 #include "DNA_space_types.h"
72 #include "DNA_speaker_types.h"
73 #include "DNA_userdef_types.h"
74 #include "DNA_volume_types.h"
75 #include "DNA_world_types.h"
76 
77 #include "MEM_guardedalloc.h"
78 
79 #include "BLI_alloca.h"
80 #include "BLI_blenlib.h"
81 #include "BLI_ghash.h"
82 #include "BLI_string.h"
83 #include "BLI_utildefines.h"
84 
85 #include "BKE_action.h"
86 #include "BKE_anim_data.h"
87 #include "BKE_collection.h"
88 #include "BKE_context.h"
89 #include "BKE_fcurve.h"
90 #include "BKE_fcurve_driver.h"
91 #include "BKE_global.h"
92 #include "BKE_key.h"
93 #include "BKE_layer.h"
94 #include "BKE_main.h"
95 #include "BKE_mask.h"
96 #include "BKE_material.h"
97 #include "BKE_modifier.h"
98 #include "BKE_node.h"
99 #include "BKE_sequencer.h"
100 
101 #include "ED_anim_api.h"
102 #include "ED_markers.h"
103 
104 #include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */
105 
106 /* ************************************************************ */
107 /* Blender Context <-> Animation Context mapping */
108 
109 /* ----------- Private Stuff - General -------------------- */
110 
111 /* Get vertical scaling factor (i.e. typically used for keyframe size) */
animedit_get_yscale_factor(bAnimContext * ac)112 static void animedit_get_yscale_factor(bAnimContext *ac)
113 {
114   bTheme *btheme = UI_GetTheme();
115 
116   /* grab scale factor directly from action editor setting
117    * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally
118    *       since it is a float, and the theme settings methods can only handle chars.
119    */
120   ac->yscale_fac = btheme->space_action.keyframe_scale_fac;
121 
122   /* clamp to avoid problems with uninitialized values... */
123   if (ac->yscale_fac < 0.1f) {
124     ac->yscale_fac = 1.0f;
125   }
126   // printf("yscale_fac = %f\n", ac->yscale_fac);
127 }
128 
129 /* ----------- Private Stuff - Action Editor ------------- */
130 
131 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
132 /* Note: there's a similar function in key.c (BKE_key_from_object) */
actedit_get_shapekeys(bAnimContext * ac)133 static Key *actedit_get_shapekeys(bAnimContext *ac)
134 {
135   ViewLayer *view_layer = ac->view_layer;
136   Object *ob;
137   Key *key;
138 
139   ob = OBACT(view_layer);
140   if (ob == NULL) {
141     return NULL;
142   }
143 
144   /* XXX pinning is not available in 'ShapeKey' mode... */
145   // if (saction->pin) { return NULL; }
146 
147   /* shapekey data is stored with geometry data */
148   key = BKE_key_from_object(ob);
149 
150   if (key) {
151     if (key->type == KEY_RELATIVE) {
152       return key;
153     }
154   }
155 
156   return NULL;
157 }
158 
159 /* Get data being edited in Action Editor (depending on current 'mode') */
actedit_get_context(bAnimContext * ac,SpaceAction * saction)160 static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
161 {
162   /* get dopesheet */
163   ac->ads = &saction->ads;
164 
165   /* sync settings with current view status, then return appropriate data */
166   switch (saction->mode) {
167     case SACTCONT_ACTION: /* 'Action Editor' */
168       /* if not pinned, sync with active object */
169       if (/*saction->pin == 0*/ true) {
170         if (ac->obact && ac->obact->adt) {
171           saction->action = ac->obact->adt->action;
172         }
173         else {
174           saction->action = NULL;
175         }
176       }
177 
178       ac->datatype = ANIMCONT_ACTION;
179       ac->data = saction->action;
180 
181       ac->mode = saction->mode;
182       return true;
183 
184     case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
185       ac->datatype = ANIMCONT_SHAPEKEY;
186       ac->data = actedit_get_shapekeys(ac);
187 
188       /* if not pinned, sync with active object */
189       if (/*saction->pin == 0*/ true) {
190         Key *key = (Key *)ac->data;
191 
192         if (key && key->adt) {
193           saction->action = key->adt->action;
194         }
195         else {
196           saction->action = NULL;
197         }
198       }
199 
200       ac->mode = saction->mode;
201       return true;
202 
203     case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */
204       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
205       saction->ads.source = (ID *)ac->scene;
206 
207       ac->datatype = ANIMCONT_GPENCIL;
208       ac->data = &saction->ads;
209 
210       ac->mode = saction->mode;
211       return true;
212 
213     case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
214       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
215       saction->ads.source = (ID *)ac->scene;
216 
217       ac->datatype = ANIMCONT_CHANNEL;
218       ac->data = &saction->ads;
219 
220       ac->mode = saction->mode;
221       return true;
222 
223     case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */
224     {
225       /* TODO, other methods to get the mask */
226 #if 0
227       Sequence *seq = BKE_sequencer_active_get(ac->scene);
228       MovieClip *clip = ac->scene->clip;
229       struct Mask *mask = seq ? seq->mask : NULL;
230 #endif
231 
232       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
233       saction->ads.source = (ID *)ac->scene;
234 
235       ac->datatype = ANIMCONT_MASK;
236       ac->data = &saction->ads;
237 
238       ac->mode = saction->mode;
239       return true;
240     }
241 
242     case SACTCONT_DOPESHEET: /* DopeSheet */
243       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
244       saction->ads.source = (ID *)ac->scene;
245 
246       ac->datatype = ANIMCONT_DOPESHEET;
247       ac->data = &saction->ads;
248 
249       ac->mode = saction->mode;
250       return true;
251 
252     case SACTCONT_TIMELINE: /* Timeline */
253       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
254       saction->ads.source = (ID *)ac->scene;
255 
256       /* sync scene's "selected keys only" flag with our "only selected" flag
257        *
258        * XXX: This is a workaround for T55525. We shouldn't really be syncing the flags like this,
259        * but it's a simpler fix for now than also figuring out how the next/prev keyframe
260        * tools should work in the 3D View if we allowed full access to the timeline's
261        * dopesheet filters (i.e. we'd have to figure out where to host those settings,
262        * to be on a scene level like this flag currently is, along with several other unknowns).
263        */
264       if (ac->scene->flag & SCE_KEYS_NO_SELONLY) {
265         saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL;
266       }
267       else {
268         saction->ads.filterflag |= ADS_FILTER_ONLYSEL;
269       }
270 
271       ac->datatype = ANIMCONT_TIMELINE;
272       ac->data = &saction->ads;
273 
274       ac->mode = saction->mode;
275       return true;
276 
277     default: /* unhandled yet */
278       ac->datatype = ANIMCONT_NONE;
279       ac->data = NULL;
280 
281       ac->mode = -1;
282       return false;
283   }
284 }
285 
286 /* ----------- Private Stuff - Graph Editor ------------- */
287 
288 /* Get data being edited in Graph Editor (depending on current 'mode') */
graphedit_get_context(bAnimContext * ac,SpaceGraph * sipo)289 static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo)
290 {
291   /* init dopesheet data if non-existent (i.e. for old files) */
292   if (sipo->ads == NULL) {
293     sipo->ads = MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
294     sipo->ads->source = (ID *)ac->scene;
295   }
296   ac->ads = sipo->ads;
297 
298   /* set settings for Graph Editor - "Selected = Editable" */
299   if (sipo->flag & SIPO_SELCUVERTSONLY) {
300     sipo->ads->filterflag |= ADS_FILTER_SELEDIT;
301   }
302   else {
303     sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT;
304   }
305 
306   /* sync settings with current view status, then return appropriate data */
307   switch (sipo->mode) {
308     case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */
309       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
310       sipo->ads->source = (ID *)ac->scene;
311       sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
312 
313       ac->datatype = ANIMCONT_FCURVES;
314       ac->data = sipo->ads;
315 
316       ac->mode = sipo->mode;
317       return true;
318 
319     case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */
320       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
321       sipo->ads->source = (ID *)ac->scene;
322       sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS;
323 
324       ac->datatype = ANIMCONT_DRIVERS;
325       ac->data = sipo->ads;
326 
327       ac->mode = sipo->mode;
328       return true;
329 
330     default: /* unhandled yet */
331       ac->datatype = ANIMCONT_NONE;
332       ac->data = NULL;
333 
334       ac->mode = -1;
335       return false;
336   }
337 }
338 
339 /* ----------- Private Stuff - NLA Editor ------------- */
340 
341 /* Get data being edited in Graph Editor (depending on current 'mode') */
nlaedit_get_context(bAnimContext * ac,SpaceNla * snla)342 static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
343 {
344   /* init dopesheet data if non-existent (i.e. for old files) */
345   if (snla->ads == NULL) {
346     snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
347   }
348   ac->ads = snla->ads;
349 
350   /* sync settings with current view status, then return appropriate data */
351   /* update scene-pointer (no need to check for pinning yet, as not implemented) */
352   snla->ads->source = (ID *)ac->scene;
353   snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
354 
355   ac->datatype = ANIMCONT_NLA;
356   ac->data = snla->ads;
357 
358   return true;
359 }
360 
361 /* ----------- Public API --------------- */
362 
363 /* Obtain current anim-data context,
364  * given that context info from Blender context has already been set:
365  * - AnimContext to write to is provided as pointer to var on stack so that we don't have
366  *   allocation/freeing costs (which are not that avoidable with channels).
367  */
ANIM_animdata_context_getdata(bAnimContext * ac)368 bool ANIM_animdata_context_getdata(bAnimContext *ac)
369 {
370   SpaceLink *sl = ac->sl;
371   bool ok = false;
372 
373   /* context depends on editor we are currently in */
374   if (sl) {
375     switch (ac->spacetype) {
376       case SPACE_ACTION: {
377         SpaceAction *saction = (SpaceAction *)sl;
378         ok = actedit_get_context(ac, saction);
379         break;
380       }
381       case SPACE_GRAPH: {
382         SpaceGraph *sipo = (SpaceGraph *)sl;
383         ok = graphedit_get_context(ac, sipo);
384         break;
385       }
386       case SPACE_NLA: {
387         SpaceNla *snla = (SpaceNla *)sl;
388         ok = nlaedit_get_context(ac, snla);
389         break;
390       }
391     }
392   }
393 
394   /* check if there's any valid data */
395   return (ok && ac->data);
396 }
397 
398 /* Obtain current anim-data context from Blender Context info
399  * - AnimContext to write to is provided as pointer to var on stack so that we don't have
400  *   allocation/freeing costs (which are not that avoidable with channels).
401  * - Clears data and sets the information from Blender Context which is useful
402  */
ANIM_animdata_get_context(const bContext * C,bAnimContext * ac)403 bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
404 {
405   Main *bmain = CTX_data_main(C);
406   ScrArea *area = CTX_wm_area(C);
407   ARegion *region = CTX_wm_region(C);
408   SpaceLink *sl = CTX_wm_space_data(C);
409   Scene *scene = CTX_data_scene(C);
410 
411   /* clear old context info */
412   if (ac == NULL) {
413     return false;
414   }
415   memset(ac, 0, sizeof(bAnimContext));
416 
417   /* get useful default context settings from context */
418   ac->bmain = bmain;
419   ac->scene = scene;
420   if (scene) {
421     ac->markers = ED_context_get_markers(C);
422   }
423   ac->view_layer = CTX_data_view_layer(C);
424   ac->depsgraph = CTX_data_depsgraph_pointer(C);
425   ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL;
426   ac->area = area;
427   ac->region = region;
428   ac->sl = sl;
429   ac->spacetype = (area) ? area->spacetype : 0;
430   ac->regiontype = (region) ? region->regiontype : 0;
431 
432   /* Initialize default y-scale factor. */
433   animedit_get_yscale_factor(ac);
434 
435   /* get data context info */
436   /* XXX: if the below fails, try to grab this info from context instead...
437    * (to allow for scripting). */
438   return ANIM_animdata_context_getdata(ac);
439 }
440 
441 /* ************************************************************ */
442 /* Blender Data <-- Filter --> Channels to be operated on */
443 
444 /* macros to use before/after getting the sub-channels of some channel,
445  * to abstract away some of the tricky logic involved
446  *
447  * cases:
448  * 1) Graph Edit main area (just data) OR channels visible in Channel List
449  * 2) If not showing channels, we're only interested in the data (Action Editor's editing)
450  * 3) We don't care what data, we just care there is some (so that a collapsed
451  *    channel can be kept around). No need to clear channels-flag in order to
452  *    keep expander channels with no sub-data out, as those cases should get
453  *    dealt with by the recursive detection idiom in place.
454  *
455  * Implementation Note:
456  *  YES the _doSubChannels variable is NOT read anywhere. BUT, this is NOT an excuse
457  *  to go steamrolling the logic into a single-line expression as from experience,
458  *  those are notoriously difficult to read + debug when extending later on. The code
459  *  below is purposefully laid out so that each case noted above corresponds clearly to
460  *  one case below.
461  */
462 #define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \
463   { \
464     int _filter = filter_mode; \
465     short _doSubChannels = 0; \
466     if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) { \
467       _doSubChannels = 1; \
468     } \
469     else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) { \
470       _doSubChannels = 2; \
471     } \
472     else { \
473       filter_mode |= ANIMFILTER_TMP_PEEK; \
474     } \
475 \
476     { \
477       (void)_doSubChannels; \
478     }
479 /* ... standard sub-channel filtering can go on here now ... */
480 #define END_ANIMFILTER_SUBCHANNELS \
481   filter_mode = _filter; \
482   } \
483   (void)0
484 
485 /* ............................... */
486 
487 /* quick macro to test if AnimData is usable */
488 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
489 
490 /* quick macro to test if AnimData is usable for drivers */
491 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
492 
493 /* quick macro to test if AnimData is usable for NLA */
494 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
495 
496 /**
497  * Quick macro to test for all three above usability tests, performing the appropriate provided
498  * action for each when the AnimData context is appropriate.
499  *
500  * Priority order for this goes (most important, to least):
501  * AnimData blocks, NLA, Drivers, Keyframes.
502  *
503  * For this to work correctly,
504  * a standard set of data needs to be available within the scope that this
505  *
506  * Gets called in:
507  * - ListBase anim_data;
508  * - bDopeSheet *ads;
509  * - bAnimListElem *ale;
510  * - size_t items;
511  *
512  * - id: ID block which should have an AnimData pointer following it immediately, to use
513  * - adtOk: line or block of code to execute for AnimData-blocks case
514  *   (usually #ANIMDATA_ADD_ANIMDATA).
515  * - nlaOk: line or block of code to execute for NLA tracks+strips case
516  * - driversOk: line or block of code to execute for Drivers case
517  * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
518  * - keysOk: line or block of code for Keyframes case
519  *
520  * The checks for the various cases are as follows:
521  * 0) top level: checks for animdata and also that all the F-Curves for the block will be visible
522  * 1) animdata check: for filtering animdata blocks only
523  * 2A) nla tracks: include animdata block's data as there are NLA tracks+strips there
524  * 2B) actions to convert to nla: include animdata block's data as there is an action that can be
525  *     converted to a new NLA strip, and the filtering options allow this
526  * 2C) allow non-animated data-blocks to be included so that data-blocks can be added
527  * 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
528  * 4A) nla strip keyframes: these are the per-strip controls for time and influence
529  * 4B) normal keyframes: only when there is an active action
530  */
531 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
532   { \
533     if ((id)->adt) { \
534       if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || \
535           !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
536         if (filter_mode & ANIMFILTER_ANIMDATA) { \
537           adtOk \
538         } \
539         else if (ads->filterflag & ADS_FILTER_ONLYNLA) { \
540           if (ANIMDATA_HAS_NLA(id)) { \
541             nlaOk \
542           } \
543           else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \
544             nlaOk \
545           } \
546         } \
547         else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { \
548           if (ANIMDATA_HAS_DRIVERS(id)) { \
549             driversOk \
550           } \
551         } \
552         else { \
553           if (ANIMDATA_HAS_NLA(id)) { \
554             nlaKeysOk \
555           } \
556           if (ANIMDATA_HAS_KEYS(id)) { \
557             keysOk \
558           } \
559         } \
560       } \
561     } \
562   } \
563   (void)0
564 
565 /* ............................... */
566 
567 /**
568  * Add a new animation channel, taking into account the "peek" flag, which is used to just check
569  * whether any channels will be added (but without needing them to actually get created).
570  *
571  * \warning This causes the calling function to return early if we're only "peeking" for channels.
572  *
573  * XXX: ale_statement stuff is really a hack for one special case. It shouldn't really be needed.
574  */
575 #define ANIMCHANNEL_NEW_CHANNEL_FULL( \
576     channel_data, channel_type, owner_id, fcurve_owner_id, ale_statement) \
577   if (filter_mode & ANIMFILTER_TMP_PEEK) { \
578     return 1; \
579   } \
580   { \
581     bAnimListElem *ale = make_new_animlistelem( \
582         channel_data, channel_type, (ID *)owner_id, fcurve_owner_id); \
583     if (ale) { \
584       BLI_addtail(anim_data, ale); \
585       items++; \
586       ale_statement \
587     } \
588   } \
589   (void)0
590 
591 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id, fcurve_owner_id) \
592   ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, fcurve_owner_id, {})
593 
594 /* ............................... */
595 
596 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */
597 #define ANIMCHANNEL_ACTIVEOK(ale) \
598   (!(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE))
599 
600 /* Quick macro to test if an anim-channel (F-Curve, Group, etc.)
601  * is selected in an acceptable way. */
602 #define ANIMCHANNEL_SELOK(test_func) \
603   (!(filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) || \
604    ((filter_mode & ANIMFILTER_SEL) && test_func) || \
605    ((filter_mode & ANIMFILTER_UNSEL) && test_func == 0))
606 
607 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes
608  * - _SELEDIT means that only selected curves will have visible+editable keyframes
609  *
610  * checks here work as follows:
611  * 1) seledit off - don't need to consider the implications of this option
612  * 2) foredit off - we're not considering editing, so channel is ok still
613  * 3) test_func (i.e. selection test) - only if selected, this test will pass
614  */
615 #define ANIMCHANNEL_SELEDITOK(test_func) \
616   (!(filter_mode & ANIMFILTER_SELEDIT) || !(filter_mode & ANIMFILTER_FOREDIT) || (test_func))
617 
618 /* ----------- 'Private' Stuff --------------- */
619 
620 /* this function allocates memory for a new bAnimListElem struct for the
621  * provided animation channel-data.
622  */
make_new_animlistelem(void * data,short datatype,ID * owner_id,ID * fcurve_owner_id)623 static bAnimListElem *make_new_animlistelem(void *data,
624                                             short datatype,
625                                             ID *owner_id,
626                                             ID *fcurve_owner_id)
627 {
628   bAnimListElem *ale = NULL;
629 
630   /* only allocate memory if there is data to convert */
631   if (data) {
632     /* allocate and set generic data */
633     ale = MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
634 
635     ale->data = data;
636     ale->type = datatype;
637 
638     ale->id = owner_id;
639     ale->adt = BKE_animdata_from_id(owner_id);
640     ale->fcurve_owner_id = fcurve_owner_id;
641 
642     /* do specifics */
643     switch (datatype) {
644       case ANIMTYPE_SUMMARY: {
645         /* Nothing to include for now... this is just a dummy wrapper around
646          * all the other channels in the DopeSheet, and gets included at the start of the list. */
647         ale->key_data = NULL;
648         ale->datatype = ALE_ALL;
649         break;
650       }
651       case ANIMTYPE_SCENE: {
652         Scene *sce = (Scene *)data;
653 
654         ale->flag = sce->flag;
655 
656         ale->key_data = sce;
657         ale->datatype = ALE_SCE;
658 
659         ale->adt = BKE_animdata_from_id(data);
660         break;
661       }
662       case ANIMTYPE_OBJECT: {
663         Base *base = (Base *)data;
664         Object *ob = base->object;
665 
666         ale->flag = ob->flag;
667 
668         ale->key_data = ob;
669         ale->datatype = ALE_OB;
670 
671         ale->adt = BKE_animdata_from_id(&ob->id);
672         break;
673       }
674       case ANIMTYPE_FILLACTD: {
675         bAction *act = (bAction *)data;
676 
677         ale->flag = act->flag;
678 
679         ale->key_data = act;
680         ale->datatype = ALE_ACT;
681         break;
682       }
683       case ANIMTYPE_FILLDRIVERS: {
684         AnimData *adt = (AnimData *)data;
685 
686         ale->flag = adt->flag;
687 
688         /* XXX drivers don't show summary for now. */
689         ale->key_data = NULL;
690         ale->datatype = ALE_NONE;
691         break;
692       }
693       case ANIMTYPE_DSMAT: {
694         Material *ma = (Material *)data;
695         AnimData *adt = ma->adt;
696 
697         ale->flag = FILTER_MAT_OBJD(ma);
698 
699         ale->key_data = (adt) ? adt->action : NULL;
700         ale->datatype = ALE_ACT;
701 
702         ale->adt = BKE_animdata_from_id(data);
703         break;
704       }
705       case ANIMTYPE_DSLAM: {
706         Light *la = (Light *)data;
707         AnimData *adt = la->adt;
708 
709         ale->flag = FILTER_LAM_OBJD(la);
710 
711         ale->key_data = (adt) ? adt->action : NULL;
712         ale->datatype = ALE_ACT;
713 
714         ale->adt = BKE_animdata_from_id(data);
715         break;
716       }
717       case ANIMTYPE_DSCAM: {
718         Camera *ca = (Camera *)data;
719         AnimData *adt = ca->adt;
720 
721         ale->flag = FILTER_CAM_OBJD(ca);
722 
723         ale->key_data = (adt) ? adt->action : NULL;
724         ale->datatype = ALE_ACT;
725 
726         ale->adt = BKE_animdata_from_id(data);
727         break;
728       }
729       case ANIMTYPE_DSCACHEFILE: {
730         CacheFile *cache_file = (CacheFile *)data;
731         AnimData *adt = cache_file->adt;
732 
733         ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
734 
735         ale->key_data = (adt) ? adt->action : NULL;
736         ale->datatype = ALE_ACT;
737 
738         ale->adt = BKE_animdata_from_id(data);
739         break;
740       }
741       case ANIMTYPE_DSCUR: {
742         Curve *cu = (Curve *)data;
743         AnimData *adt = cu->adt;
744 
745         ale->flag = FILTER_CUR_OBJD(cu);
746 
747         ale->key_data = (adt) ? adt->action : NULL;
748         ale->datatype = ALE_ACT;
749 
750         ale->adt = BKE_animdata_from_id(data);
751         break;
752       }
753       case ANIMTYPE_DSARM: {
754         bArmature *arm = (bArmature *)data;
755         AnimData *adt = arm->adt;
756 
757         ale->flag = FILTER_ARM_OBJD(arm);
758 
759         ale->key_data = (adt) ? adt->action : NULL;
760         ale->datatype = ALE_ACT;
761 
762         ale->adt = BKE_animdata_from_id(data);
763         break;
764       }
765       case ANIMTYPE_DSMESH: {
766         Mesh *me = (Mesh *)data;
767         AnimData *adt = me->adt;
768 
769         ale->flag = FILTER_MESH_OBJD(me);
770 
771         ale->key_data = (adt) ? adt->action : NULL;
772         ale->datatype = ALE_ACT;
773 
774         ale->adt = BKE_animdata_from_id(data);
775         break;
776       }
777       case ANIMTYPE_DSLAT: {
778         Lattice *lt = (Lattice *)data;
779         AnimData *adt = lt->adt;
780 
781         ale->flag = FILTER_LATTICE_OBJD(lt);
782 
783         ale->key_data = (adt) ? adt->action : NULL;
784         ale->datatype = ALE_ACT;
785 
786         ale->adt = BKE_animdata_from_id(data);
787         break;
788       }
789       case ANIMTYPE_DSSPK: {
790         Speaker *spk = (Speaker *)data;
791         AnimData *adt = spk->adt;
792 
793         ale->flag = FILTER_SPK_OBJD(spk);
794 
795         ale->key_data = (adt) ? adt->action : NULL;
796         ale->datatype = ALE_ACT;
797 
798         ale->adt = BKE_animdata_from_id(data);
799         break;
800       }
801       case ANIMTYPE_DSHAIR: {
802         Hair *hair = (Hair *)data;
803         AnimData *adt = hair->adt;
804 
805         ale->flag = FILTER_HAIR_OBJD(hair);
806 
807         ale->key_data = (adt) ? adt->action : NULL;
808         ale->datatype = ALE_ACT;
809 
810         ale->adt = BKE_animdata_from_id(data);
811         break;
812       }
813       case ANIMTYPE_DSPOINTCLOUD: {
814         PointCloud *pointcloud = (PointCloud *)data;
815         AnimData *adt = pointcloud->adt;
816 
817         ale->flag = FILTER_POINTS_OBJD(pointcloud);
818 
819         ale->key_data = (adt) ? adt->action : NULL;
820         ale->datatype = ALE_ACT;
821 
822         ale->adt = BKE_animdata_from_id(data);
823         break;
824       }
825       case ANIMTYPE_DSVOLUME: {
826         Volume *volume = (Volume *)data;
827         AnimData *adt = volume->adt;
828 
829         ale->flag = FILTER_VOLUME_OBJD(volume);
830 
831         ale->key_data = (adt) ? adt->action : NULL;
832         ale->datatype = ALE_ACT;
833 
834         ale->adt = BKE_animdata_from_id(data);
835         break;
836       }
837       case ANIMTYPE_DSSIMULATION: {
838         Simulation *simulation = (Simulation *)data;
839         AnimData *adt = simulation->adt;
840 
841         ale->flag = FILTER_SIMULATION_OBJD(simulation);
842 
843         ale->key_data = (adt) ? adt->action : NULL;
844         ale->datatype = ALE_ACT;
845 
846         ale->adt = BKE_animdata_from_id(data);
847         break;
848       }
849       case ANIMTYPE_DSSKEY: {
850         Key *key = (Key *)data;
851         AnimData *adt = key->adt;
852 
853         ale->flag = FILTER_SKE_OBJD(key);
854 
855         ale->key_data = (adt) ? adt->action : NULL;
856         ale->datatype = ALE_ACT;
857 
858         ale->adt = BKE_animdata_from_id(data);
859         break;
860       }
861       case ANIMTYPE_DSWOR: {
862         World *wo = (World *)data;
863         AnimData *adt = wo->adt;
864 
865         ale->flag = FILTER_WOR_SCED(wo);
866 
867         ale->key_data = (adt) ? adt->action : NULL;
868         ale->datatype = ALE_ACT;
869 
870         ale->adt = BKE_animdata_from_id(data);
871         break;
872       }
873       case ANIMTYPE_DSNTREE: {
874         bNodeTree *ntree = (bNodeTree *)data;
875         AnimData *adt = ntree->adt;
876 
877         ale->flag = FILTER_NTREE_DATA(ntree);
878 
879         ale->key_data = (adt) ? adt->action : NULL;
880         ale->datatype = ALE_ACT;
881 
882         ale->adt = BKE_animdata_from_id(data);
883         break;
884       }
885       case ANIMTYPE_DSLINESTYLE: {
886         FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data;
887         AnimData *adt = linestyle->adt;
888 
889         ale->flag = FILTER_LS_SCED(linestyle);
890 
891         ale->key_data = (adt) ? adt->action : NULL;
892         ale->datatype = ALE_ACT;
893 
894         ale->adt = BKE_animdata_from_id(data);
895         break;
896       }
897       case ANIMTYPE_DSPART: {
898         ParticleSettings *part = (ParticleSettings *)ale->data;
899         AnimData *adt = part->adt;
900 
901         ale->flag = FILTER_PART_OBJD(part);
902 
903         ale->key_data = (adt) ? adt->action : NULL;
904         ale->datatype = ALE_ACT;
905 
906         ale->adt = BKE_animdata_from_id(data);
907         break;
908       }
909       case ANIMTYPE_DSTEX: {
910         Tex *tex = (Tex *)data;
911         AnimData *adt = tex->adt;
912 
913         ale->flag = FILTER_TEX_DATA(tex);
914 
915         ale->key_data = (adt) ? adt->action : NULL;
916         ale->datatype = ALE_ACT;
917 
918         ale->adt = BKE_animdata_from_id(data);
919         break;
920       }
921       case ANIMTYPE_DSGPENCIL: {
922         bGPdata *gpd = (bGPdata *)data;
923         AnimData *adt = gpd->adt;
924 
925         /* NOTE: we just reuse the same expand filter for this case */
926         ale->flag = EXPANDED_GPD(gpd);
927 
928         /* XXX: currently, this is only used for access to its animation data */
929         ale->key_data = (adt) ? adt->action : NULL;
930         ale->datatype = ALE_ACT;
931 
932         ale->adt = BKE_animdata_from_id(data);
933         break;
934       }
935       case ANIMTYPE_DSMCLIP: {
936         MovieClip *clip = (MovieClip *)data;
937         AnimData *adt = clip->adt;
938 
939         ale->flag = EXPANDED_MCLIP(clip);
940 
941         ale->key_data = (adt) ? adt->action : NULL;
942         ale->datatype = ALE_ACT;
943 
944         ale->adt = BKE_animdata_from_id(data);
945         break;
946       }
947       case ANIMTYPE_NLACONTROLS: {
948         AnimData *adt = (AnimData *)data;
949 
950         ale->flag = adt->flag;
951 
952         ale->key_data = NULL;
953         ale->datatype = ALE_NONE;
954         break;
955       }
956       case ANIMTYPE_GROUP: {
957         bActionGroup *agrp = (bActionGroup *)data;
958 
959         ale->flag = agrp->flag;
960 
961         ale->key_data = NULL;
962         ale->datatype = ALE_GROUP;
963         break;
964       }
965       case ANIMTYPE_FCURVE:
966       case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE.
967                                * Differences are applied post-creation */
968       {
969         FCurve *fcu = (FCurve *)data;
970 
971         ale->flag = fcu->flag;
972 
973         ale->key_data = fcu;
974         ale->datatype = ALE_FCURVE;
975         break;
976       }
977       case ANIMTYPE_SHAPEKEY: {
978         KeyBlock *kb = (KeyBlock *)data;
979         Key *key = (Key *)ale->id;
980 
981         ale->flag = kb->flag;
982 
983         /* whether we have keyframes depends on whether there is a Key block to find it from */
984         if (key) {
985           /* index of shapekey is defined by place in key's list */
986           ale->index = BLI_findindex(&key->block, kb);
987 
988           /* the corresponding keyframes are from the animdata */
989           if (ale->adt && ale->adt->action) {
990             bAction *act = ale->adt->action;
991             char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
992 
993             /* try to find the F-Curve which corresponds to this exactly,
994              * then free the MEM_alloc'd string
995              */
996             if (rna_path) {
997               ale->key_data = (void *)BKE_fcurve_find(&act->curves, rna_path, 0);
998               MEM_freeN(rna_path);
999             }
1000           }
1001           ale->datatype = (ale->key_data) ? ALE_FCURVE : ALE_NONE;
1002         }
1003         break;
1004       }
1005       case ANIMTYPE_GPLAYER: {
1006         bGPDlayer *gpl = (bGPDlayer *)data;
1007 
1008         ale->flag = gpl->flag;
1009 
1010         ale->key_data = NULL;
1011         ale->datatype = ALE_GPFRAME;
1012         break;
1013       }
1014       case ANIMTYPE_MASKLAYER: {
1015         MaskLayer *masklay = (MaskLayer *)data;
1016 
1017         ale->flag = masklay->flag;
1018 
1019         ale->key_data = NULL;
1020         ale->datatype = ALE_MASKLAY;
1021         break;
1022       }
1023       case ANIMTYPE_NLATRACK: {
1024         NlaTrack *nlt = (NlaTrack *)data;
1025 
1026         ale->flag = nlt->flag;
1027 
1028         ale->key_data = &nlt->strips;
1029         ale->datatype = ALE_NLASTRIP;
1030         break;
1031       }
1032       case ANIMTYPE_NLAACTION: {
1033         /* nothing to include for now... nothing editable from NLA-perspective here */
1034         ale->key_data = NULL;
1035         ale->datatype = ALE_NONE;
1036         break;
1037       }
1038     }
1039   }
1040 
1041   /* return created datatype */
1042   return ale;
1043 }
1044 
1045 /* ----------------------------------------- */
1046 
1047 /* 'Only Selected' selected data and/or 'Include Hidden' filtering
1048  * NOTE: when this function returns true, the F-Curve is to be skipped
1049  */
skip_fcurve_selected_data(bDopeSheet * ads,FCurve * fcu,ID * owner_id,int filter_mode)1050 static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
1051 {
1052   if (fcu->grp != NULL && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) {
1053     return false;
1054   }
1055   /* hidden items should be skipped if we only care about visible data,
1056    * but we aren't interested in hidden stuff */
1057   const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) &&
1058                            !(ads->filterflag & ADS_FILTER_INCL_HIDDEN);
1059 
1060   if (GS(owner_id->name) == ID_OB) {
1061     Object *ob = (Object *)owner_id;
1062 
1063     /* only consider if F-Curve involves pose.bones */
1064     if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
1065       bPoseChannel *pchan;
1066       char *bone_name;
1067 
1068       /* get bone-name, and check if this bone is selected */
1069       bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
1070       pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
1071       if (bone_name) {
1072         MEM_freeN(bone_name);
1073       }
1074 
1075       /* check whether to continue or skip */
1076       if ((pchan) && (pchan->bone)) {
1077         /* If only visible channels,
1078          * skip if bone not visible unless user wants channels from hidden data too. */
1079         if (skip_hidden) {
1080           bArmature *arm = (bArmature *)ob->data;
1081 
1082           /* skipping - not visible on currently visible layers */
1083           if ((arm->layer & pchan->bone->layer) == 0) {
1084             return true;
1085           }
1086           /* skipping - is currently hidden */
1087           if (pchan->bone->flag & BONE_HIDDEN_P) {
1088             return true;
1089           }
1090         }
1091 
1092         /* can only add this F-Curve if it is selected */
1093         if (ads->filterflag & ADS_FILTER_ONLYSEL) {
1094           if ((pchan->bone->flag & BONE_SELECTED) == 0) {
1095             return true;
1096           }
1097         }
1098       }
1099     }
1100   }
1101   else if (GS(owner_id->name) == ID_SCE) {
1102     Scene *scene = (Scene *)owner_id;
1103 
1104     /* only consider if F-Curve involves sequence_editor.sequences */
1105     if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
1106       Editing *ed = BKE_sequencer_editing_get(scene, false);
1107       Sequence *seq = NULL;
1108       char *seq_name;
1109 
1110       if (ed) {
1111         /* get strip name, and check if this strip is selected */
1112         seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
1113         seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false);
1114         if (seq_name) {
1115           MEM_freeN(seq_name);
1116         }
1117       }
1118 
1119       /* can only add this F-Curve if it is selected */
1120       if (ads->filterflag & ADS_FILTER_ONLYSEL) {
1121         if ((seq == NULL) || (seq->flag & SELECT) == 0) {
1122           return true;
1123         }
1124       }
1125     }
1126   }
1127   else if (GS(owner_id->name) == ID_NT) {
1128     bNodeTree *ntree = (bNodeTree *)owner_id;
1129 
1130     /* check for selected nodes */
1131     if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
1132       bNode *node;
1133       char *node_name;
1134 
1135       /* get strip name, and check if this strip is selected */
1136       node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
1137       node = nodeFindNodebyName(ntree, node_name);
1138       if (node_name) {
1139         MEM_freeN(node_name);
1140       }
1141 
1142       /* can only add this F-Curve if it is selected */
1143       if (ads->filterflag & ADS_FILTER_ONLYSEL) {
1144         if ((node) && (node->flag & NODE_SELECT) == 0) {
1145           return true;
1146         }
1147       }
1148     }
1149   }
1150 
1151   return false;
1152 }
1153 
1154 /* Helper for name-based filtering - Perform "partial/fuzzy matches" (as in 80a7efd) */
name_matches_dopesheet_filter(bDopeSheet * ads,char * name)1155 static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name)
1156 {
1157   if (ads->flag & ADS_FLAG_FUZZY_NAMES) {
1158     /* full fuzzy, multi-word, case insensitive matches */
1159     const size_t str_len = strlen(ads->searchstr);
1160     const int words_max = BLI_string_max_possible_word_count(str_len);
1161 
1162     int(*words)[2] = BLI_array_alloca(words, words_max);
1163     const int words_len = BLI_string_find_split_words(
1164         ads->searchstr, str_len, ' ', words, words_max);
1165     bool found = false;
1166 
1167     /* match name against all search words */
1168     for (int index = 0; index < words_len; index++) {
1169       if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) {
1170         found = true;
1171         break;
1172       }
1173     }
1174 
1175     /* if we have a match somewhere, this returns true */
1176     return ((ads->flag & ADS_FLAG_INVERT_FILTER) == 0) ? found : !found;
1177   }
1178   /* fallback/default - just case insensitive, but starts from start of word */
1179   bool found = BLI_strcasestr(name, ads->searchstr) != NULL;
1180   return ((ads->flag & ADS_FLAG_INVERT_FILTER) == 0) ? found : !found;
1181 }
1182 
1183 /* (Display-)Name-based F-Curve filtering
1184  * NOTE: when this function returns true, the F-Curve is to be skipped
1185  */
skip_fcurve_with_name(bDopeSheet * ads,FCurve * fcu,eAnim_ChannelType channel_type,void * owner,ID * owner_id)1186 static bool skip_fcurve_with_name(
1187     bDopeSheet *ads, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id)
1188 {
1189   bAnimListElem ale_dummy = {NULL};
1190   const bAnimChannelType *acf;
1191 
1192   /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */
1193   ale_dummy.type = channel_type;
1194   ale_dummy.owner = owner;
1195   ale_dummy.id = owner_id;
1196   ale_dummy.data = fcu;
1197 
1198   /* get type info for channel */
1199   acf = ANIM_channel_get_typeinfo(&ale_dummy);
1200   if (acf && acf->name) {
1201     char name[256]; /* hopefully this will be enough! */
1202 
1203     /* get name */
1204     acf->name(&ale_dummy, name);
1205 
1206     /* check for partial match with the match string, assuming case insensitive filtering
1207      * if match, this channel shouldn't be ignored!
1208      */
1209     return !name_matches_dopesheet_filter(ads, name);
1210   }
1211 
1212   /* just let this go... */
1213   return true;
1214 }
1215 
1216 /**
1217  * Check if F-Curve has errors and/or is disabled
1218  *
1219  * \return true if F-Curve has errors/is disabled
1220  */
fcurve_has_errors(FCurve * fcu)1221 static bool fcurve_has_errors(FCurve *fcu)
1222 {
1223   /* F-Curve disabled - path eval error */
1224   if (fcu->flag & FCURVE_DISABLED) {
1225     return true;
1226   }
1227 
1228   /* driver? */
1229   if (fcu->driver) {
1230     ChannelDriver *driver = fcu->driver;
1231     DriverVar *dvar;
1232 
1233     /* error flag on driver usually means that there is an error
1234      * BUT this may not hold with PyDrivers as this flag gets cleared
1235      *     if no critical errors prevent the driver from working...
1236      */
1237     if (driver->flag & DRIVER_FLAG_INVALID) {
1238       return true;
1239     }
1240 
1241     /* check variables for other things that need linting... */
1242     /* TODO: maybe it would be more efficient just to have a quick flag for this? */
1243     for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
1244       DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
1245         if (dtar->flag & DTAR_FLAG_INVALID) {
1246           return true;
1247         }
1248       }
1249       DRIVER_TARGETS_LOOPER_END;
1250     }
1251   }
1252 
1253   /* no errors found */
1254   return false;
1255 }
1256 
1257 /* find the next F-Curve that is usable for inclusion */
animfilter_fcurve_next(bDopeSheet * ads,FCurve * first,eAnim_ChannelType channel_type,int filter_mode,void * owner,ID * owner_id)1258 static FCurve *animfilter_fcurve_next(bDopeSheet *ads,
1259                                       FCurve *first,
1260                                       eAnim_ChannelType channel_type,
1261                                       int filter_mode,
1262                                       void *owner,
1263                                       ID *owner_id)
1264 {
1265   bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? owner : NULL;
1266   FCurve *fcu = NULL;
1267 
1268   /* Loop over F-Curves - assume that the caller of this has already checked
1269    * that these should be included.
1270    * NOTE: we need to check if the F-Curves belong to the same group,
1271    * as this gets called for groups too...
1272    */
1273   for (fcu = first; ((fcu) && (fcu->grp == grp)); fcu = fcu->next) {
1274     /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves:
1275      * - The 'Only Selected' and 'Include Hidden' data filters should be applied to sub-ID data
1276      *   which can be independently selected/hidden, such as Pose-Channels, Sequence Strips,
1277      *   and Nodes. Since these checks were traditionally done as first check for objects,
1278      *   we do the same here.
1279      * - We currently use an 'approximate' method for getting these F-Curves that doesn't require
1280      *   carefully checking the entire path.
1281      * - This will also affect things like Drivers, and also works for Bone Constraints.
1282      */
1283     if (ads && owner_id) {
1284       if ((filter_mode & ANIMFILTER_TMP_IGNORE_ONLYSEL) == 0) {
1285         if ((ads->filterflag & ADS_FILTER_ONLYSEL) ||
1286             (ads->filterflag & ADS_FILTER_INCL_HIDDEN) == 0) {
1287           if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode)) {
1288             continue;
1289           }
1290         }
1291       }
1292     }
1293 
1294     /* only include if visible (Graph Editor check, not channels check) */
1295     if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
1296       /* only work with this channel and its subchannels if it is editable */
1297       if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
1298         /* Only include this curve if selected in a way consistent
1299          * with the filtering requirements. */
1300         if (ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu))) {
1301           /* only include if this curve is active */
1302           if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
1303             /* name based filtering... */
1304             if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) {
1305               if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id)) {
1306                 continue;
1307               }
1308             }
1309 
1310             /* error-based filtering... */
1311             if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) {
1312               /* skip if no errors... */
1313               if (fcurve_has_errors(fcu) == false) {
1314                 continue;
1315               }
1316             }
1317 
1318             /* this F-Curve can be used, so return it */
1319             return fcu;
1320           }
1321         }
1322       }
1323     }
1324   }
1325 
1326   /* no (more) F-Curves from the list are suitable... */
1327   return NULL;
1328 }
1329 
animfilter_fcurves(ListBase * anim_data,bDopeSheet * ads,FCurve * first,eAnim_ChannelType fcurve_type,int filter_mode,void * owner,ID * owner_id,ID * fcurve_owner_id)1330 static size_t animfilter_fcurves(ListBase *anim_data,
1331                                  bDopeSheet *ads,
1332                                  FCurve *first,
1333                                  eAnim_ChannelType fcurve_type,
1334                                  int filter_mode,
1335                                  void *owner,
1336                                  ID *owner_id,
1337                                  ID *fcurve_owner_id)
1338 {
1339   FCurve *fcu;
1340   size_t items = 0;
1341 
1342   /* Loop over every F-Curve able to be included.
1343    *
1344    * This for-loop works like this:
1345    * 1) The starting F-Curve is assigned to the fcu pointer
1346    *    so that we have a starting point to search from.
1347    * 2) The first valid F-Curve to start from (which may include the one given as 'first')
1348    *    in the remaining list of F-Curves is found, and verified to be non-null.
1349    * 3) The F-Curve referenced by fcu pointer is added to the list
1350    * 4) The fcu pointer is set to the F-Curve after the one we just added,
1351    *    so that we can keep going through the rest of the F-Curve list without an eternal loop.
1352    *    Back to step 2 :)
1353    */
1354   for (fcu = first;
1355        ((fcu = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id)));
1356        fcu = fcu->next) {
1357     if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) {
1358       /* NLA Control Curve - Basically the same as normal F-Curves,
1359        * except we need to set some stuff differently */
1360       ANIMCHANNEL_NEW_CHANNEL_FULL(fcu, ANIMTYPE_NLACURVE, owner_id, fcurve_owner_id, {
1361         ale->owner = owner; /* strip */
1362         ale->adt = NULL;    /* to prevent time mapping from causing problems */
1363       });
1364     }
1365     else {
1366       /* Normal FCurve */
1367       ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id, fcurve_owner_id);
1368     }
1369   }
1370 
1371   /* return the number of items added to the list */
1372   return items;
1373 }
1374 
animfilter_act_group(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bAction * act,bActionGroup * agrp,int filter_mode,ID * owner_id)1375 static size_t animfilter_act_group(bAnimContext *ac,
1376                                    ListBase *anim_data,
1377                                    bDopeSheet *ads,
1378                                    bAction *act,
1379                                    bActionGroup *agrp,
1380                                    int filter_mode,
1381                                    ID *owner_id)
1382 {
1383   ListBase tmp_data = {NULL, NULL};
1384   size_t tmp_items = 0;
1385   size_t items = 0;
1386   // int ofilter = filter_mode;
1387 
1388   /* if we care about the selection status of the channels,
1389    * but the group isn't expanded (1)...
1390    * (1) this only matters if we actually care about the hierarchy though.
1391    *     - Hierarchy matters: this hack should be applied
1392    *     - Hierarchy ignored: cases like T21276 won't work properly, unless we skip this hack
1393    */
1394   if (
1395       /* Care about hierarchy but group isn't expanded. */
1396       ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp) == 0) &&
1397       /* Care about selection status. */
1398       (filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL))) {
1399     /* If the group itself isn't selected appropriately,
1400      * we shouldn't consider its children either. */
1401     if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0) {
1402       return 0;
1403     }
1404 
1405     /* if we're still here,
1406      * then the selection status of the curves within this group should not matter,
1407      * since this creates too much overhead for animators (i.e. making a slow workflow).
1408      *
1409      * Tools affected by this at time of coding (2010 Feb 09):
1410      * - Inserting keyframes on selected channels only.
1411      * - Pasting keyframes.
1412      * - Creating ghost curves in Graph Editor.
1413      */
1414     filter_mode &= ~(ANIMFILTER_SEL | ANIMFILTER_UNSEL | ANIMFILTER_LIST_VISIBLE);
1415   }
1416 
1417   /* add grouped F-Curves */
1418   BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_AGRP(ac, agrp)) {
1419     /* special filter so that we can get just the F-Curves within the active group */
1420     if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
1421       /* for the Graph Editor, curves may be set to not be visible in the view to lessen
1422        * clutter, but to do this, we need to check that the group doesn't have its
1423        * not-visible flag set preventing all its sub-curves to be shown
1424        */
1425       if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE)) {
1426         /* group must be editable for its children to be editable (if we care about this) */
1427         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
1428           /* get first F-Curve which can be used here */
1429           FCurve *first_fcu = animfilter_fcurve_next(
1430               ads, agrp->channels.first, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id);
1431 
1432           /* filter list, starting from this F-Curve */
1433           tmp_items += animfilter_fcurves(
1434               &tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id, &act->id);
1435         }
1436       }
1437     }
1438   }
1439   END_ANIMFILTER_SUBCHANNELS;
1440 
1441   /* did we find anything? */
1442   if (tmp_items) {
1443     /* add this group as a channel first */
1444     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1445       /* restore original filter mode so that this next step works ok... */
1446       // filter_mode = ofilter;
1447 
1448       /* filter selection of channel specially here again,
1449        * since may be open and not subject to previous test */
1450       if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp))) {
1451         ANIMCHANNEL_NEW_CHANNEL(agrp, ANIMTYPE_GROUP, owner_id, &act->id);
1452       }
1453     }
1454 
1455     /* now add the list of collected channels */
1456     BLI_movelisttolist(anim_data, &tmp_data);
1457     BLI_assert(BLI_listbase_is_empty(&tmp_data));
1458     items += tmp_items;
1459   }
1460 
1461   /* return the number of items added to the list */
1462   return items;
1463 }
1464 
animfilter_action(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bAction * act,int filter_mode,ID * owner_id)1465 static size_t animfilter_action(bAnimContext *ac,
1466                                 ListBase *anim_data,
1467                                 bDopeSheet *ads,
1468                                 bAction *act,
1469                                 int filter_mode,
1470                                 ID *owner_id)
1471 {
1472   bActionGroup *agrp;
1473   FCurve *lastchan = NULL;
1474   size_t items = 0;
1475 
1476   /* don't include anything from this action if it is linked in from another file,
1477    * and we're getting stuff for editing...
1478    */
1479   if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED(act)) {
1480     return 0;
1481   }
1482 
1483   /* do groups */
1484   /* TODO: do nested groups? */
1485   for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1486     /* store reference to last channel of group */
1487     if (agrp->channels.last) {
1488       lastchan = agrp->channels.last;
1489     }
1490 
1491     /* action group's channels */
1492     items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id);
1493   }
1494 
1495   /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */
1496   if (!(filter_mode & ANIMFILTER_ACTGROUPED)) {
1497     FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first);
1498     items += animfilter_fcurves(
1499         anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id, &act->id);
1500   }
1501 
1502   /* return the number of items added to the list */
1503   return items;
1504 }
1505 
1506 /* Include NLA-Data for NLA-Editor:
1507  * - When ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display
1508  *   Although the evaluation order is from the first track to the last and then apply the
1509  *   Action on top, we present this in the UI as the Active Action followed by the last track
1510  *   to the first so that we get the evaluation order presented as per a stack.
1511  * - For normal filtering (i.e. for editing),
1512  *   we only need the NLA-tracks but they can be in 'normal' evaluation order, i.e. first to last.
1513  *   Otherwise, some tools may get screwed up.
1514  */
animfilter_nla(bAnimContext * UNUSED (ac),ListBase * anim_data,bDopeSheet * ads,AnimData * adt,int filter_mode,ID * owner_id)1515 static size_t animfilter_nla(bAnimContext *UNUSED(ac),
1516                              ListBase *anim_data,
1517                              bDopeSheet *ads,
1518                              AnimData *adt,
1519                              int filter_mode,
1520                              ID *owner_id)
1521 {
1522   NlaTrack *nlt;
1523   NlaTrack *first = NULL, *next = NULL;
1524   size_t items = 0;
1525 
1526   /* if showing channels, include active action */
1527   if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1528     /* if NLA action-line filtering is off, don't show unless there are keyframes,
1529      * in order to keep things more compact for doing transforms
1530      */
1531     if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) {
1532       /* there isn't really anything editable here, so skip if need editable */
1533       if ((filter_mode & ANIMFILTER_FOREDIT) == 0) {
1534         /* Just add the action track now (this MUST appear for drawing):
1535          * - As AnimData may not have an action,
1536          *   we pass a dummy pointer just to get the list elem created,
1537          *   then overwrite this with the real value - REVIEW THIS.
1538          */
1539         ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, NULL, {
1540           ale->data = adt->action ? adt->action : NULL;
1541         });
1542       }
1543     }
1544 
1545     /* first track to include will be the last one if we're filtering by channels */
1546     first = adt->nla_tracks.last;
1547   }
1548   else {
1549     /* first track to include will the first one (as per normal) */
1550     first = adt->nla_tracks.first;
1551   }
1552 
1553   /* loop over NLA Tracks -
1554    * assume that the caller of this has already checked that these should be included */
1555   for (nlt = first; nlt; nlt = next) {
1556     /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
1557     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1558       next = nlt->prev;
1559     }
1560     else {
1561       next = nlt->next;
1562     }
1563 
1564     /* only work with this channel and its subchannels if it is editable */
1565     if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
1566       /* only include this track if selected in a way consistent with the filtering requirements */
1567       if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
1568         /* only include if this track is active */
1569         if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
1570           /* name based filtering... */
1571           if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) {
1572             bool track_ok = false, strip_ok = false;
1573 
1574             /* check if the name of the track, or the strips it has are ok... */
1575             track_ok = name_matches_dopesheet_filter(ads, nlt->name);
1576 
1577             if (track_ok == false) {
1578               NlaStrip *strip;
1579               for (strip = nlt->strips.first; strip; strip = strip->next) {
1580                 if (name_matches_dopesheet_filter(ads, strip->name)) {
1581                   strip_ok = true;
1582                   break;
1583                 }
1584               }
1585             }
1586 
1587             /* skip if both fail this test... */
1588             if (!track_ok && !strip_ok) {
1589               continue;
1590             }
1591           }
1592 
1593           /* add the track now that it has passed all our tests */
1594           ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id, NULL);
1595         }
1596       }
1597     }
1598   }
1599 
1600   /* return the number of items added to the list */
1601   return items;
1602 }
1603 
1604 /* Include the control FCurves per NLA Strip in the channel list
1605  * NOTE: This is includes the expander too...
1606  */
animfilter_nla_controls(ListBase * anim_data,bDopeSheet * ads,AnimData * adt,int filter_mode,ID * owner_id)1607 static size_t animfilter_nla_controls(
1608     ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
1609 {
1610   ListBase tmp_data = {NULL, NULL};
1611   size_t tmp_items = 0;
1612   size_t items = 0;
1613 
1614   /* add control curves from each NLA strip... */
1615   /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
1616   BEGIN_ANIMFILTER_SUBCHANNELS (((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0)) {
1617     NlaTrack *nlt;
1618     NlaStrip *strip;
1619 
1620     /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
1621     for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1622       for (strip = nlt->strips.first; strip; strip = strip->next) {
1623         /* pass strip as the "owner",
1624          * so that the name lookups (used while filtering) will resolve */
1625         /* NLA tracks are coming from AnimData, so owner of f-curves
1626          * is the same as owner of animation data. */
1627         tmp_items += animfilter_fcurves(&tmp_data,
1628                                         ads,
1629                                         strip->fcurves.first,
1630                                         ANIMTYPE_NLACURVE,
1631                                         filter_mode,
1632                                         strip,
1633                                         owner_id,
1634                                         owner_id);
1635       }
1636     }
1637   }
1638   END_ANIMFILTER_SUBCHANNELS;
1639 
1640   /* did we find anything? */
1641   if (tmp_items) {
1642     /* add the expander as a channel first */
1643     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1644       /* currently these channels cannot be selected, so they should be skipped */
1645       if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
1646         ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id, NULL);
1647       }
1648     }
1649 
1650     /* now add the list of collected channels */
1651     BLI_movelisttolist(anim_data, &tmp_data);
1652     BLI_assert(BLI_listbase_is_empty(&tmp_data));
1653     items += tmp_items;
1654   }
1655 
1656   /* return the number of items added to the list */
1657   return items;
1658 }
1659 
1660 /* determine what animation data from AnimData block should get displayed */
animfilter_block_data(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * id,int filter_mode)1661 static size_t animfilter_block_data(
1662     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
1663 {
1664   AnimData *adt = BKE_animdata_from_id(id);
1665   size_t items = 0;
1666 
1667   /* image object data-blocks have no anim-data so check for NULL */
1668   if (adt) {
1669     IdAdtTemplate *iat = (IdAdtTemplate *)id;
1670 
1671     /* NOTE: this macro is used instead of inlining the logic here,
1672      * since this sort of filtering is still needed in a few places in the rest of the code still -
1673      * notably for the few cases where special mode-based
1674      * different types of data expanders are required.
1675      */
1676     ANIMDATA_FILTER_CASES(
1677         iat,
1678         { /* AnimData */
1679           /* specifically filter animdata block */
1680           if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt))) {
1681             ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id, NULL);
1682           }
1683         },
1684         { /* NLA */
1685           items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
1686         },
1687         { /* Drivers */
1688           items += animfilter_fcurves(
1689               anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, filter_mode, NULL, id, id);
1690         },
1691         { /* NLA Control Keyframes */
1692           items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
1693         },
1694         { /* Keyframes */
1695           items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
1696         });
1697   }
1698 
1699   return items;
1700 }
1701 
1702 /* Include ShapeKey Data for ShapeKey Editor */
animdata_filter_shapekey(bAnimContext * ac,ListBase * anim_data,Key * key,int filter_mode)1703 static size_t animdata_filter_shapekey(bAnimContext *ac,
1704                                        ListBase *anim_data,
1705                                        Key *key,
1706                                        int filter_mode)
1707 {
1708   size_t items = 0;
1709 
1710   /* check if channels or only F-Curves */
1711   if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1712     KeyBlock *kb;
1713     bDopeSheet *ads = ac->ads;
1714 
1715     /* loop through the channels adding ShapeKeys as appropriate */
1716     for (kb = key->block.first; kb; kb = kb->next) {
1717       /* skip the first one, since that's the non-animatable basis */
1718       if (kb == key->block.first) {
1719         continue;
1720       }
1721 
1722       /* Skip shapekey if the name doesn't match the filter string. */
1723       if (ads != NULL && ads->searchstr[0] != '\0' &&
1724           name_matches_dopesheet_filter(ads, kb->name) == false) {
1725         continue;
1726       }
1727 
1728       /* only work with this channel and its subchannels if it is editable */
1729       if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
1730         /* Only include this track if selected in a way consistent
1731          * with the filtering requirements. */
1732         if (ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb))) {
1733           /* TODO: consider 'active' too? */
1734 
1735           /* owner-id here must be key so that the F-Curve can be resolved... */
1736           ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key, NULL);
1737         }
1738       }
1739     }
1740   }
1741   else {
1742     /* just use the action associated with the shapekey */
1743     /* TODO: somehow manage to pass dopesheet info down here too? */
1744     if (key->adt) {
1745       if (filter_mode & ANIMFILTER_ANIMDATA) {
1746         if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt))) {
1747           ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key, NULL);
1748         }
1749       }
1750       else if (key->adt->action) {
1751         items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key);
1752       }
1753     }
1754   }
1755 
1756   /* return the number of items added to the list */
1757   return items;
1758 }
1759 
1760 /* Helper for Grease Pencil - layers within a data-block. */
animdata_filter_gpencil_layers_data(ListBase * anim_data,bDopeSheet * ads,bGPdata * gpd,int filter_mode)1761 static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data,
1762                                                   bDopeSheet *ads,
1763                                                   bGPdata *gpd,
1764                                                   int filter_mode)
1765 {
1766   bGPDlayer *gpl;
1767   size_t items = 0;
1768 
1769   /* loop over layers as the conditions are acceptable (top-Down order) */
1770   for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
1771     /* only if selected */
1772     if (!ANIMCHANNEL_SELOK(SEL_GPL(gpl))) {
1773       continue;
1774     }
1775 
1776     /* only if editable */
1777     if ((filter_mode & ANIMFILTER_FOREDIT) && !EDITABLE_GPL(gpl)) {
1778       continue;
1779     }
1780 
1781     /* active... */
1782     if ((filter_mode & ANIMFILTER_ACTIVE) && (gpl->flag & GP_LAYER_ACTIVE) == 0) {
1783       continue;
1784     }
1785 
1786     /* skip layer if the name doesn't match the filter string */
1787     if (ads != NULL && ads->searchstr[0] != '\0' &&
1788         name_matches_dopesheet_filter(ads, gpl->info) == false) {
1789       continue;
1790     }
1791 
1792     /* Skip empty layers. */
1793     if (BLI_listbase_is_empty(&gpl->frames)) {
1794       continue;
1795     }
1796 
1797     /* add to list */
1798     ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd, NULL);
1799   }
1800 
1801   return items;
1802 }
1803 
1804 /* Helper for Grease Pencil - Grease Pencil data-block - GP Frames. */
animdata_filter_gpencil_data(ListBase * anim_data,bDopeSheet * ads,bGPdata * gpd,int filter_mode)1805 static size_t animdata_filter_gpencil_data(ListBase *anim_data,
1806                                            bDopeSheet *ads,
1807                                            bGPdata *gpd,
1808                                            int filter_mode)
1809 {
1810   size_t items = 0;
1811 
1812   /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
1813    * for convenience, this will return GP Data-blocks instead.
1814    * This may cause issues down the track, but for now, this will do.
1815    */
1816   if (filter_mode & ANIMFILTER_ANIMDATA) {
1817     /* just add GPD as a channel - this will add everything needed */
1818     ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd, NULL);
1819   }
1820   else {
1821     ListBase tmp_data = {NULL, NULL};
1822     size_t tmp_items = 0;
1823 
1824     /* add gpencil animation channels */
1825     BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
1826       tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
1827     }
1828     END_ANIMFILTER_SUBCHANNELS;
1829 
1830     /* did we find anything? */
1831     if (tmp_items) {
1832       /* include data-expand widget first */
1833       if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1834         /* add gpd as channel too (if for drawing, and it has layers) */
1835         ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL, NULL);
1836       }
1837 
1838       /* now add the list of collected channels */
1839       BLI_movelisttolist(anim_data, &tmp_data);
1840       BLI_assert(BLI_listbase_is_empty(&tmp_data));
1841       items += tmp_items;
1842     }
1843   }
1844 
1845   return items;
1846 }
1847 
1848 /**
1849  * Grab all Grease Pencil data-blocks in file.
1850  *
1851  * TODO: should this be amalgamated with the dope-sheet filtering code?
1852  */
animdata_filter_gpencil(bAnimContext * ac,ListBase * anim_data,void * UNUSED (data),int filter_mode)1853 static size_t animdata_filter_gpencil(bAnimContext *ac,
1854                                       ListBase *anim_data,
1855                                       void *UNUSED(data),
1856                                       int filter_mode)
1857 {
1858   bDopeSheet *ads = ac->ads;
1859   size_t items = 0;
1860 
1861   ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
1862   Base *base;
1863 
1864   /* Include all annotation datablocks. */
1865   if (((ads->filterflag & ADS_FILTER_ONLYSEL) == 0) ||
1866       (ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
1867     LISTBASE_FOREACH (bGPdata *, gpd, &ac->bmain->gpencils) {
1868       if (gpd->flag & GP_DATA_ANNOTATIONS) {
1869         items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
1870       }
1871     }
1872   }
1873   /* Objects in the scene */
1874   for (base = view_layer->object_bases.first; base; base = base->next) {
1875     /* Only consider this object if it has got some GP data (saving on all the other tests) */
1876     if (base->object && (base->object->type == OB_GPENCIL)) {
1877       Object *ob = base->object;
1878 
1879       /* firstly, check if object can be included, by the following factors:
1880        * - if only visible, must check for layer and also viewport visibility
1881        *   --> while tools may demand only visible, user setting takes priority
1882        *       as user option controls whether sets of channels get included while
1883        *       tool-flag takes into account collapsed/open channels too
1884        * - if only selected, must check if object is selected
1885        * - there must be animation data to edit (this is done recursively as we
1886        *   try to add the channels)
1887        */
1888       if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
1889         /* Layer visibility - we check both object and base,
1890          * since these may not be in sync yet. */
1891         if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
1892           continue;
1893         }
1894 
1895         /* outliner restrict-flag */
1896         if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
1897           continue;
1898         }
1899       }
1900 
1901       /* check selection and object type filters */
1902       if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
1903         /* only selected should be shown */
1904         continue;
1905       }
1906 
1907       /* check if object belongs to the filtering group if option to filter
1908        * objects by the grouped status is on
1909        * - used to ease the process of doing multiple-character choreographies
1910        */
1911       if (ads->filter_grp != NULL) {
1912         if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) {
1913           continue;
1914         }
1915       }
1916 
1917       /* finally, include this object's grease pencil data-block. */
1918       /* XXX: Should we store these under expanders per item? */
1919       items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
1920     }
1921   }
1922 
1923   /* return the number of items added to the list */
1924   return items;
1925 }
1926 
1927 /* Helper for Grease Pencil data integrated with main DopeSheet */
animdata_filter_ds_gpencil(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bGPdata * gpd,int filter_mode)1928 static size_t animdata_filter_ds_gpencil(
1929     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode)
1930 {
1931   ListBase tmp_data = {NULL, NULL};
1932   size_t tmp_items = 0;
1933   size_t items = 0;
1934 
1935   /* add relevant animation channels for Grease Pencil */
1936   BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
1937     /* add animation channels */
1938     tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode);
1939 
1940     /* add Grease Pencil layers */
1941 
1942     /* TODO: do these need a separate expander?
1943      * XXX:  what order should these go in? */
1944   }
1945   END_ANIMFILTER_SUBCHANNELS;
1946 
1947   /* did we find anything? */
1948   if (tmp_items) {
1949     /* include data-expand widget first */
1950     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1951       /* check if filtering by active status */
1952       /* XXX: active check here needs checking */
1953       if (ANIMCHANNEL_ACTIVEOK(gpd)) {
1954         ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_DSGPENCIL, gpd, NULL);
1955       }
1956     }
1957 
1958     /* now add the list of collected channels */
1959     BLI_movelisttolist(anim_data, &tmp_data);
1960     BLI_assert(BLI_listbase_is_empty(&tmp_data));
1961     items += tmp_items;
1962   }
1963 
1964   /* return the number of items added to the list */
1965   return items;
1966 }
1967 
1968 /* Helper for Cache File data integrated with main DopeSheet */
animdata_filter_ds_cachefile(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,CacheFile * cache_file,int filter_mode)1969 static size_t animdata_filter_ds_cachefile(
1970     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode)
1971 {
1972   ListBase tmp_data = {NULL, NULL};
1973   size_t tmp_items = 0;
1974   size_t items = 0;
1975 
1976   /* add relevant animation channels for Cache File */
1977   BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_CACHEFILE_OBJD(cache_file)) {
1978     /* add animation channels */
1979     tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, filter_mode);
1980   }
1981   END_ANIMFILTER_SUBCHANNELS;
1982 
1983   /* did we find anything? */
1984   if (tmp_items) {
1985     /* include data-expand widget first */
1986     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1987       /* check if filtering by active status */
1988       /* XXX: active check here needs checking */
1989       if (ANIMCHANNEL_ACTIVEOK(cache_file)) {
1990         ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file, NULL);
1991       }
1992     }
1993 
1994     /* now add the list of collected channels */
1995     BLI_movelisttolist(anim_data, &tmp_data);
1996     BLI_assert(BLI_listbase_is_empty(&tmp_data));
1997     items += tmp_items;
1998   }
1999 
2000   /* return the number of items added to the list */
2001   return items;
2002 }
2003 
2004 /* Helper for Mask Editing - mask layers */
animdata_filter_mask_data(ListBase * anim_data,Mask * mask,const int filter_mode)2005 static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode)
2006 {
2007   MaskLayer *masklay_act = BKE_mask_layer_active(mask);
2008   MaskLayer *masklay;
2009   size_t items = 0;
2010 
2011   /* loop over layers as the conditions are acceptable */
2012   for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
2013     /* only if selected */
2014     if (ANIMCHANNEL_SELOK(SEL_MASKLAY(masklay))) {
2015       /* only if editable */
2016       if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_MASK(masklay)) {
2017         /* active... */
2018         if (!(filter_mode & ANIMFILTER_ACTIVE) || (masklay_act == masklay)) {
2019           /* add to list */
2020           ANIMCHANNEL_NEW_CHANNEL(masklay, ANIMTYPE_MASKLAYER, mask, NULL);
2021         }
2022       }
2023     }
2024   }
2025 
2026   return items;
2027 }
2028 
2029 /* Grab all mask data */
animdata_filter_mask(Main * bmain,ListBase * anim_data,void * UNUSED (data),int filter_mode)2030 static size_t animdata_filter_mask(Main *bmain,
2031                                    ListBase *anim_data,
2032                                    void *UNUSED(data),
2033                                    int filter_mode)
2034 {
2035   Mask *mask;
2036   size_t items = 0;
2037 
2038   /* For now, grab mask data-blocks directly from main. */
2039   /* XXX: this is not good... */
2040   for (mask = bmain->masks.first; mask; mask = mask->id.next) {
2041     ListBase tmp_data = {NULL, NULL};
2042     size_t tmp_items = 0;
2043 
2044     /* only show if mask is used by something... */
2045     if (ID_REAL_USERS(mask) < 1) {
2046       continue;
2047     }
2048 
2049     /* add mask animation channels */
2050     BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_MASK(mask)) {
2051       tmp_items += animdata_filter_mask_data(&tmp_data, mask, filter_mode);
2052     }
2053     END_ANIMFILTER_SUBCHANNELS;
2054 
2055     /* did we find anything? */
2056     if (tmp_items) {
2057       /* include data-expand widget first */
2058       if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2059         /* add mask data-block as channel too (if for drawing, and it has layers) */
2060         ANIMCHANNEL_NEW_CHANNEL(mask, ANIMTYPE_MASKDATABLOCK, NULL, NULL);
2061       }
2062 
2063       /* now add the list of collected channels */
2064       BLI_movelisttolist(anim_data, &tmp_data);
2065       BLI_assert(BLI_listbase_is_empty(&tmp_data));
2066       items += tmp_items;
2067     }
2068   }
2069 
2070   /* return the number of items added to the list */
2071   return items;
2072 }
2073 
2074 /* NOTE: owner_id is scene, material, or texture block,
2075  * which is the direct owner of the node tree in question. */
animdata_filter_ds_nodetree_group(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * owner_id,bNodeTree * ntree,int filter_mode)2076 static size_t animdata_filter_ds_nodetree_group(bAnimContext *ac,
2077                                                 ListBase *anim_data,
2078                                                 bDopeSheet *ads,
2079                                                 ID *owner_id,
2080                                                 bNodeTree *ntree,
2081                                                 int filter_mode)
2082 {
2083   ListBase tmp_data = {NULL, NULL};
2084   size_t tmp_items = 0;
2085   size_t items = 0;
2086 
2087   /* add nodetree animation channels */
2088   BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_NTREE_DATA(ntree)) {
2089     /* animation data filtering */
2090     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ntree, filter_mode);
2091   }
2092   END_ANIMFILTER_SUBCHANNELS;
2093 
2094   /* did we find anything? */
2095   if (tmp_items) {
2096     /* include data-expand widget first */
2097     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2098       /* check if filtering by active status */
2099       if (ANIMCHANNEL_ACTIVEOK(ntree)) {
2100         ANIMCHANNEL_NEW_CHANNEL(ntree, ANIMTYPE_DSNTREE, owner_id, NULL);
2101       }
2102     }
2103 
2104     /* now add the list of collected channels */
2105     BLI_movelisttolist(anim_data, &tmp_data);
2106     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2107     items += tmp_items;
2108   }
2109 
2110   /* return the number of items added to the list */
2111   return items;
2112 }
2113 
animdata_filter_ds_nodetree(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * owner_id,bNodeTree * ntree,int filter_mode)2114 static size_t animdata_filter_ds_nodetree(bAnimContext *ac,
2115                                           ListBase *anim_data,
2116                                           bDopeSheet *ads,
2117                                           ID *owner_id,
2118                                           bNodeTree *ntree,
2119                                           int filter_mode)
2120 {
2121   bNode *node;
2122   size_t items = 0;
2123 
2124   items += animdata_filter_ds_nodetree_group(ac, anim_data, ads, owner_id, ntree, filter_mode);
2125 
2126   for (node = ntree->nodes.first; node; node = node->next) {
2127     if (node->type == NODE_GROUP) {
2128       if (node->id) {
2129         if ((ads->filterflag & ADS_FILTER_ONLYSEL) && (node->flag & NODE_SELECT) == 0) {
2130           continue;
2131         }
2132         /* Recurse into the node group */
2133         items += animdata_filter_ds_nodetree(ac,
2134                                              anim_data,
2135                                              ads,
2136                                              owner_id,
2137                                              (bNodeTree *)node->id,
2138                                              filter_mode | ANIMFILTER_TMP_IGNORE_ONLYSEL);
2139       }
2140     }
2141   }
2142 
2143   return items;
2144 }
2145 
animdata_filter_ds_linestyle(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,int filter_mode)2146 static size_t animdata_filter_ds_linestyle(
2147     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
2148 {
2149   ViewLayer *view_layer;
2150   FreestyleLineSet *lineset;
2151   size_t items = 0;
2152 
2153   for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
2154     for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
2155       if (lineset->linestyle) {
2156         lineset->linestyle->id.tag |= LIB_TAG_DOIT;
2157       }
2158     }
2159   }
2160 
2161   for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
2162     /* skip render layers without Freestyle enabled */
2163     if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) {
2164       continue;
2165     }
2166 
2167     /* loop over linesets defined in the render layer */
2168     for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
2169       FreestyleLineStyle *linestyle = lineset->linestyle;
2170       ListBase tmp_data = {NULL, NULL};
2171       size_t tmp_items = 0;
2172 
2173       if ((linestyle == NULL) || !(linestyle->id.tag & LIB_TAG_DOIT)) {
2174         continue;
2175       }
2176       linestyle->id.tag &= ~LIB_TAG_DOIT;
2177 
2178       /* add scene-level animation channels */
2179       BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_LS_SCED(linestyle)) {
2180         /* animation data filtering */
2181         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)linestyle, filter_mode);
2182       }
2183       END_ANIMFILTER_SUBCHANNELS;
2184 
2185       /* did we find anything? */
2186       if (tmp_items) {
2187         /* include anim-expand widget first */
2188         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2189           /* check if filtering by active status */
2190           if (ANIMCHANNEL_ACTIVEOK(linestyle)) {
2191             ANIMCHANNEL_NEW_CHANNEL(linestyle, ANIMTYPE_DSLINESTYLE, sce, NULL);
2192           }
2193         }
2194 
2195         /* now add the list of collected channels */
2196         BLI_movelisttolist(anim_data, &tmp_data);
2197         BLI_assert(BLI_listbase_is_empty(&tmp_data));
2198         items += tmp_items;
2199       }
2200     }
2201   }
2202 
2203   /* return the number of items added to the list */
2204   return items;
2205 }
2206 
animdata_filter_ds_texture(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Tex * tex,ID * owner_id,int filter_mode)2207 static size_t animdata_filter_ds_texture(bAnimContext *ac,
2208                                          ListBase *anim_data,
2209                                          bDopeSheet *ads,
2210                                          Tex *tex,
2211                                          ID *owner_id,
2212                                          int filter_mode)
2213 {
2214   ListBase tmp_data = {NULL, NULL};
2215   size_t tmp_items = 0;
2216   size_t items = 0;
2217 
2218   /* add texture's animation data to temp collection */
2219   BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_TEX_DATA(tex)) {
2220     /* texture animdata */
2221     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)tex, filter_mode);
2222 
2223     /* nodes */
2224     if ((tex->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2225       /* owner_id as id instead of texture,
2226        * since it'll otherwise be impossible to track the depth. */
2227 
2228       /* FIXME: perhaps as a result, textures should NOT be included under materials,
2229        * but under their own section instead so that free-floating textures can also be animated.
2230        */
2231       tmp_items += animdata_filter_ds_nodetree(
2232           ac, &tmp_data, ads, (ID *)tex, tex->nodetree, filter_mode);
2233     }
2234   }
2235   END_ANIMFILTER_SUBCHANNELS;
2236 
2237   /* did we find anything? */
2238   if (tmp_items) {
2239     /* include texture-expand widget? */
2240     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2241       /* check if filtering by active status */
2242       if (ANIMCHANNEL_ACTIVEOK(tex)) {
2243         ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id, NULL);
2244       }
2245     }
2246 
2247     /* now add the list of collected channels */
2248     BLI_movelisttolist(anim_data, &tmp_data);
2249     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2250     items += tmp_items;
2251   }
2252 
2253   /* return the number of items added to the list */
2254   return items;
2255 }
2256 
2257 /* NOTE: owner_id is the direct owner of the texture stack in question
2258  *       It used to be Material/Light/World before the Blender Internal removal for 2.8
2259  */
animdata_filter_ds_textures(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * owner_id,int filter_mode)2260 static size_t animdata_filter_ds_textures(
2261     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
2262 {
2263   MTex **mtex = NULL;
2264   size_t items = 0;
2265   int a = 0;
2266 
2267   /* get datatype specific data first */
2268   if (owner_id == NULL) {
2269     return 0;
2270   }
2271 
2272   switch (GS(owner_id->name)) {
2273     case ID_PA: {
2274       ParticleSettings *part = (ParticleSettings *)owner_id;
2275       mtex = (MTex **)(&part->mtex);
2276       break;
2277     }
2278     default: {
2279       /* invalid/unsupported option */
2280       if (G.debug & G_DEBUG) {
2281         printf("ERROR: Unsupported owner_id (i.e. texture stack) for filter textures - %s\n",
2282                owner_id->name);
2283       }
2284       return 0;
2285     }
2286   }
2287 
2288   /* Firstly check that we actually have some textures,
2289    * by gathering all textures in a temp list. */
2290   for (a = 0; a < MAX_MTEX; a++) {
2291     Tex *tex = (mtex[a]) ? mtex[a]->tex : NULL;
2292 
2293     /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */
2294     if (tex == NULL) {
2295       continue;
2296     }
2297 
2298     /* add texture's anim channels */
2299     items += animdata_filter_ds_texture(ac, anim_data, ads, tex, owner_id, filter_mode);
2300   }
2301 
2302   /* return the number of items added to the list */
2303   return items;
2304 }
2305 
animdata_filter_ds_material(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Material * ma,int filter_mode)2306 static size_t animdata_filter_ds_material(
2307     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Material *ma, int filter_mode)
2308 {
2309   ListBase tmp_data = {NULL, NULL};
2310   size_t tmp_items = 0;
2311   size_t items = 0;
2312 
2313   /* add material's animation data to temp collection */
2314   BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_MAT_OBJD(ma)) {
2315     /* material's animation data */
2316     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode);
2317 
2318     /* nodes */
2319     if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2320       tmp_items += animdata_filter_ds_nodetree(
2321           ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode);
2322     }
2323   }
2324   END_ANIMFILTER_SUBCHANNELS;
2325 
2326   /* did we find anything? */
2327   if (tmp_items) {
2328     /* include material-expand widget first */
2329     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2330       /* check if filtering by active status */
2331       if (ANIMCHANNEL_ACTIVEOK(ma)) {
2332         ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma, NULL);
2333       }
2334     }
2335 
2336     /* now add the list of collected channels */
2337     BLI_movelisttolist(anim_data, &tmp_data);
2338     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2339     items += tmp_items;
2340   }
2341 
2342   return items;
2343 }
2344 
animdata_filter_ds_materials(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2345 static size_t animdata_filter_ds_materials(
2346     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2347 {
2348   size_t items = 0;
2349   int a = 0;
2350 
2351   /* First pass: take the materials referenced via the Material slots of the object. */
2352   for (a = 1; a <= ob->totcol; a++) {
2353     Material *ma = BKE_object_material_get(ob, a);
2354 
2355     /* if material is valid, try to add relevant contents from here */
2356     if (ma) {
2357       /* add channels */
2358       items += animdata_filter_ds_material(ac, anim_data, ads, ma, filter_mode);
2359     }
2360   }
2361 
2362   /* return the number of items added to the list */
2363   return items;
2364 }
2365 
2366 /* ............ */
2367 
2368 /* Temporary context for modifier linked-data channel extraction */
2369 typedef struct tAnimFilterModifiersContext {
2370   bAnimContext *ac; /* anim editor context */
2371   bDopeSheet *ads;  /* dopesheet filtering settings */
2372 
2373   ListBase tmp_data; /* list of channels created (but not yet added to the main list) */
2374   size_t items;      /* number of channels created */
2375 
2376   int filter_mode; /* flags for stuff we want to filter */
2377 } tAnimFilterModifiersContext;
2378 
2379 /* dependency walker callback for modifier dependencies */
animfilter_modifier_idpoin_cb(void * afm_ptr,Object * ob,ID ** idpoin,int UNUSED (cb_flag))2380 static void animfilter_modifier_idpoin_cb(void *afm_ptr,
2381                                           Object *ob,
2382                                           ID **idpoin,
2383                                           int UNUSED(cb_flag))
2384 {
2385   tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
2386   ID *owner_id = &ob->id;
2387   ID *id = *idpoin;
2388 
2389   /* NOTE: the walker only guarantees to give us all the ID-ptr *slots*,
2390    * not just the ones which are actually used, so be careful!
2391    */
2392   if (id == NULL) {
2393     return;
2394   }
2395 
2396   /* check if this is something we're interested in... */
2397   switch (GS(id->name)) {
2398     case ID_TE: /* Textures */
2399     {
2400       Tex *tex = (Tex *)id;
2401       if (!(afm->ads->filterflag & ADS_FILTER_NOTEX)) {
2402         afm->items += animdata_filter_ds_texture(
2403             afm->ac, &afm->tmp_data, afm->ads, tex, owner_id, afm->filter_mode);
2404       }
2405       break;
2406     }
2407 
2408     /* TODO: images? */
2409     default:
2410       break;
2411   }
2412 }
2413 
2414 /* animation linked to data used by modifiers
2415  * NOTE: strictly speaking, modifier animation is already included under Object level
2416  *       but for some modifiers (e.g. Displace), there can be linked data that has settings
2417  *       which would be nice to animate (i.e. texture parameters) but which are not actually
2418  *       attached to any other objects/materials/etc. in the scene
2419  */
2420 /* TODO: do we want an expander for this? */
animdata_filter_ds_modifiers(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2421 static size_t animdata_filter_ds_modifiers(
2422     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2423 {
2424   tAnimFilterModifiersContext afm = {NULL};
2425   size_t items = 0;
2426 
2427   /* 1) create a temporary "context" containing all the info we have here to pass to the callback
2428    *    use to walk through the dependencies of the modifiers
2429    *
2430    * Assumes that all other unspecified values (i.e. accumulation buffers)
2431    * are zero'd out properly!
2432    */
2433   afm.ac = ac;
2434   afm.ads = ads;
2435   afm.filter_mode = filter_mode;
2436 
2437   /* 2) walk over dependencies */
2438   BKE_modifiers_foreach_ID_link(ob, animfilter_modifier_idpoin_cb, &afm);
2439 
2440   /* 3) extract data from the context, merging it back into the standard list */
2441   if (afm.items) {
2442     /* now add the list of collected channels */
2443     BLI_movelisttolist(anim_data, &afm.tmp_data);
2444     BLI_assert(BLI_listbase_is_empty(&afm.tmp_data));
2445     items += afm.items;
2446   }
2447 
2448   return items;
2449 }
2450 
2451 /* ............ */
2452 
animdata_filter_ds_particles(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2453 static size_t animdata_filter_ds_particles(
2454     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2455 {
2456   ParticleSystem *psys;
2457   size_t items = 0;
2458 
2459   for (psys = ob->particlesystem.first; psys; psys = psys->next) {
2460     ListBase tmp_data = {NULL, NULL};
2461     size_t tmp_items = 0;
2462 
2463     /* Note that when psys->part->adt is NULL the textures can still be
2464      * animated. */
2465     if (psys->part == NULL) {
2466       continue;
2467     }
2468 
2469     /* add particle-system's animation data to temp collection */
2470     BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_PART_OBJD(psys->part)) {
2471       /* particle system's animation data */
2472       tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
2473 
2474       /* textures */
2475       if (!(ads->filterflag & ADS_FILTER_NOTEX)) {
2476         tmp_items += animdata_filter_ds_textures(
2477             ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
2478       }
2479     }
2480     END_ANIMFILTER_SUBCHANNELS;
2481 
2482     /* did we find anything? */
2483     if (tmp_items) {
2484       /* include particle-expand widget first */
2485       if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2486         /* check if filtering by active status */
2487         if (ANIMCHANNEL_ACTIVEOK(psys->part)) {
2488           ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part, NULL);
2489         }
2490       }
2491 
2492       /* now add the list of collected channels */
2493       BLI_movelisttolist(anim_data, &tmp_data);
2494       BLI_assert(BLI_listbase_is_empty(&tmp_data));
2495       items += tmp_items;
2496     }
2497   }
2498 
2499   /* return the number of items added to the list */
2500   return items;
2501 }
2502 
animdata_filter_ds_obdata(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2503 static size_t animdata_filter_ds_obdata(
2504     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2505 {
2506   ListBase tmp_data = {NULL, NULL};
2507   size_t tmp_items = 0;
2508   size_t items = 0;
2509 
2510   IdAdtTemplate *iat = ob->data;
2511   short type = 0, expanded = 0;
2512 
2513   /* get settings based on data type */
2514   switch (ob->type) {
2515     case OB_CAMERA: /* ------- Camera ------------ */
2516     {
2517       Camera *ca = (Camera *)ob->data;
2518 
2519       if (ads->filterflag & ADS_FILTER_NOCAM) {
2520         return 0;
2521       }
2522 
2523       type = ANIMTYPE_DSCAM;
2524       expanded = FILTER_CAM_OBJD(ca);
2525       break;
2526     }
2527     case OB_LAMP: /* ---------- Light ----------- */
2528     {
2529       Light *la = (Light *)ob->data;
2530 
2531       if (ads->filterflag & ADS_FILTER_NOLAM) {
2532         return 0;
2533       }
2534 
2535       type = ANIMTYPE_DSLAM;
2536       expanded = FILTER_LAM_OBJD(la);
2537       break;
2538     }
2539     case OB_CURVE: /* ------- Curve ---------- */
2540     case OB_SURF:  /* ------- Nurbs Surface ---------- */
2541     case OB_FONT:  /* ------- Text Curve ---------- */
2542     {
2543       Curve *cu = (Curve *)ob->data;
2544 
2545       if (ads->filterflag & ADS_FILTER_NOCUR) {
2546         return 0;
2547       }
2548 
2549       type = ANIMTYPE_DSCUR;
2550       expanded = FILTER_CUR_OBJD(cu);
2551       break;
2552     }
2553     case OB_MBALL: /* ------- MetaBall ---------- */
2554     {
2555       MetaBall *mb = (MetaBall *)ob->data;
2556 
2557       if (ads->filterflag & ADS_FILTER_NOMBA) {
2558         return 0;
2559       }
2560 
2561       type = ANIMTYPE_DSMBALL;
2562       expanded = FILTER_MBALL_OBJD(mb);
2563       break;
2564     }
2565     case OB_ARMATURE: /* ------- Armature ---------- */
2566     {
2567       bArmature *arm = (bArmature *)ob->data;
2568 
2569       if (ads->filterflag & ADS_FILTER_NOARM) {
2570         return 0;
2571       }
2572 
2573       type = ANIMTYPE_DSARM;
2574       expanded = FILTER_ARM_OBJD(arm);
2575       break;
2576     }
2577     case OB_MESH: /* ------- Mesh ---------- */
2578     {
2579       Mesh *me = (Mesh *)ob->data;
2580 
2581       if (ads->filterflag & ADS_FILTER_NOMESH) {
2582         return 0;
2583       }
2584 
2585       type = ANIMTYPE_DSMESH;
2586       expanded = FILTER_MESH_OBJD(me);
2587       break;
2588     }
2589     case OB_LATTICE: /* ---- Lattice ---- */
2590     {
2591       Lattice *lt = (Lattice *)ob->data;
2592 
2593       if (ads->filterflag & ADS_FILTER_NOLAT) {
2594         return 0;
2595       }
2596 
2597       type = ANIMTYPE_DSLAT;
2598       expanded = FILTER_LATTICE_OBJD(lt);
2599       break;
2600     }
2601     case OB_SPEAKER: /* ---------- Speaker ----------- */
2602     {
2603       Speaker *spk = (Speaker *)ob->data;
2604 
2605       type = ANIMTYPE_DSSPK;
2606       expanded = FILTER_SPK_OBJD(spk);
2607       break;
2608     }
2609     case OB_HAIR: /* ---------- Hair ----------- */
2610     {
2611       Hair *hair = (Hair *)ob->data;
2612 
2613       if (ads->filterflag2 & ADS_FILTER_NOHAIR) {
2614         return 0;
2615       }
2616 
2617       type = ANIMTYPE_DSHAIR;
2618       expanded = FILTER_HAIR_OBJD(hair);
2619       break;
2620     }
2621     case OB_POINTCLOUD: /* ---------- PointCloud ----------- */
2622     {
2623       PointCloud *pointcloud = (PointCloud *)ob->data;
2624 
2625       if (ads->filterflag2 & ADS_FILTER_NOPOINTCLOUD) {
2626         return 0;
2627       }
2628 
2629       type = ANIMTYPE_DSPOINTCLOUD;
2630       expanded = FILTER_POINTS_OBJD(pointcloud);
2631       break;
2632     }
2633     case OB_VOLUME: /* ---------- Volume ----------- */
2634     {
2635       Volume *volume = (Volume *)ob->data;
2636 
2637       if (ads->filterflag2 & ADS_FILTER_NOVOLUME) {
2638         return 0;
2639       }
2640 
2641       type = ANIMTYPE_DSVOLUME;
2642       expanded = FILTER_VOLUME_OBJD(volume);
2643       break;
2644     }
2645   }
2646 
2647   /* add object data animation channels */
2648   BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
2649     /* animation data filtering */
2650     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)iat, filter_mode);
2651 
2652     /* sub-data filtering... */
2653     switch (ob->type) {
2654       case OB_LAMP: /* light - textures + nodetree */
2655       {
2656         Light *la = ob->data;
2657         bNodeTree *ntree = la->nodetree;
2658 
2659         /* nodetree */
2660         if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2661           tmp_items += animdata_filter_ds_nodetree(
2662               ac, &tmp_data, ads, &la->id, ntree, filter_mode);
2663         }
2664         break;
2665       }
2666     }
2667   }
2668   END_ANIMFILTER_SUBCHANNELS;
2669 
2670   /* did we find anything? */
2671   if (tmp_items) {
2672     /* include data-expand widget first */
2673     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2674       /* check if filtering by active status */
2675       if (ANIMCHANNEL_ACTIVEOK(iat)) {
2676         ANIMCHANNEL_NEW_CHANNEL(iat, type, iat, NULL);
2677       }
2678     }
2679 
2680     /* now add the list of collected channels */
2681     BLI_movelisttolist(anim_data, &tmp_data);
2682     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2683     items += tmp_items;
2684   }
2685 
2686   /* return the number of items added to the list */
2687   return items;
2688 }
2689 
2690 /* shapekey-level animation */
animdata_filter_ds_keyanim(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,Key * key,int filter_mode)2691 static size_t animdata_filter_ds_keyanim(
2692     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode)
2693 {
2694   ListBase tmp_data = {NULL, NULL};
2695   size_t tmp_items = 0;
2696   size_t items = 0;
2697 
2698   /* add shapekey-level animation channels */
2699   BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_SKE_OBJD(key)) {
2700     /* animation data filtering */
2701     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)key, filter_mode);
2702   }
2703   END_ANIMFILTER_SUBCHANNELS;
2704 
2705   /* did we find anything? */
2706   if (tmp_items) {
2707     /* include key-expand widget first */
2708     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2709       if (ANIMCHANNEL_ACTIVEOK(key)) {
2710         ANIMCHANNEL_NEW_CHANNEL(key, ANIMTYPE_DSSKEY, ob, NULL);
2711       }
2712     }
2713 
2714     /* now add the list of collected channels */
2715     BLI_movelisttolist(anim_data, &tmp_data);
2716     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2717     items += tmp_items;
2718   }
2719 
2720   /* return the number of items added to the list */
2721   return items;
2722 }
2723 
2724 /* object-level animation */
animdata_filter_ds_obanim(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2725 static size_t animdata_filter_ds_obanim(
2726     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2727 {
2728   ListBase tmp_data = {NULL, NULL};
2729   size_t tmp_items = 0;
2730   size_t items = 0;
2731 
2732   AnimData *adt = ob->adt;
2733   short type = 0, expanded = 1;
2734   void *cdata = NULL;
2735 
2736   /* determine the type of expander channels to use */
2737   /* this is the best way to do this for now... */
2738   ANIMDATA_FILTER_CASES(
2739       ob, /* Some useless long comment to prevent wrapping by old clang-format versions... */
2740       {/* AnimData - no channel, but consider data */},
2741       {/* NLA - no channel, but consider data */},
2742       { /* Drivers */
2743         type = ANIMTYPE_FILLDRIVERS;
2744         cdata = adt;
2745         expanded = EXPANDED_DRVD(adt);
2746       },
2747       {/* NLA Strip Controls - no dedicated channel for now (XXX) */},
2748       { /* Keyframes */
2749         type = ANIMTYPE_FILLACTD;
2750         cdata = adt->action;
2751         expanded = EXPANDED_ACTC(adt->action);
2752       });
2753 
2754   /* add object-level animation channels */
2755   BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
2756     /* animation data filtering */
2757     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ob, filter_mode);
2758   }
2759   END_ANIMFILTER_SUBCHANNELS;
2760 
2761   /* did we find anything? */
2762   if (tmp_items) {
2763     /* include anim-expand widget first */
2764     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2765       if (type != ANIMTYPE_NONE) {
2766         /* NOTE: active-status (and the associated checks) don't apply here... */
2767         ANIMCHANNEL_NEW_CHANNEL(cdata, type, ob, NULL);
2768       }
2769     }
2770 
2771     /* now add the list of collected channels */
2772     BLI_movelisttolist(anim_data, &tmp_data);
2773     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2774     items += tmp_items;
2775   }
2776 
2777   /* return the number of items added to the list */
2778   return items;
2779 }
2780 
2781 /* get animation channels from object2 */
animdata_filter_dopesheet_ob(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Base * base,int filter_mode)2782 static size_t animdata_filter_dopesheet_ob(
2783     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
2784 {
2785   ListBase tmp_data = {NULL, NULL};
2786   Object *ob = base->object;
2787   size_t tmp_items = 0;
2788   size_t items = 0;
2789 
2790   /* filter data contained under object first */
2791   BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_OBJC(ob)) {
2792     Key *key = BKE_key_from_object(ob);
2793 
2794     /* object-level animation */
2795     if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) {
2796       tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode);
2797     }
2798 
2799     /* particle deflector textures */
2800     if (ob->pd != NULL && ob->pd->tex != NULL && !(ads->filterflag & ADS_FILTER_NOTEX)) {
2801       tmp_items += animdata_filter_ds_texture(
2802           ac, &tmp_data, ads, ob->pd->tex, &ob->id, filter_mode);
2803     }
2804 
2805     /* shape-key */
2806     if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
2807       tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode);
2808     }
2809 
2810     /* modifiers */
2811     if ((ob->modifiers.first) && !(ads->filterflag & ADS_FILTER_NOMODIFIERS)) {
2812       tmp_items += animdata_filter_ds_modifiers(ac, &tmp_data, ads, ob, filter_mode);
2813     }
2814 
2815     /* materials */
2816     if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) {
2817       tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode);
2818     }
2819 
2820     /* object data */
2821     if (ob->data) {
2822       tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode);
2823     }
2824 
2825     /* particles */
2826     if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) {
2827       tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode);
2828     }
2829 
2830     /* grease pencil */
2831     if ((ob->type == OB_GPENCIL) && (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
2832       tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode);
2833     }
2834   }
2835   END_ANIMFILTER_SUBCHANNELS;
2836 
2837   /* if we collected some channels, add these to the new list... */
2838   if (tmp_items) {
2839     /* firstly add object expander if required */
2840     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2841       /* check if filtering by selection */
2842       /* XXX: double-check on this -
2843        * most of the time, a lot of tools need to filter out these channels! */
2844       if (ANIMCHANNEL_SELOK((base->flag & BASE_SELECTED))) {
2845         /* check if filtering by active status */
2846         if (ANIMCHANNEL_ACTIVEOK(ob)) {
2847           ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob, NULL);
2848         }
2849       }
2850     }
2851 
2852     /* now add the list of collected channels */
2853     BLI_movelisttolist(anim_data, &tmp_data);
2854     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2855     items += tmp_items;
2856   }
2857 
2858   /* return the number of items added */
2859   return items;
2860 }
2861 
animdata_filter_ds_world(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,World * wo,int filter_mode)2862 static size_t animdata_filter_ds_world(
2863     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode)
2864 {
2865   ListBase tmp_data = {NULL, NULL};
2866   size_t tmp_items = 0;
2867   size_t items = 0;
2868 
2869   /* add world animation channels */
2870   BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_WOR_SCED(wo)) {
2871     /* animation data filtering */
2872     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode);
2873 
2874     /* nodes */
2875     if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2876       tmp_items += animdata_filter_ds_nodetree(
2877           ac, &tmp_data, ads, (ID *)wo, wo->nodetree, filter_mode);
2878     }
2879   }
2880   END_ANIMFILTER_SUBCHANNELS;
2881 
2882   /* did we find anything? */
2883   if (tmp_items) {
2884     /* include data-expand widget first */
2885     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2886       /* check if filtering by active status */
2887       if (ANIMCHANNEL_ACTIVEOK(wo)) {
2888         ANIMCHANNEL_NEW_CHANNEL(wo, ANIMTYPE_DSWOR, sce, NULL);
2889       }
2890     }
2891 
2892     /* now add the list of collected channels */
2893     BLI_movelisttolist(anim_data, &tmp_data);
2894     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2895     items += tmp_items;
2896   }
2897 
2898   /* return the number of items added to the list */
2899   return items;
2900 }
2901 
animdata_filter_ds_scene(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,int filter_mode)2902 static size_t animdata_filter_ds_scene(
2903     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
2904 {
2905   ListBase tmp_data = {NULL, NULL};
2906   size_t tmp_items = 0;
2907   size_t items = 0;
2908 
2909   AnimData *adt = sce->adt;
2910   short type = 0, expanded = 1;
2911   void *cdata = NULL;
2912 
2913   /* determine the type of expander channels to use */
2914   /* this is the best way to do this for now... */
2915   ANIMDATA_FILTER_CASES(
2916       sce, /* Some useless long comment to prevent wrapping by old clang-format versions... */
2917       {/* AnimData - no channel, but consider data */},
2918       {/* NLA - no channel, but consider data */},
2919       { /* Drivers */
2920         type = ANIMTYPE_FILLDRIVERS;
2921         cdata = adt;
2922         expanded = EXPANDED_DRVD(adt);
2923       },
2924       {/* NLA Strip Controls - no dedicated channel for now (XXX) */},
2925       { /* Keyframes */
2926         type = ANIMTYPE_FILLACTD;
2927         cdata = adt->action;
2928         expanded = EXPANDED_ACTC(adt->action);
2929       });
2930 
2931   /* add scene-level animation channels */
2932   BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
2933     /* animation data filtering */
2934     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)sce, filter_mode);
2935   }
2936   END_ANIMFILTER_SUBCHANNELS;
2937 
2938   /* did we find anything? */
2939   if (tmp_items) {
2940     /* include anim-expand widget first */
2941     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2942       if (type != ANIMTYPE_NONE) {
2943         /* NOTE: active-status (and the associated checks) don't apply here... */
2944         ANIMCHANNEL_NEW_CHANNEL(cdata, type, sce, NULL);
2945       }
2946     }
2947 
2948     /* now add the list of collected channels */
2949     BLI_movelisttolist(anim_data, &tmp_data);
2950     BLI_assert(BLI_listbase_is_empty(&tmp_data));
2951     items += tmp_items;
2952   }
2953 
2954   /* return the number of items added to the list */
2955   return items;
2956 }
2957 
animdata_filter_dopesheet_scene(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,int filter_mode)2958 static size_t animdata_filter_dopesheet_scene(
2959     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
2960 {
2961   ListBase tmp_data = {NULL, NULL};
2962   size_t tmp_items = 0;
2963   size_t items = 0;
2964 
2965   /* filter data contained under object first */
2966   BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_SCEC(sce)) {
2967     bNodeTree *ntree = sce->nodetree;
2968     bGPdata *gpd = sce->gpd;
2969     World *wo = sce->world;
2970 
2971     /* Action, Drivers, or NLA for Scene */
2972     if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
2973       tmp_items += animdata_filter_ds_scene(ac, &tmp_data, ads, sce, filter_mode);
2974     }
2975 
2976     /* world */
2977     if ((wo) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
2978       tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode);
2979     }
2980 
2981     /* nodetree */
2982     if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2983       tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode);
2984     }
2985 
2986     /* line styles */
2987     if ((ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) {
2988       tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode);
2989     }
2990 
2991     /* grease pencil */
2992     if ((gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
2993       tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, gpd, filter_mode);
2994     }
2995 
2996     /* TODO: one day, when sequencer becomes its own datatype,
2997      * perhaps it should be included here. */
2998   }
2999   END_ANIMFILTER_SUBCHANNELS;
3000 
3001   /* if we collected some channels, add these to the new list... */
3002   if (tmp_items) {
3003     /* firstly add object expander if required */
3004     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3005       /* check if filtering by selection */
3006       if (ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED))) {
3007         /* NOTE: active-status doesn't matter for this! */
3008         ANIMCHANNEL_NEW_CHANNEL(sce, ANIMTYPE_SCENE, sce, NULL);
3009       }
3010     }
3011 
3012     /* now add the list of collected channels */
3013     BLI_movelisttolist(anim_data, &tmp_data);
3014     BLI_assert(BLI_listbase_is_empty(&tmp_data));
3015     items += tmp_items;
3016   }
3017 
3018   /* return the number of items added */
3019   return items;
3020 }
3021 
animdata_filter_ds_movieclip(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,MovieClip * clip,int filter_mode)3022 static size_t animdata_filter_ds_movieclip(
3023     bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, MovieClip *clip, int filter_mode)
3024 {
3025   ListBase tmp_data = {NULL, NULL};
3026   size_t tmp_items = 0;
3027   size_t items = 0;
3028   /* add world animation channels */
3029   BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_MCLIP(clip)) {
3030     /* animation data filtering */
3031     tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)clip, filter_mode);
3032   }
3033   END_ANIMFILTER_SUBCHANNELS;
3034   /* did we find anything? */
3035   if (tmp_items) {
3036     /* include data-expand widget first */
3037     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3038       /* check if filtering by active status */
3039       if (ANIMCHANNEL_ACTIVEOK(clip)) {
3040         ANIMCHANNEL_NEW_CHANNEL(clip, ANIMTYPE_DSMCLIP, clip, NULL);
3041       }
3042     }
3043     /* now add the list of collected channels */
3044     BLI_movelisttolist(anim_data, &tmp_data);
3045     BLI_assert(BLI_listbase_is_empty(&tmp_data));
3046     items += tmp_items;
3047   }
3048   /* return the number of items added to the list */
3049   return items;
3050 }
3051 
animdata_filter_dopesheet_movieclips(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,int filter_mode)3052 static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac,
3053                                                    ListBase *anim_data,
3054                                                    bDopeSheet *ads,
3055                                                    int filter_mode)
3056 {
3057   size_t items = 0;
3058   MovieClip *clip;
3059   for (clip = ac->bmain->movieclips.first; clip != NULL; clip = clip->id.next) {
3060     /* only show if gpd is used by something... */
3061     if (ID_REAL_USERS(clip) < 1) {
3062       continue;
3063     }
3064     items += animdata_filter_ds_movieclip(ac, anim_data, ads, clip, filter_mode);
3065   }
3066   /* return the number of items added to the list */
3067   return items;
3068 }
3069 
3070 /* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
animdata_filter_base_is_ok(bDopeSheet * ads,Base * base,int filter_mode)3071 static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_mode)
3072 {
3073   Object *ob = base->object;
3074 
3075   if (base->object == NULL) {
3076     return false;
3077   }
3078 
3079   /* firstly, check if object can be included, by the following factors:
3080    * - if only visible, must check for layer and also viewport visibility
3081    *   --> while tools may demand only visible, user setting takes priority
3082    *       as user option controls whether sets of channels get included while
3083    *       tool-flag takes into account collapsed/open channels too
3084    * - if only selected, must check if object is selected
3085    * - there must be animation data to edit (this is done recursively as we
3086    *   try to add the channels)
3087    */
3088   if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
3089     /* layer visibility - we check both object and base, since these may not be in sync yet */
3090     if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0 || (base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
3091       return false;
3092     }
3093 
3094     /* outliner restrict-flag */
3095     if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
3096       return false;
3097     }
3098   }
3099 
3100   /* if only F-Curves with visible flags set can be shown, check that
3101    * data-block hasn't been set to invisible.
3102    */
3103   if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
3104     if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) {
3105       return false;
3106     }
3107   }
3108 
3109   /* Pinned curves are visible regardless of selection flags. */
3110   if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
3111     return true;
3112   }
3113 
3114   /* Special case.
3115    * We don't do recursive checks for pin, but we need to deal with tricky
3116    * setup like animated camera lens without animated camera location.
3117    * Without such special handle here we wouldn't be able to bin such
3118    * camera data only animation to the editor.
3119    */
3120   if (ob->adt == NULL && ob->data != NULL) {
3121     AnimData *data_adt = BKE_animdata_from_id(ob->data);
3122     if (data_adt != NULL && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
3123       return true;
3124     }
3125   }
3126 
3127   /* check selection and object type filters */
3128   if ((ads->filterflag & ADS_FILTER_ONLYSEL) &&
3129       !((base->flag & BASE_SELECTED) /*|| (base == sce->basact)*/)) {
3130     /* only selected should be shown */
3131     return false;
3132   }
3133 
3134   /* check if object belongs to the filtering group if option to filter
3135    * objects by the grouped status is on
3136    * - used to ease the process of doing multiple-character choreographies
3137    */
3138   if (ads->filter_grp != NULL) {
3139     if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) {
3140       return false;
3141     }
3142   }
3143 
3144   /* no reason to exclude this object... */
3145   return true;
3146 }
3147 
3148 /* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */
ds_base_sorting_cmp(const void * base1_ptr,const void * base2_ptr)3149 static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
3150 {
3151   const Base *b1 = *((const Base **)base1_ptr);
3152   const Base *b2 = *((const Base **)base2_ptr);
3153 
3154   return strcmp(b1->object->id.name + 2, b2->object->id.name + 2);
3155 }
3156 
3157 /* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
animdata_filter_ds_sorted_bases(bDopeSheet * ads,ViewLayer * view_layer,int filter_mode,size_t * r_usable_bases)3158 static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads,
3159                                               ViewLayer *view_layer,
3160                                               int filter_mode,
3161                                               size_t *r_usable_bases)
3162 {
3163   /* Create an array with space for all the bases, but only containing the usable ones */
3164   size_t tot_bases = BLI_listbase_count(&view_layer->object_bases);
3165   size_t num_bases = 0;
3166 
3167   Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
3168   LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
3169     if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
3170       sorted_bases[num_bases++] = base;
3171     }
3172   }
3173 
3174   /* Sort this list of pointers (based on the names) */
3175   qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp);
3176 
3177   /* Return list of sorted bases */
3178   *r_usable_bases = num_bases;
3179   return sorted_bases;
3180 }
3181 
3182 /* TODO: implement pinning...
3183  * (if and when pinning is done, what we need to do is to provide freeing mechanisms -
3184  * to protect against data that was deleted). */
animdata_filter_dopesheet(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,int filter_mode)3185 static size_t animdata_filter_dopesheet(bAnimContext *ac,
3186                                         ListBase *anim_data,
3187                                         bDopeSheet *ads,
3188                                         int filter_mode)
3189 {
3190   Scene *scene = (Scene *)ads->source;
3191   ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
3192   size_t items = 0;
3193 
3194   /* check that we do indeed have a scene */
3195   if ((ads->source == NULL) || (GS(ads->source->name) != ID_SCE)) {
3196     printf("Dope Sheet Error: No scene!\n");
3197     if (G.debug & G_DEBUG) {
3198       printf("\tPointer = %p, Name = '%s'\n",
3199              (void *)ads->source,
3200              (ads->source) ? ads->source->name : NULL);
3201     }
3202     return 0;
3203   }
3204 
3205   /* augment the filter-flags with settings based on the dopesheet filterflags
3206    * so that some temp settings can get added automagically...
3207    */
3208   if (ads->filterflag & ADS_FILTER_SELEDIT) {
3209     /* only selected F-Curves should get their keyframes considered for editability */
3210     filter_mode |= ANIMFILTER_SELEDIT;
3211   }
3212 
3213   /* Cache files level animations (frame duration and such). */
3214   if (!(ads->filterflag2 & ADS_FILTER_NOCACHEFILES) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) {
3215     CacheFile *cache_file = ac->bmain->cachefiles.first;
3216     for (; cache_file; cache_file = cache_file->id.next) {
3217       items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
3218     }
3219   }
3220 
3221   /* movie clip's animation */
3222   if (!(ads->filterflag2 & ADS_FILTER_NOMOVIECLIPS) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) {
3223     items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode);
3224   }
3225 
3226   /* Scene-linked animation - e.g. world, compositing nodes, scene anim
3227    * (including sequencer currently). */
3228   items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
3229 
3230   /* If filtering for channel drawing, we want the objects in alphabetical order,
3231    * to make it easier to predict where items are in the hierarchy
3232    * - This order only really matters
3233    *   if we need to show all channels in the list (e.g. for drawing).
3234    *   (XXX: What about lingering "active" flags? The order may now become unpredictable)
3235    * - Don't do this if this behavior has been turned off (i.e. due to it being too slow)
3236    * - Don't do this if there's just a single object
3237    */
3238   if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
3239       (view_layer->object_bases.first != view_layer->object_bases.last)) {
3240     /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
3241     /* TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... */
3242     Base **sorted_bases;
3243     size_t num_bases;
3244 
3245     sorted_bases = animdata_filter_ds_sorted_bases(ads, view_layer, filter_mode, &num_bases);
3246     if (sorted_bases) {
3247       /* Add the necessary channels for these bases... */
3248       for (size_t i = 0; i < num_bases; i++) {
3249         items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode);
3250       }
3251 
3252       /* TODO: store something to validate whether any changes are needed? */
3253 
3254       /* free temporary data */
3255       MEM_freeN(sorted_bases);
3256     }
3257   }
3258   else {
3259     /* Filter and add contents of each base (i.e. object) without them sorting first
3260      * NOTE: This saves performance in cases where order doesn't matter
3261      */
3262     LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
3263       if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
3264         /* since we're still here, this object should be usable */
3265         items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
3266       }
3267     }
3268   }
3269 
3270   /* return the number of items in the list */
3271   return items;
3272 }
3273 
3274 /* Summary track for DopeSheet/Action Editor
3275  * - return code is whether the summary lets the other channels get drawn
3276  */
animdata_filter_dopesheet_summary(bAnimContext * ac,ListBase * anim_data,int filter_mode,size_t * items)3277 static short animdata_filter_dopesheet_summary(bAnimContext *ac,
3278                                                ListBase *anim_data,
3279                                                int filter_mode,
3280                                                size_t *items)
3281 {
3282   bDopeSheet *ads = NULL;
3283 
3284   /* get the DopeSheet information to use
3285    * - we should only need to deal with the DopeSheet/Action Editor,
3286    *   since all the other Animation Editors won't have this concept
3287    *   being applicable.
3288    */
3289   if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) {
3290     SpaceAction *saction = (SpaceAction *)ac->sl;
3291     ads = &saction->ads;
3292   }
3293   else {
3294     /* invalid space type - skip this summary channels */
3295     return 1;
3296   }
3297 
3298   /* dopesheet summary
3299    * - only for drawing and/or selecting keyframes in channels, but not for real editing
3300    * - only useful for DopeSheet/Action/etc. editors where it is actually useful
3301    */
3302   if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
3303     bAnimListElem *ale = make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, NULL);
3304     if (ale) {
3305       BLI_addtail(anim_data, ale);
3306       (*items)++;
3307     }
3308 
3309     /* If summary is collapsed, don't show other channels beneath this - this check is put inside
3310      * the summary check so that it doesn't interfere with normal operation.
3311      */
3312     if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED) {
3313       return 0;
3314     }
3315   }
3316 
3317   /* the other channels beneath this can be shown */
3318   return 1;
3319 }
3320 
3321 /* ......................... */
3322 
3323 /* filter data associated with a channel - usually for handling summary-channels in DopeSheet */
animdata_filter_animchan(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bAnimListElem * channel,int filter_mode)3324 static size_t animdata_filter_animchan(bAnimContext *ac,
3325                                        ListBase *anim_data,
3326                                        bDopeSheet *ads,
3327                                        bAnimListElem *channel,
3328                                        int filter_mode)
3329 {
3330   size_t items = 0;
3331 
3332   /* data to filter depends on channel type */
3333   /* NOTE: only common channel-types have been handled for now. More can be added as necessary */
3334   switch (channel->type) {
3335     case ANIMTYPE_SUMMARY:
3336       items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode);
3337       break;
3338 
3339     case ANIMTYPE_SCENE:
3340       items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode);
3341       break;
3342 
3343     case ANIMTYPE_OBJECT:
3344       items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
3345       break;
3346 
3347     case ANIMTYPE_DSCACHEFILE:
3348       items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode);
3349       break;
3350 
3351     case ANIMTYPE_ANIMDATA:
3352       items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode);
3353       break;
3354 
3355     default:
3356       printf("ERROR: Unsupported channel type (%d) in animdata_filter_animchan()\n",
3357              channel->type);
3358       break;
3359   }
3360 
3361   return items;
3362 }
3363 
3364 /* ----------- Cleanup API --------------- */
3365 
3366 /* Remove entries with invalid types in animation channel list */
animdata_filter_remove_invalid(ListBase * anim_data)3367 static size_t animdata_filter_remove_invalid(ListBase *anim_data)
3368 {
3369   bAnimListElem *ale, *next;
3370   size_t items = 0;
3371 
3372   /* only keep entries with valid types */
3373   for (ale = anim_data->first; ale; ale = next) {
3374     next = ale->next;
3375 
3376     if (ale->type == ANIMTYPE_NONE) {
3377       BLI_freelinkN(anim_data, ale);
3378     }
3379     else {
3380       items++;
3381     }
3382   }
3383 
3384   return items;
3385 }
3386 
3387 /* Remove duplicate entries in animation channel list */
animdata_filter_remove_duplis(ListBase * anim_data)3388 static size_t animdata_filter_remove_duplis(ListBase *anim_data)
3389 {
3390   bAnimListElem *ale, *next;
3391   GSet *gs;
3392   size_t items = 0;
3393 
3394   /* build new hashtable to efficiently store and retrieve which entries have been
3395    * encountered already while searching
3396    */
3397   gs = BLI_gset_ptr_new(__func__);
3398 
3399   /* loop through items, removing them from the list if a similar item occurs already */
3400   for (ale = anim_data->first; ale; ale = next) {
3401     next = ale->next;
3402 
3403     /* check if hash has any record of an entry like this
3404      * - just use ale->data for now, though it would be nicer to involve
3405      *   ale->type in combination too to capture corner cases
3406      *   (where same data performs differently)
3407      */
3408     if (BLI_gset_add(gs, ale->data)) {
3409       /* this entry is 'unique' and can be kept */
3410       items++;
3411     }
3412     else {
3413       /* this entry isn't needed anymore */
3414       BLI_freelinkN(anim_data, ale);
3415     }
3416   }
3417 
3418   /* free the hash... */
3419   BLI_gset_free(gs, NULL);
3420 
3421   /* return the number of items still in the list */
3422   return items;
3423 }
3424 
3425 /* ----------- Public API --------------- */
3426 
3427 /**
3428  * This function filters the active data source to leave only animation channels suitable for
3429  * usage by the caller. It will return the length of the list
3430  *
3431  * \param anim_data: Is a pointer to a #ListBase,
3432  * to which the filtered animation channels will be placed for use.
3433  * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
3434  */
ANIM_animdata_filter(bAnimContext * ac,ListBase * anim_data,eAnimFilter_Flags filter_mode,void * data,eAnimCont_Types datatype)3435 size_t ANIM_animdata_filter(bAnimContext *ac,
3436                             ListBase *anim_data,
3437                             eAnimFilter_Flags filter_mode,
3438                             void *data,
3439                             eAnimCont_Types datatype)
3440 {
3441   size_t items = 0;
3442 
3443   /* only filter data if there's somewhere to put it */
3444   if (data && anim_data) {
3445     /* firstly filter the data */
3446     switch (datatype) {
3447       /* Action-Editing Modes */
3448       case ANIMCONT_ACTION: /* 'Action Editor' */
3449       {
3450         Object *obact = ac->obact;
3451         SpaceAction *saction = (SpaceAction *)ac->sl;
3452         bDopeSheet *ads = (saction) ? &saction->ads : NULL;
3453 
3454         /* specially check for AnimData filter, see T36687. */
3455         if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) {
3456           /* all channels here are within the same AnimData block, hence this special case */
3457           if (LIKELY(obact->adt)) {
3458             ANIMCHANNEL_NEW_CHANNEL(obact->adt, ANIMTYPE_ANIMDATA, (ID *)obact, NULL);
3459           }
3460         }
3461         else {
3462           /* The check for the DopeSheet summary is included here
3463            * since the summary works here too. */
3464           if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3465             items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact);
3466           }
3467         }
3468 
3469         break;
3470       }
3471       case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
3472       {
3473         Key *key = (Key *)data;
3474 
3475         /* specially check for AnimData filter, see T36687. */
3476         if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) {
3477           /* all channels here are within the same AnimData block, hence this special case */
3478           if (LIKELY(key->adt)) {
3479             ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, (ID *)key, NULL);
3480           }
3481         }
3482         else {
3483           /* The check for the DopeSheet summary is included here
3484            * since the summary works here too. */
3485           if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3486             items = animdata_filter_shapekey(ac, anim_data, key, filter_mode);
3487           }
3488         }
3489 
3490         break;
3491       }
3492 
3493       /* Modes for Specialty Data Types (i.e. not keyframes) */
3494       case ANIMCONT_GPENCIL: {
3495         if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3496           items = animdata_filter_gpencil(ac, anim_data, data, filter_mode);
3497         }
3498         break;
3499       }
3500       case ANIMCONT_MASK: {
3501         if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3502           items = animdata_filter_mask(ac->bmain, anim_data, data, filter_mode);
3503         }
3504         break;
3505       }
3506 
3507       /* DopeSheet Based Modes */
3508       case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
3509       {
3510         /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
3511         if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3512           items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
3513         }
3514         break;
3515       }
3516       case ANIMCONT_FCURVES: /* Graph Editor -> F-Curves/Animation Editing */
3517       case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
3518       case ANIMCONT_NLA:     /* NLA Editor */
3519       {
3520         /* all of these editors use the basic DopeSheet data for filtering options,
3521          * but don't have all the same features */
3522         items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
3523         break;
3524       }
3525 
3526       /* Timeline Mode - Basically the same as dopesheet,
3527        * except we only have the summary for now */
3528       case ANIMCONT_TIMELINE: {
3529         /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
3530         if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3531           items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
3532         }
3533         break;
3534       }
3535 
3536       /* Special/Internal Use */
3537       case ANIMCONT_CHANNEL: /* animation channel */
3538       {
3539         bDopeSheet *ads = ac->ads;
3540 
3541         /* based on the channel type, filter relevant data for this */
3542         items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode);
3543         break;
3544       }
3545 
3546       /* unhandled */
3547       default: {
3548         printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype);
3549         break;
3550       }
3551     }
3552 
3553     /* remove any 'weedy' entries */
3554     items = animdata_filter_remove_invalid(anim_data);
3555 
3556     /* remove duplicates (if required) */
3557     if (filter_mode & ANIMFILTER_NODUPLIS) {
3558       items = animdata_filter_remove_duplis(anim_data);
3559     }
3560   }
3561 
3562   /* return the number of items in the list */
3563   return items;
3564 }
3565 
3566 /* ************************************************************ */
3567