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:
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
|
@ -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) */
|
||||
|
|
Loading…
Reference in New Issue