[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [34750] trunk/blender/source/blender/ editors/animation/anim_channels_edit.c: Bugfix [#25831] Sorting channels broken

Joshua Leung aligorith at gmail.com
Thu Feb 10 06:15:08 CET 2011


Revision: 34750
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=34750
Author:   aligorith
Date:     2011-02-10 05:15:05 +0000 (Thu, 10 Feb 2011)
Log Message:
-----------
Bugfix [#25831] Sorting channels broken

Recoded animation channel sorting code. In particular, the old code
didn't handle "islands" of selected items well (i.e. a chain of
several connected items in a row), with some of these cases having
unpredictable results.

There were also some bugs in the way some of the rearranging methods
worked, allowing some invalid operations to be performed. Some of
these probably triggered errors such as some channels getting stuck,
and so on.

Modified Paths:
--------------
    trunk/blender/source/blender/editors/animation/anim_channels_edit.c

Modified: trunk/blender/source/blender/editors/animation/anim_channels_edit.c
===================================================================
--- trunk/blender/source/blender/editors/animation/anim_channels_edit.c	2011-02-10 04:48:49 UTC (rev 34749)
+++ trunk/blender/source/blender/editors/animation/anim_channels_edit.c	2011-02-10 05:15:05 UTC (rev 34750)
@@ -585,57 +585,46 @@
 	{0, NULL, 0, NULL, NULL}
 };
 
-/* Rearrange Utilities --------------------------------------------- */
+/* Reordering "Islands" Defines ----------------------------------- */
 
-/* checks if a channel should be considered for moving */
-static short rearrange_animchannel_is_ok (Link *channel, short type)
-{
-	if (type == ANIMTYPE_GROUP) {
-		bActionGroup *agrp= (bActionGroup *)channel;
-		
-		if (SEL_AGRP(agrp) && !(agrp->flag & AGRP_MOVED))
-			return 1;
-	}
-	else if (type == ANIMTYPE_FCURVE) {
-		FCurve *fcu= (FCurve *)channel;
-		
-		// FIXME: F-Curve visibility is difficult... needs special filtering tests these days...
-		if (SEL_FCU(fcu) && !(fcu->flag & FCURVE_TAGGED))
-			return 1;
-	}
-	else if (type == ANIMTYPE_NLATRACK) {
-		NlaTrack *nlt = (NlaTrack *)channel;
-		
-		if (SEL_NLT(nlt) && !(nlt->flag & NLASTRIP_FLAG_EDIT_TOUCHED))
-			return 1;
-	}
+/* Island definition - just a listbase container */
+typedef struct tReorderChannelIsland {
+	struct tReorderChannelIsland *next, *prev;
 	
-	return 0;
-}
+	ListBase channels; 	/* channels within this region with the same state */
+	int flag;			/* eReorderIslandFlag */
+} tReorderChannelIsland;
 
-/* checks if another channel can be placed after the given one */
-static short rearrange_animchannel_after_ok (Link *channel, short type)
+/* flags for channel reordering islands */
+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 */
+} eReorderIslandFlag;
+
+
+/* Rearrange Methods --------------------------------------------- */
+
+static short rearrange_island_ok (tReorderChannelIsland *island)
 {
-	if (type == ANIMTYPE_GROUP) {
-		bActionGroup *agrp= (bActionGroup *)channel;
-		
-		if (agrp->flag & AGRP_TEMP)
-			return 0;
-	}
+	/* island must not be untouchable */
+	if (island->flag & REORDER_ISLAND_UNTOUCHABLE)
+		return 0;
 	
-	return 1;
+	/* island should be selected to be moved */
+	return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED);
 }
 
-/* Rearrange Methods --------------------------------------------- */
+/* ............................. */
 
