diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_dopesheet.py | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 77 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_action_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_action.c | 7 |
4 files changed, 81 insertions, 7 deletions
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 546c9c2808d..cea4eaf5149 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -101,6 +101,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): if bpy.data.grease_pencil: row.prop(dopesheet, "show_gpencil", text="") + layout.prop(dopesheet, "use_datablock_sorting", text="") ####################################### # DopeSheet Editor - General/Standard UI diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 53ce1e944f4..a4d5fefe2eb 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2730,6 +2730,8 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d return items; } + +/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode) { Object *ob = base->object; @@ -2783,11 +2785,42 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base return true; } +/* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */ +static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr) +{ + const Base *b1 = *((Base **)base1_ptr); + const Base *b2 = *((Base **)base2_ptr); + + return strcmp(b1->object->id.name, b2->object->id.name); +} + +/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */ +static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases) +{ + /* Create an array with space for all the bases, but only containing the usable ones */ + size_t tot_bases = BLI_listbase_count(&scene->base); + size_t num_bases = 0; + + Base **sorted_bases = MEM_callocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases"); + for (Base *base = scene->base.first; base; base = base->next) { + if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { + sorted_bases[num_bases++] = base; + } + } + + /* Sort this list of pointers (based on the names) */ + qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp); + + /* Return list of sorted bases */ + *r_usable_bases = num_bases; + return sorted_bases; +} + + // TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted) static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode) { Scene *scene = (Scene *)ads->source; - Base *base; size_t items = 0; /* check that we do indeed have a scene */ @@ -2809,11 +2842,43 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode); - /* loop over all bases (i.e. objects) in the scene */ - for (base = scene->base.first; base; base = base->next) { - if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { - /* since we're still here, this object should be usable */ - items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); + /* If filtering for channel drawing, we want the objects in alphabetical order, + * to make it easier to predict where items are in the hierarchy + * - This order only really matters if we need to show all channels in the list (e.g. for drawing) + * (XXX: What about lingering "active" flags? The order may now become unpredictable) + * - Don't do this if this behaviour has been turned off (i.e. due to it being too slow) + * - Don't do this if there's just a single object + */ + if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) && + (scene->base.first != scene->base.last)) + { + /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */ + // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... + Base **sorted_bases; + size_t num_bases; + + sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases); + if (sorted_bases) { + /* Add the necessary channels for these bases... */ + for (size_t i = 0; i < num_bases; i++) { + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode); + } + + // TODO: store something to validate whether any changes are needed? + + /* free temporary data */ + MEM_freeN(sorted_bases); + } + } + else { + /* Filter and add contents of each base (i.e. object) without them sorting first + * NOTE: This saves performance in cases where order doesn't matter + */ + for (Base *base = scene->base.first; base; base = base->next) { + if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { + /* since we're still here, this object should be usable */ + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); + } } } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 4d82e4528d6..ec2a8e2f612 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -627,8 +627,9 @@ typedef enum eDopeSheet_FilterFlag { typedef enum eDopeSheet_Flag { ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */ ADS_FLAG_SHOW_DBFILTERS = (1 << 1), /* show filters for datablocks */ - + ADS_FLAG_FUZZY_NAMES = (1 << 2), /* use fuzzy/partial string matches when ADS_FILTER_BY_FCU_NAME is enabled (WARNING: expensive operation) */ + ADS_FLAG_NO_DB_SORT = (1 << 3), /* do not sort datablocks (mostly objects) by name (NOTE: potentially expensive operation) */ /* NOTE: datablock filter flags continued (1 << 10) onwards... */ } eDopeSheet_Flag; diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 7c21ce95a1d..907ee8ba1c7 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -308,6 +308,13 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + prop = RNA_def_property(srna, "use_datablock_sorting", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADS_FLAG_NO_DB_SORT); + RNA_def_property_ui_text(prop, "Sort Datablocks", + "Alphabetically sorts datablocks - mainly objects in the scene (disable to increase viewport speed)"); + RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); + RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* Debug Filtering Settings */ prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS); |