Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/animation/anim_channels_edit.c
| Show All 30 Lines | |||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_listbase.h" | |||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_key_types.h" | #include "DNA_key_types.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_mask_types.h" | #include "DNA_mask_types.h" | ||||
| ▲ Show 20 Lines • Show All 601 Lines • ▼ Show 20 Lines | typedef struct tReorderChannelIsland { | ||||
| ListBase channels; /* channels within this region with the same state */ | ListBase channels; /* channels within this region with the same state */ | ||||
| int flag; /* eReorderIslandFlag */ | int flag; /* eReorderIslandFlag */ | ||||
| } tReorderChannelIsland; | } tReorderChannelIsland; | ||||
| /* flags for channel reordering islands */ | /* flags for channel reordering islands */ | ||||
| typedef enum eReorderIslandFlag { | typedef enum eReorderIslandFlag { | ||||
| REORDER_ISLAND_SELECTED = (1 << 0), /* island is selected */ | REORDER_ISLAND_SELECTED = (1 << 0), /* island is selected */ | ||||
| REORDER_ISLAND_UNTOUCHABLE = (1 << 1), /* island should be ignored */ | 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; | } eReorderIslandFlag; | ||||
| /* Rearrange Methods --------------------------------------------- */ | /* Rearrange Methods --------------------------------------------- */ | ||||
| static bool rearrange_island_ok(tReorderChannelIsland *island) | static bool rearrange_island_ok(tReorderChannelIsland *island) | ||||
| { | { | ||||
| /* island must not be untouchable */ | /* island must not be untouchable */ | ||||
| Show All 21 Lines | static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island) | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island) | static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island) | ||||
| { | { | ||||
| if (rearrange_island_ok(island)) { | if (rearrange_island_ok(island)) { | ||||
| /* moving up = moving before the previous island, otherwise we're in the same place */ | /* moving up = moving before the previous island, otherwise we're in the same place */ | ||||
| tReorderChannelIsland *prev = island->prev; | tReorderChannelIsland *prev = island->prev; | ||||
| /* Skip hidden islands! */ | |||||
| while (prev && prev->flag & REORDER_ISLAND_HIDDEN) { | |||||
| prev = prev->prev; | |||||
| } | |||||
| if (prev) { | if (prev) { | ||||
| /* remove from current position */ | /* remove from current position */ | ||||
| BLI_remlink(list, island); | BLI_remlink(list, island); | ||||
| /* push it up */ | /* push it up */ | ||||
| BLI_insertlinkbefore(list, prev, island); | BLI_insertlinkbefore(list, prev, island); | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island) | static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island) | ||||
| { | { | ||||
| if (rearrange_island_ok(island)) { | if (rearrange_island_ok(island)) { | ||||
| /* moving down = moving after the next island, otherwise we're in the same place */ | /* moving down = moving after the next island, otherwise we're in the same place */ | ||||
| tReorderChannelIsland *next = island->next; | tReorderChannelIsland *next = island->next; | ||||
| /* Skip hidden islands! */ | |||||
| while (next && next->flag & REORDER_ISLAND_HIDDEN) { | |||||
| next = next->next; | |||||
| } | |||||
| if (next) { | if (next) { | ||||
| /* can only move past if next is not untouchable (i.e. nothing can go after it) */ | /* can only move past if next is not untouchable (i.e. nothing can go after it) */ | ||||
| if ((next->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) { | if ((next->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) { | ||||
| /* remove from current position */ | /* remove from current position */ | ||||
| BLI_remlink(list, island); | BLI_remlink(list, island); | ||||
| /* push it down */ | /* push it down */ | ||||
| BLI_insertlinkafter(list, next, island); | BLI_insertlinkafter(list, next, island); | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | switch (mode) { | ||||
| default: | default: | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | } | ||||
| /* Rearrange Islands Generics ------------------------------------- */ | /* Rearrange Islands Generics ------------------------------------- */ | ||||
| /* add channel into list of islands */ | /* 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 */ | tReorderChannelIsland *island = islands->last; /* always try to add to last island if possible */ | ||||
| bool is_sel = false, is_untouchable = false; | bool is_sel = false, is_untouchable = false; | ||||
| /* get flags - selected and untouchable from the channel */ | /* get flags - selected and untouchable from the channel */ | ||||
| switch (type) { | switch (type) { | ||||
| case ANIMTYPE_GROUP: | case ANIMTYPE_GROUP: | ||||
| { | { | ||||
| Show All 18 Lines | case ANIMTYPE_NLATRACK: | ||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type); | printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type); | ||||
| return; | return; | ||||
| } | } | ||||
| /* do we need to add to a new island? */ | /* do we need to add to a new island? */ | ||||
| if ((island == NULL) || /* 1) no islands yet */ | if (/* 1) no islands yet */ | ||||
| ((island->flag & REORDER_ISLAND_SELECTED) == 0) || /* 2) unselected islands have single channels only - to allow up/down movement */ | (island == NULL) || | ||||
| (is_sel == 0)) /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */ | /* 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 */ | /* create a new island now */ | ||||
| island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland"); | island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland"); | ||||
| BLI_addtail(islands, island); | BLI_addtail(islands, island); | ||||
| if (is_sel) | if (is_sel) | ||||
| island->flag |= REORDER_ISLAND_SELECTED; | island->flag |= REORDER_ISLAND_SELECTED; | ||||
| if (is_untouchable) | if (is_untouchable) | ||||
| island->flag |= REORDER_ISLAND_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 */ | /* add channel to island - need to remove it from its existing list first though */ | ||||
| BLI_remlink(srcList, channel); | BLI_remlink(srcList, channel); | ||||
| BLI_addtail(&island->channels, channel); | BLI_addtail(&island->channels, channel); | ||||
| } | } | ||||
| /* flatten islands out into a single list again */ | /* flatten islands out into a single list again */ | ||||
| Show All 11 Lines | for (island = islands->first; island; island = isn) { | ||||
| /* merge island channels back to main list, then delete the island */ | /* merge island channels back to main list, then delete the island */ | ||||
| BLI_movelisttolist(srcList, &island->channels); | BLI_movelisttolist(srcList, &island->channels); | ||||
| BLI_freelinkN(islands, island); | BLI_freelinkN(islands, island); | ||||
| } | } | ||||
| } | } | ||||
| /* ............................. */ | /* ............................. */ | ||||
| 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 */ | /* 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}; | ListBase islands = {NULL, NULL}; | ||||
| Link *channel, *chanNext = NULL; | Link *channel, *chanNext = NULL; | ||||
| short done = FALSE; | short done = FALSE; | ||||
| /* don't waste effort on an empty list */ | /* don't waste effort on an empty list */ | ||||
| if (BLI_listbase_is_empty(list)) | if (BLI_listbase_is_empty(list)) | ||||
| return 0; | return 0; | ||||
| /* group channels into islands */ | /* group channels into islands */ | ||||
| for (channel = list->first; channel; channel = chanNext) { | 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; | 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 | /* perform moving of selected islands now, but only if there is more than one of 'em so that something will happen | ||||
| * - scanning of the list is performed in the opposite direction to the direction we're moving things, so that we | * - scanning of the list is performed in the opposite direction to the direction we're moving things, so that we | ||||
| * shouldn't need to encounter items we've moved already | * shouldn't need to encounter items we've moved already | ||||
| */ | */ | ||||
| if (islands.first != islands.last) { | if (islands.first != islands.last) { | ||||
| tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first; | tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first; | ||||
| Show All 18 Lines | |||||
| } | } | ||||
| /* NLA Specific Stuff ----------------------------------------------------- */ | /* NLA Specific Stuff ----------------------------------------------------- */ | ||||
| /* Change the order NLA Tracks within NLA Stack | /* Change the order NLA Tracks within NLA Stack | ||||
| * ! NLA tracks are displayed in opposite order, so directions need care | * ! NLA tracks are displayed in opposite order, so directions need care | ||||
| * mode: REARRANGE_ANIMCHAN_* | * 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; | AnimChanRearrangeFp rearrange_func; | ||||
| ListBase anim_data_visible = {NULL, NULL}; | |||||
| /* hack: invert mode so that functions will work in right order */ | /* hack: invert mode so that functions will work in right order */ | ||||
| mode *= -1; | mode *= -1; | ||||
| /* get rearranging function */ | /* get rearranging function */ | ||||
| rearrange_func = rearrange_get_mode_func(mode); | rearrange_func = rearrange_get_mode_func(mode); | ||||
| if (rearrange_func == NULL) | if (rearrange_func == NULL) | ||||
| return; | return; | ||||
| /* only consider NLA data if it's accessible */ | /* only consider NLA data if it's accessible */ | ||||
| //if (EXPANDED_DRVD(adt) == 0) | //if (EXPANDED_DRVD(adt) == 0) | ||||
| // return; | // return; | ||||
| /* Filter visible data. */ | |||||
| rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK); | |||||
| /* perform rearranging on tracks list */ | /* 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 ------------------------------------------------- */ | /* Drivers Specific Stuff ------------------------------------------------- */ | ||||
| /* Change the order drivers within AnimData block | /* Change the order drivers within AnimData block | ||||
| * mode: REARRANGE_ANIMCHAN_* | * 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 */ | /* get rearranging function */ | ||||
| AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); | AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); | ||||
| ListBase anim_data_visible = {NULL, NULL}; | |||||
| if (rearrange_func == NULL) | if (rearrange_func == NULL) | ||||
| return; | return; | ||||
| /* only consider drivers if they're accessible */ | /* only consider drivers if they're accessible */ | ||||
| if (EXPANDED_DRVD(adt) == 0) | if (EXPANDED_DRVD(adt) == 0) | ||||
| return; | 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) */ | /* 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 ------------------------------------------------- */ | /* Action Specific Stuff ------------------------------------------------- */ | ||||
| /* make sure all action-channels belong to a group (and clear action's list) */ | /* make sure all action-channels belong to a group (and clear action's list) */ | ||||
| static void split_groups_action_temp(bAction *act, bActionGroup *tgrp) | static void split_groups_action_temp(bAction *act, bActionGroup *tgrp) | ||||
| { | { | ||||
| bActionGroup *agrp; | bActionGroup *agrp; | ||||
| ▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Change the order of anim-channels within action | /* Change the order of anim-channels within action | ||||
| * mode: REARRANGE_ANIMCHAN_* | * mode: REARRANGE_ANIMCHAN_* | ||||
| */ | */ | ||||
| static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode) | static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode) | ||||
| { | { | ||||
| bActionGroup tgrp; | bActionGroup tgrp; | ||||
| ListBase anim_data_visible = {NULL, NULL}; | |||||
| bool do_channels; | bool do_channels; | ||||
| /* get rearranging function */ | /* get rearranging function */ | ||||
| AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); | AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); | ||||
| if (rearrange_func == NULL) | if (rearrange_func == NULL) | ||||
| return; | return; | ||||
| /* make sure we're only operating with groups (vs a mixture of groups+curves) */ | /* make sure we're only operating with groups (vs a mixture of groups+curves) */ | ||||
| split_groups_action_temp(act, &tgrp); | split_groups_action_temp(act, &tgrp); | ||||
| /* Filter visible data. */ | |||||
| rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GROUP); | |||||
| /* rearrange groups first | /* rearrange groups first | ||||
| * - the group's channels will only get considered if nothing happened when rearranging the groups | * - the group's channels will only get considered if nothing happened when rearranging the groups | ||||
| * i.e. the rearrange function returned 0 | * 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) { | if (do_channels) { | ||||
| bActionGroup *agrp; | bActionGroup *agrp; | ||||
| /* Filter visible data. */ | |||||
| rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE); | |||||
| for (agrp = act->groups.first; agrp; agrp = agrp->next) { | for (agrp = act->groups.first; agrp; agrp = agrp->next) { | ||||
| /* only consider F-Curves if they're visible (group expanded) */ | /* only consider F-Curves if they're visible (group expanded) */ | ||||
| if (EXPANDED_AGRP(ac, agrp)) { | 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) */ | /* assemble lists into one list (and clear moved tags) */ | ||||
| join_groups_action_temp(act); | join_groups_action_temp(act); | ||||
| } | } | ||||
| /* ------------------- */ | /* ------------------- */ | ||||
| ▲ Show 20 Lines • Show All 1,759 Lines • Show Last 20 Lines | |||||