-static short rearrange_animchannel_top (ListBase *list, Link *channel, short type)
+static short rearrange_island_top (ListBase *list, tReorderChannelIsland *island)
 {
-	if (rearrange_animchannel_is_ok(channel, type)) {
-		/* take it out off the chain keep data */
-		BLI_remlink(list, channel);
+	if (rearrange_island_ok(island)) {
+		/* remove from current position */
+		BLI_remlink(list, island);
 		
 		/* make it first element */
-		BLI_insertlinkbefore(list, list->first, channel);
+		BLI_insertlinkbefore(list, list->first, island);
 		
 		return 1;
 	}
@@ -643,17 +632,18 @@
 	return 0;
 }
 
-static short rearrange_animchannel_up (ListBase *list, Link *channel, short type)
+static short rearrange_island_up (ListBase *list, tReorderChannelIsland *island)
 {
-	if (rearrange_animchannel_is_ok(channel, type)) {
-		Link *prev= channel->prev;
+	if (rearrange_island_ok(island)) {
+		/* moving up = moving before the previous island, otherwise we're in the same place */
+		tReorderChannelIsland *prev= island->prev;
 		
 		if (prev) {
-			/* take it out off the chain keep data */
-			BLI_remlink(list, channel);
+			/* remove from current position */
+			BLI_remlink(list, island);
 			
 			/* push it up */
-			BLI_insertlinkbefore(list, prev, channel);
+			BLI_insertlinkbefore(list, prev, island);
 			
 			return 1;
 		}
@@ -662,110 +652,200 @@
 	return 0;
 }
 
-static short rearrange_animchannel_down (ListBase *list, Link *channel, short type)
+static short rearrange_island_down (ListBase *list, tReorderChannelIsland *island)
 {
-	if (rearrange_animchannel_is_ok(channel, type)) {
-		Link *next = (channel->next) ? channel->next->next : NULL;
+	if (rearrange_island_ok(island)) {
+		/* moving down = moving after the next island, otherwise we're in the same place */
+		tReorderChannelIsland *next = island->next;
 		
 		if (next) {
-			/* take it out off the chain keep data */
-			BLI_remlink(list, channel);
-			
-			/* move it down */
-			BLI_insertlinkbefore(list, next, channel);
-			
-			return 1;
+			/* can only move past if next is not untouchable (i.e. nothing can go after it) */
+			if ((next->flag & REORDER_ISLAND_UNTOUCHABLE)==0) {
+				/* remove from current position */
+				BLI_remlink(list, island);
+				
+				/* push it down */
+				BLI_insertlinkafter(list, next, island);
+				
+				return 1;
+			}
 		}
-		else if (rearrange_animchannel_after_ok(list->last, type)) {
-			/* take it out off the chain keep data */
-			BLI_remlink(list, channel);
-			
-			/* add at end */
-			BLI_addtail(list, channel);
-			
-			return 1;
-		}
-		else {
-			/* take it out off the chain keep data */
-			BLI_remlink(list, channel);
-			
-			/* add just before end */
-			BLI_insertlinkbefore(list, list->last, channel);
-			
-			return 1;
-		}
+		/* else: no next channel, so we're at the bottom already, so can't move */
 	}
 	
 	return 0;
 }
 
-static short rearrange_animchannel_bottom (ListBase *list, Link *channel, short type)
+static short rearrange_island_bottom (ListBase *list, tReorderChannelIsland *island)
 {
-	if (rearrange_animchannel_is_ok(channel, type)) {
-		if (rearrange_animchannel_after_ok(list->last, type)) {
-			/* take it out off the chain keep data */
-			BLI_remlink(list, channel);
+	if (rearrange_island_ok(island)) {
+		tReorderChannelIsland *last = list->last;
+		
+		/* remove island from current position */
+		BLI_remlink(list, island);
+		
+		/* add before or after the last channel? */
+		if ((last->flag & REORDER_ISLAND_UNTOUCHABLE)==0) {
+			/* can add after it */
+			BLI_addtail(list, island);
+		}
+		else {
+			/* can at most go just before it, since last cannot be moved */
+			BLI_insertlinkbefore(list, last, island);
 			
-			/* add at end */
-			BLI_addtail(list, channel);
-			
-			return 1;
 		}
+		
+		return 1;
 	}
 	
 	return 0;
 }
 
-/* Generic Stuff ---------------------------------------------------------- */
+/* ............................. */
 
 /* typedef for channel rearranging function 
  * < list: list that channels belong to
- * < channel: channel to be moved
- * < type: type of channel (eAnim_ChannelType)
+ * < island: island to be moved
  * > return[0]: whether operation was a success
  */
-typedef short (*AnimChanRearrangeFp)(ListBase *list, Link *channel, short type);
+typedef short (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island);
 
 /* get rearranging function, given 'rearrange' mode */
 static AnimChanRearrangeFp rearrange_get_mode_func (short mode)
 {
 	switch (mode) {
 		case REARRANGE_ANIMCHAN_TOP:
-			return rearrange_animchannel_top;
+			return rearrange_island_top;
 		case REARRANGE_ANIMCHAN_UP:
-			return rearrange_animchannel_up;
+			return rearrange_island_up;
 		case REARRANGE_ANIMCHAN_DOWN:
-			return rearrange_animchannel_down;
+			return rearrange_island_down;
 		case REARRANGE_ANIMCHAN_BOTTOM:
-			return rearrange_animchannel_bottom;
+			return rearrange_island_bottom;
 		default:
 			return NULL;
 	}
 }
 
-/* ........ */
+/* Rearrange Islands Generics ------------------------------------- */
 
-/* These iteration helpers (ideally should be inlined, but probably not necessary) */
+/* add channel into list of islands */
+static void rearrange_animchannel_add_to_islands (ListBase *islands, ListBase *srcList, Link *channel, short type)
+{
+	tReorderChannelIsland *island = islands->last; 	/* always try to add to last island if possible */
+	short is_sel=0, is_untouchable=0;
+	
+	/* get flags - selected and untouchable from the channel */
+	switch (type) {
+		case ANIMTYPE_GROUP:
+		{
+			bActionGroup *agrp= (bActionGroup *)channel;
+			
+			is_sel= SEL_AGRP(agrp);
+			is_untouchable= (agrp->flag & AGRP_TEMP) != 0;
+		}
+			break;
+		case ANIMTYPE_FCURVE:
+		{
+			FCurve *fcu= (FCurve *)channel;
+			
+			is_sel= SEL_FCU(fcu);
+		}	
+			break;
+		case ANIMTYPE_NLATRACK:
+		{
+			NlaTrack *nlt= (NlaTrack *)channel;
+			
+			is_sel= SEL_NLT(nlt);
+		}
+			break;
+			
+		default:
+			printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
+			return;
+	}
+	
+	/* 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) */
+	{
+		/* create a new island now */
+		island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
+		BLI_addtail(islands, island);
+		
+		if (is_sel)
+			island->flag |= REORDER_ISLAND_SELECTED;
+		if (is_untouchable)
+			island->flag |= REORDER_ISLAND_UNTOUCHABLE;
+	}
 
-static Link *rearrange_iter_first (ListBase *list, short mode)
-{
-	return (mode > 0) ? list->first : list->last;
+	/* add channel to island - need to remove it from its existing list first though */
+	BLI_remlink(srcList, channel);
+	BLI_addtail(&island->channels, channel);
 }
 
-static Link *rearrange_iter_next (Link *item, short mode)
+/* flatten islands out into a single list again */
+static void rearrange_animchannel_flatten_islands (ListBase *islands, ListBase *srcList)
 {
-	return (mode > 0) ? item->next : item->prev;
+	tReorderChannelIsland *island, *isn=NULL;
+	
+	/* make sure srcList is empty now */
+	BLI_assert(srcList->first == NULL);
+	
+	/* go through merging islands */
+	for (island = islands->first; island; island = isn) {
+		isn = island->next;
+		
+		/* merge island channels back to main list, then delete the island */
+		BLI_movelisttolist(srcList, &island->channels);
+		BLI_freelinkN(islands, island);
+	}
 }
 
-/* ........ */
+/* ............................. */
 
-/* Clear 'tag' on all F-Curves */
-static void rearrange_clear_fcurve_tags (ListBase *list)

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list