Fix T38897: Problems moving animation channels up and down in dope sheet/action editor.

Basic idea is to check whether an element is visible or not, and ignore those that are hidden, during move up/down.

Reviewers: aligorith

Reviewed By: aligorith

Differential Revision: https://developer.blender.org/D376
This commit is contained in:
Bastien Montagne 2014-03-14 12:45:22 +01:00
parent ade6646755
commit 1f3655d224
Notes: blender-bot 2023-02-14 11:06:09 +01:00
Referenced by issue #40304, PgUp and PgDn no longer work to move NLA tracks up and down
Referenced by issue #38897, Problems moving animation channels up and down in dope sheet/action editor
1 changed files with 74 additions and 15 deletions

View File

@ -36,6 +36,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BKE_library.h"
#include "DNA_anim_types.h"
@ -653,7 +654,8 @@ typedef struct tReorderChannelIsland {
typedef enum eReorderIslandFlag {
REORDER_ISLAND_SELECTED = (1 << 0), /* island is selected */
REORDER_ISLAND_UNTOUCHABLE = (1 << 1), /* island should be ignored */
REORDER_ISLAND_MOVED = (1 << 2) /* island has already been moved */
REORDER_ISLAND_MOVED = (1 << 2), /* island has already been moved */
REORDER_ISLAND_HIDDEN = (1 << 3), /* island is not visible */
} eReorderIslandFlag;
@ -691,7 +693,12 @@ static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
if (rearrange_island_ok(island)) {
/* moving up = moving before the previous island, otherwise we're in the same place */
tReorderChannelIsland *prev = island->prev;
/* Skip hidden islands! */
while (prev && prev->flag & REORDER_ISLAND_HIDDEN) {
prev = prev->prev;
}
if (prev) {
/* remove from current position */
BLI_remlink(list, island);
@ -711,7 +718,12 @@ static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
if (rearrange_island_ok(island)) {
/* moving down = moving after the next island, otherwise we're in the same place */
tReorderChannelIsland *next = island->next;
/* Skip hidden islands! */
while (next && next->flag & REORDER_ISLAND_HIDDEN) {
next = next->next;
}
if (next) {
/* can only move past if next is not untouchable (i.e. nothing can go after it) */
if ((next->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) {
@ -784,7 +796,7 @@ static AnimChanRearrangeFp rearrange_get_mode_func(short mode)
/* Rearrange Islands Generics ------------------------------------- */
/* add channel into list of islands */
static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList, Link *channel, short type)
static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList, Link *channel, short type, const bool is_hidden)
{
tReorderChannelIsland *island = islands->last; /* always try to add to last island if possible */
bool is_sel = false, is_untouchable = false;
@ -819,9 +831,15 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
}
/* do we need to add to a new island? */
if ((island == NULL) || /* 1) no islands yet */
((island->flag & REORDER_ISLAND_SELECTED) == 0) || /* 2) unselected islands have single channels only - to allow up/down movement */
(is_sel == 0)) /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */
if (/* 1) no islands yet */
(island == NULL) ||
/* 2) unselected islands have single channels only - to allow up/down movement */
((island->flag & REORDER_ISLAND_SELECTED) == 0) ||
/* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */
(is_sel == 0) ||
/* 4) hidden status changes */
((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden)
)
{
/* create a new island now */
island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
@ -831,6 +849,8 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
island->flag |= REORDER_ISLAND_SELECTED;
if (is_untouchable)
island->flag |= REORDER_ISLAND_UNTOUCHABLE;
if (is_hidden)
island->flag |= REORDER_ISLAND_HIDDEN;
}
/* add channel to island - need to remove it from its existing list first though */
@ -858,8 +878,16 @@ static void rearrange_animchannel_flatten_islands(ListBase *islands, ListBase *s
/* ............................. */
static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, short type)
{
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
ANIM_animdata_filter(ac, anim_data_visible, filter, ac->data, type);
}
/* performing rearranging of channels using islands */
static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func, short mode, short type)
static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func,
short mode, short type, ListBase *anim_data_visible)
{
ListBase islands = {NULL, NULL};
Link *channel, *chanNext = NULL;
@ -871,8 +899,10 @@ static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp re
/* group channels into islands */
for (channel = list->first; channel; channel = chanNext) {
/* find out whether this channel is present in anim_data_visible or not! */
const bool is_hidden = (BLI_findptr(anim_data_visible, channel, offsetof(bAnimListElem, data)) == NULL);
chanNext = channel->next;
rearrange_animchannel_add_to_islands(&islands, list, channel, type);
rearrange_animchannel_add_to_islands(&islands, list, channel, type, is_hidden);
}
/* perform moving of selected islands now, but only if there is more than one of 'em so that something will happen
@ -907,9 +937,10 @@ static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp re
* ! NLA tracks are displayed in opposite order, so directions need care
* mode: REARRANGE_ANIMCHAN_*
*/
static void rearrange_nla_channels(bAnimContext *UNUSED(ac), AnimData *adt, short mode)
static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
{
AnimChanRearrangeFp rearrange_func;
ListBase anim_data_visible = {NULL, NULL};
/* hack: invert mode so that functions will work in right order */
mode *= -1;
@ -923,8 +954,14 @@ static void rearrange_nla_channels(bAnimContext *UNUSED(ac), AnimData *adt, shor
//if (EXPANDED_DRVD(adt) == 0)
// return;
/* Filter visible data. */
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK);
/* perform rearranging on tracks list */
rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK);
rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible);
/* free temp data */
BLI_freelistN(&anim_data_visible);
}
/* Drivers Specific Stuff ------------------------------------------------- */
@ -932,10 +969,11 @@ static void rearrange_nla_channels(bAnimContext *UNUSED(ac), AnimData *adt, shor
/* Change the order drivers within AnimData block
* mode: REARRANGE_ANIMCHAN_*
*/
static void rearrange_driver_channels(bAnimContext *UNUSED(ac), AnimData *adt, short mode)
static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, short mode)
{
/* get rearranging function */
AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
ListBase anim_data_visible = {NULL, NULL};
if (rearrange_func == NULL)
return;
@ -944,8 +982,14 @@ static void rearrange_driver_channels(bAnimContext *UNUSED(ac), AnimData *adt, s
if (EXPANDED_DRVD(adt) == 0)
return;
/* Filter visible data. */
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE);
/* perform rearranging on drivers list (drivers are really just F-Curves) */
rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE);
rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible);
/* free temp data */
BLI_freelistN(&anim_data_visible);
}
/* Action Specific Stuff ------------------------------------------------- */
@ -1027,6 +1071,7 @@ static void join_groups_action_temp(bAction *act)
static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode)
{
bActionGroup tgrp;
ListBase anim_data_visible = {NULL, NULL};
bool do_channels;
/* get rearranging function */
@ -1038,21 +1083,35 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode
/* make sure we're only operating with groups (vs a mixture of groups+curves) */
split_groups_action_temp(act, &tgrp);
/* Filter visible data. */
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GROUP);
/* rearrange groups first
* - the group's channels will only get considered if nothing happened when rearranging the groups
* i.e. the rearrange function returned 0
*/
do_channels = rearrange_animchannel_islands(&act->groups, rearrange_func, mode, ANIMTYPE_GROUP) == 0;
do_channels = (rearrange_animchannel_islands(&act->groups, rearrange_func, mode, ANIMTYPE_GROUP,
&anim_data_visible) == 0);
/* free temp data */
BLI_freelistN(&anim_data_visible);
if (do_channels) {
bActionGroup *agrp;
/* Filter visible data. */
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE);
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
/* only consider F-Curves if they're visible (group expanded) */
if (EXPANDED_AGRP(ac, agrp)) {
rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE);
rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE,
&anim_data_visible);
}
}
/* free temp data */
BLI_freelistN(&anim_data_visible);
}
/* assemble lists into one list (and clear moved tags) */