- removed DNA_brush_types.h from DNA_scene_types.h (and some other similar cases) - removed DNA_wave_types.h (never used) - removed Main.wave
		
			
				
	
	
		
			2037 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2037 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * $Id$
 | |
|  *
 | |
|  * ***** BEGIN GPL LICENSE BLOCK *****
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
|  *
 | |
|  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Contributor(s): Joshua Leung
 | |
|  *
 | |
|  * ***** END GPL LICENSE BLOCK *****
 | |
|  */
 | |
| 
 | |
| #include "MEM_guardedalloc.h"
 | |
| 
 | |
| #include "BLI_blenlib.h"
 | |
| 
 | |
| #include "DNA_anim_types.h"
 | |
| #include "DNA_object_types.h"
 | |
| #include "DNA_scene_types.h"
 | |
| #include "DNA_key_types.h"
 | |
| #include "DNA_gpencil_types.h"
 | |
| 
 | |
| #include "RNA_access.h"
 | |
| #include "RNA_define.h"
 | |
| 
 | |
| #include "BKE_action.h"
 | |
| #include "BKE_fcurve.h"
 | |
| #include "BKE_context.h"
 | |
| #include "BKE_global.h"
 | |
| 
 | |
| #include "UI_view2d.h"
 | |
| 
 | |
| #include "ED_anim_api.h"
 | |
| #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
 | |
| #include "ED_screen.h"
 | |
| 
 | |
| #include "WM_api.h"
 | |
| #include "WM_types.h"
 | |
| 
 | |
| /* ************************************************************************** */
 | |
| /* CHANNELS API - Exposed API */
 | |
| 
 | |
| /* -------------------------- Selection ------------------------------------- */
 | |
| 
 | |
| /* Set the given animation-channel as the active one for the active context */
 | |
| // TODO: extend for animdata types...
 | |
| void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
 | |
| {
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	
 | |
| 	/* try to build list of filtered items */
 | |
| 	ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
 | |
| 	if (anim_data.first == NULL)
 | |
| 		return;
 | |
| 		
 | |
| 	/* only clear the 'active' flag for the channels of the same type */
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		/* skip if types don't match */
 | |
| 		if (channel_type != ale->type)
 | |
| 			continue;
 | |
| 		
 | |
| 		/* flag to set depends on type */
 | |
| 		switch (ale->type) {
 | |
| 			case ANIMTYPE_GROUP:
 | |
| 			{
 | |
| 				bActionGroup *agrp= (bActionGroup *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE);
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_FCURVE:
 | |
| 			{
 | |
| 				FCurve *fcu= (FCurve *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_NLATRACK:
 | |
| 			{
 | |
| 				NlaTrack *nlt= (NlaTrack *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
 | |
| 			}
 | |
| 				break;
 | |
| 			
 | |
| 			case ANIMTYPE_FILLACTD: /* Action Expander */
 | |
| 			case ANIMTYPE_DSMAT:	/* Datablock AnimData Expanders */
 | |
| 			case ANIMTYPE_DSLAM:
 | |
| 			case ANIMTYPE_DSCAM:
 | |
| 			case ANIMTYPE_DSCUR:
 | |
| 			case ANIMTYPE_DSSKEY:
 | |
| 			case ANIMTYPE_DSWOR:
 | |
| 			case ANIMTYPE_DSPART:
 | |
| 			case ANIMTYPE_DSMBALL:
 | |
| 			case ANIMTYPE_DSARM:
 | |
| 			case ANIMTYPE_DSMESH:
 | |
| 			{
 | |
| 				/* need to verify that this data is valid for now */
 | |
| 				if (ale->adt) {
 | |
| 					ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
 | |
| 				}
 | |
| 			}
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* set active flag */
 | |
| 	if (channel_data) {
 | |
| 		switch (channel_type) {
 | |
| 			case ANIMTYPE_GROUP:
 | |
| 			{
 | |
| 				bActionGroup *agrp= (bActionGroup *)channel_data;
 | |
| 				agrp->flag |= AGRP_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_FCURVE:
 | |
| 			{
 | |
| 				FCurve *fcu= (FCurve *)channel_data;
 | |
| 				fcu->flag |= FCURVE_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_NLATRACK:
 | |
| 			{
 | |
| 				NlaTrack *nlt= (NlaTrack *)channel_data;
 | |
| 				nlt->flag |= NLATRACK_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 				
 | |
| 			case ANIMTYPE_FILLACTD: /* Action Expander */
 | |
| 			case ANIMTYPE_DSMAT:	/* Datablock AnimData Expanders */
 | |
| 			case ANIMTYPE_DSLAM:
 | |
| 			case ANIMTYPE_DSCAM:
 | |
| 			case ANIMTYPE_DSCUR:
 | |
| 			case ANIMTYPE_DSSKEY:
 | |
| 			case ANIMTYPE_DSWOR:
 | |
| 			case ANIMTYPE_DSPART:
 | |
| 			case ANIMTYPE_DSMBALL:
 | |
| 			case ANIMTYPE_DSARM:
 | |
| 			case ANIMTYPE_DSMESH:
 | |
| 			{
 | |
| 				/* need to verify that this data is valid for now */
 | |
| 				if (ale->adt)
 | |
| 					ale->adt->flag |= ADT_UI_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* clean up */
 | |
| 	BLI_freelistN(&anim_data);
 | |
| }
 | |
| 
 | |
| /* Deselect all animation channels 
 | |
|  *	- data: pointer to datatype, as contained in bAnimContext
 | |
|  *	- datatype: the type of data that 'data' represents (eAnimCont_Types)
 | |
|  *	- test: check if deselecting instead of selecting
 | |
|  *	- sel: eAnimChannels_SetFlag;
 | |
|  */
 | |
| void ANIM_deselect_anim_channels (bAnimContext *ac, void *data, short datatype, short test, short sel)
 | |
| {
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	
 | |
| 	/* filter data */
 | |
| 	filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS;
 | |
| 	ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
 | |
| 	
 | |
| 	/* See if we should be selecting or deselecting */
 | |
| 	if (test) {
 | |
| 		for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 			if (sel == 0) 
 | |
| 				break;
 | |
| 			
 | |
| 			switch (ale->type) {
 | |
| 				case ANIMTYPE_SCENE:
 | |
| 					if (ale->flag & SCE_DS_SELECTED)
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 					break;
 | |
| 				case ANIMTYPE_OBJECT:
 | |
| 				#if 0	/* for now, do not take object selection into account, since it gets too annoying */
 | |
| 					if (ale->flag & SELECT)
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 				#endif
 | |
| 					break;
 | |
| 				case ANIMTYPE_GROUP:
 | |
| 					if (ale->flag & AGRP_SELECTED)
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 					break;
 | |
| 				case ANIMTYPE_FCURVE:
 | |
| 					if (ale->flag & FCURVE_SELECTED)
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 					break;
 | |
| 				case ANIMTYPE_SHAPEKEY:
 | |
| 					if (ale->flag & KEYBLOCK_SEL)
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 					break;
 | |
| 				case ANIMTYPE_NLATRACK:
 | |
| 					if (ale->flag & NLATRACK_SELECTED)
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 					break;
 | |
| 					
 | |
| 				case ANIMTYPE_FILLACTD: /* Action Expander */
 | |
| 				case ANIMTYPE_DSMAT:	/* Datablock AnimData Expanders */
 | |
| 				case ANIMTYPE_DSLAM:
 | |
| 				case ANIMTYPE_DSCAM:
 | |
| 				case ANIMTYPE_DSCUR:
 | |
| 				case ANIMTYPE_DSSKEY:
 | |
| 				case ANIMTYPE_DSWOR:
 | |
| 				case ANIMTYPE_DSPART:
 | |
| 				case ANIMTYPE_DSMBALL:
 | |
| 				case ANIMTYPE_DSARM:
 | |
| 				case ANIMTYPE_DSMESH:
 | |
| 				case ANIMTYPE_DSNTREE:
 | |
| 				case ANIMTYPE_DSTEX:
 | |
| 				{
 | |
| 					if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
 | |
| 						sel= ACHANNEL_SETFLAG_CLEAR;
 | |
| 				}
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 		
 | |
| 	/* Now set the flags */
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		switch (ale->type) {
 | |
| 			case ANIMTYPE_SCENE:
 | |
| 			{
 | |
| 				Scene *scene= (Scene *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
 | |
| 				
 | |
| 				if (scene->adt) {
 | |
| 					ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED);
 | |
| 				}
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_OBJECT:
 | |
| 			#if 0	/* for now, do not take object selection into account, since it gets too annoying */
 | |
| 			{
 | |
| 				Base *base= (Base *)ale->data;
 | |
| 				Object *ob= base->object;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(base, sel, SELECT);
 | |
| 				ACHANNEL_SET_FLAG(ob, sel, SELECT);
 | |
| 				
 | |
| 				if (ob->adt) {
 | |
| 					ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED);
 | |
| 				}
 | |
| 			}
 | |
| 			#endif
 | |
| 				break;
 | |
| 			case ANIMTYPE_GROUP:
 | |
| 			{
 | |
| 				bActionGroup *agrp= (bActionGroup *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
 | |
| 				agrp->flag &= ~AGRP_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_FCURVE:
 | |
| 			{
 | |
| 				FCurve *fcu= (FCurve *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
 | |
| 				fcu->flag &= ~FCURVE_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_SHAPEKEY:
 | |
| 			{
 | |
| 				KeyBlock *kb= (KeyBlock *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
 | |
| 			}
 | |
| 				break;
 | |
| 			case ANIMTYPE_NLATRACK:
 | |
| 			{
 | |
| 				NlaTrack *nlt= (NlaTrack *)ale->data;
 | |
| 				
 | |
| 				ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED);
 | |
| 				nlt->flag &= ~NLATRACK_ACTIVE;
 | |
| 			}
 | |
| 				break;
 | |
| 				
 | |
| 			case ANIMTYPE_FILLACTD: /* Action Expander */
 | |
| 			case ANIMTYPE_DSMAT:	/* Datablock AnimData Expanders */
 | |
| 			case ANIMTYPE_DSLAM:
 | |
| 			case ANIMTYPE_DSCAM:
 | |
| 			case ANIMTYPE_DSCUR:
 | |
| 			case ANIMTYPE_DSSKEY:
 | |
| 			case ANIMTYPE_DSWOR:
 | |
| 			case ANIMTYPE_DSPART:
 | |
| 			case ANIMTYPE_DSMBALL:
 | |
| 			case ANIMTYPE_DSARM:
 | |
| 			case ANIMTYPE_DSMESH:
 | |
| 			case ANIMTYPE_DSNTREE:
 | |
| 			case ANIMTYPE_DSTEX:
 | |
| 			{
 | |
| 				/* need to verify that this data is valid for now */
 | |
| 				if (ale->adt) {
 | |
| 					ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
 | |
| 					ale->adt->flag &= ~ADT_UI_ACTIVE;
 | |
| 				}
 | |
| 			}
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* Cleanup */
 | |
| 	BLI_freelistN(&anim_data);
 | |
| }
 | |
| 
 | |
| /* ---------------------------- Graph Editor ------------------------------------- */
 | |
| 
 | |
| /* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting 
 | |
|  *	- anim_data: list of the all the anim channels that can be chosen
 | |
|  *		-> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
 | |
|  *	 	  then the channels under closed expanders get ignored...
 | |
|  *	- ale_setting: the anim channel (not in the anim_data list directly, though occuring there)
 | |
|  *		with the new state of the setting that we want flushed up/down the hierarchy 
 | |
|  *	- setting: type of setting to set
 | |
|  *	- on: whether the visibility setting has been enabled or disabled 
 | |
|  */
 | |
| void ANIM_flush_setting_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on)
 | |
| {
 | |
| 	bAnimListElem *ale, *match=NULL;
 | |
| 	int prevLevel=0, matchLevel=0;
 | |
| 	
 | |
| 	/* sanity check */
 | |
| 	if (ELEM(NULL, anim_data, anim_data->first))
 | |
| 		return;
 | |
| 	
 | |
| 	/* find the channel that got changed */
 | |
| 	for (ale= anim_data->first; ale; ale= ale->next) {
 | |
| 		/* compare data, and type as main way of identifying the channel */
 | |
| 		if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
 | |
| 			/* we also have to check the ID, this is assigned to, since a block may have multiple users */
 | |
| 			// TODO: is the owner-data more revealing?
 | |
| 			if (ale->id == ale_setting->id) {
 | |
| 				match= ale;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if (match == NULL) {
 | |
| 		printf("ERROR: no channel matching the one changed was found \n");
 | |
| 		return;
 | |
| 	}
 | |
| 	else {
 | |
| 		bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting);
 | |
| 		
 | |
| 		if (acf == NULL) {
 | |
| 			printf("ERROR: no channel info for the changed channel \n");
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		/* get the level of the channel that was affected
 | |
| 		 * 	 - we define the level as simply being the offset for the start of the channel
 | |
| 		 */
 | |
| 		matchLevel= (acf->get_offset)? acf->get_offset(ac, ale_setting) : 0;
 | |
| 		prevLevel= matchLevel;
 | |
| 	}
 | |
| 	
 | |
| 	/* flush up? 
 | |
| 	 *
 | |
| 	 * For Visibility:
 | |
| 	 *	- only flush up if the current state is now enabled (positive 'on' state is default) 
 | |
| 	 *	  (otherwise, it's too much work to force the parents to be inactive too)
 | |
| 	 *
 | |
| 	 * For everything else:
 | |
| 	 *	- only flush up if the current state is now disabled (negative 'off' state is default)
 | |
| 	 *	  (otherwise, it's too much work to force the parents to be active too)
 | |
| 	 */
 | |
| 	if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) ||
 | |
| 		 ((setting != ACHANNEL_SETTING_VISIBLE) && on==0) )
 | |
| 	{
 | |
| 		/* go backwards in the list, until the highest-ranking element (by indention has been covered) */
 | |
| 		for (ale= match->prev; ale; ale= ale->prev) {
 | |
| 			bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
 | |
| 			int level;
 | |
| 			
 | |
| 			/* if no channel info was found, skip, since this type might not have any useful info */
 | |
| 			if (acf == NULL)
 | |
| 				continue;
 | |
| 			
 | |
| 			/* get the level of the current channel traversed 
 | |
| 			 * 	 - we define the level as simply being the offset for the start of the channel
 | |
| 			 */
 | |
| 			level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
 | |
| 			
 | |
| 			/* if the level is 'less than' (i.e. more important) the level we're matching
 | |
| 			 * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, 
 | |
| 			 * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel
 | |
| 			 * get updated below once the first 1st group is found)...
 | |
| 			 */
 | |
| 			if (level < prevLevel) {
 | |
| 				/* flush the new status... */
 | |
| 				ANIM_channel_setting_set(ac, ale, setting, on);
 | |
| 				
 | |
| 				/* store this level as the 'old' level now */
 | |
| 				prevLevel= level;
 | |
| 			}	
 | |
| 			/* if the level is 'greater than' (i.e. less important) than the previous level... */
 | |
| 			else if (level > prevLevel) {
 | |
| 				/* if previous level was a base-level (i.e. 0 offset / root of one hierarchy),
 | |
| 				 * stop here
 | |
| 				 */
 | |
| 				if (prevLevel == 0)
 | |
| 					break;
 | |
| 				/* otherwise, this level weaves into another sibling hierarchy to the previous one just
 | |
| 				 * finished, so skip until we get to the parent of this level 
 | |
| 				 */
 | |
| 				else
 | |
| 					continue;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* flush down (always) */
 | |
| 	{
 | |
| 		/* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
 | |
| 		for (ale= match->next; ale; ale= ale->next) {
 | |
| 			bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
 | |
| 			int level;
 | |
| 			
 | |
| 			/* if no channel info was found, skip, since this type might not have any useful info */
 | |
| 			if (acf == NULL)
 | |
| 				continue;
 | |
| 			
 | |
| 			/* get the level of the current channel traversed 
 | |
| 			 * 	 - we define the level as simply being the offset for the start of the channel
 | |
| 			 */
 | |
| 			level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
 | |
| 			
 | |
| 			/* if the level is 'greater than' (i.e. less important) the channel that was changed, 
 | |
| 			 * flush the new status...
 | |
| 			 */
 | |
| 			if (level > matchLevel)
 | |
| 				ANIM_channel_setting_set(ac, ale, setting, on);
 | |
| 			/* however, if the level is 'less than or equal to' the channel that was changed,
 | |
| 			 * (i.e. the current channel is as important if not more important than the changed channel)
 | |
| 			 * then we should stop, since we've found the last one of the children we should flush
 | |
| 			 */
 | |
| 			else
 | |
| 				break;
 | |
| 			
 | |
| 			/* store this level as the 'old' level now */
 | |
| 			prevLevel= level;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* -------------------------- F-Curves ------------------------------------- */
 | |
| 
 | |
| /* Delete the given F-Curve from its AnimData block */
 | |
| void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *fcu)
 | |
| {
 | |
| 	/* - if no AnimData, we've got nowhere to remove the F-Curve from 
 | |
| 	 *	(this doesn't guarantee that the F-Curve is in there, but at least we tried
 | |
| 	 * - if no F-Curve, there is nothing to remove
 | |
| 	 */
 | |
| 	if (ELEM(NULL, adt, fcu))
 | |
| 		return;
 | |
| 		
 | |
| 	/* remove from whatever list it came from
 | |
| 	 *	- Action Group
 | |
| 	 *	- Action
 | |
| 	 *	- Drivers
 | |
| 	 *	- TODO... some others?
 | |
| 	 */
 | |
| 	if (fcu->grp)
 | |
| 		action_groups_remove_channel(adt->action, fcu);
 | |
| 	else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS))
 | |
| 		BLI_remlink(&adt->drivers, fcu);
 | |
| 	else if (adt->action)
 | |
| 		BLI_remlink(&adt->action->curves, fcu);
 | |
| 		
 | |
| 	/* free the F-Curve itself */
 | |
| 	free_fcurve(fcu);
 | |
| }
 | |
| 
 | |
| /* ************************************************************************** */
 | |
| /* OPERATORS */
 | |
| 
 | |
| /* ****************** Operator Utilities ********************************** */
 | |
| 
 | |
| /* poll callback for being in an Animation Editor channels list region */
 | |
| int animedit_poll_channels_active (bContext *C)
 | |
| {
 | |
| 	ScrArea *sa= CTX_wm_area(C);
 | |
| 	
 | |
| 	/* channels region test */
 | |
| 	// TODO: could enhance with actually testing if channels region?
 | |
| 	if (ELEM(NULL, sa, CTX_wm_region(C)))
 | |
| 		return 0;
 | |
| 	/* animation editor test */
 | |
| 	if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
 | |
| 		return 0;
 | |
| 		
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
 | |
| int animedit_poll_channels_nla_tweakmode_off (bContext *C)
 | |
| {
 | |
| 	ScrArea *sa= CTX_wm_area(C);
 | |
| 	Scene *scene = CTX_data_scene(C);
 | |
| 	
 | |
| 	/* channels region test */
 | |
| 	// TODO: could enhance with actually testing if channels region?
 | |
| 	if (ELEM(NULL, sa, CTX_wm_region(C)))
 | |
| 		return 0;
 | |
| 	/* animation editor test */
 | |
| 	if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
 | |
| 		return 0;
 | |
| 	
 | |
| 	/* NLA TweakMode test */	
 | |
| 	if (sa->spacetype == SPACE_NLA) {
 | |
| 		if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
 | |
| 			return 0;
 | |
| 	}
 | |
| 		
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| /* ****************** Rearrange Channels Operator ******************* */
 | |
| /* This operator only works for Action Editor mode for now, as having it elsewhere makes things difficult */
 | |
| 
 | |
| #if 0 // XXX old animation system - needs to be updated for new system...
 | |
| 
 | |
| /* constants for channel rearranging */
 | |
| /* WARNING: don't change exising ones without modifying rearrange func accordingly */
 | |
| enum {
 | |
| 	REARRANGE_ACTCHAN_TOP= -2,
 | |
| 	REARRANGE_ACTCHAN_UP= -1,
 | |
| 	REARRANGE_ACTCHAN_DOWN= 1,
 | |
| 	REARRANGE_ACTCHAN_BOTTOM= 2
 | |
| };
 | |
| 
 | |
| /* make sure all action-channels belong to a group (and clear action's list) */
 | |
| static void split_groups_action_temp (bAction *act, bActionGroup *tgrp)
 | |
| {
 | |
| 	bActionChannel *achan;
 | |
| 	bActionGroup *agrp;
 | |
| 	
 | |
| 	/* Separate action-channels into lists per group */
 | |
| 	for (agrp= act->groups.first; agrp; agrp= agrp->next) {
 | |
| 		if (agrp->channels.first) {
 | |
| 			achan= agrp->channels.last;
 | |
| 			act->chanbase.first= achan->next;
 | |
| 			
 | |
| 			achan= agrp->channels.first;
 | |
| 			achan->prev= NULL;
 | |
| 			
 | |
| 			achan= agrp->channels.last;
 | |
| 			achan->next= NULL;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* Initialise memory for temp-group */
 | |
| 	memset(tgrp, 0, sizeof(bActionGroup));
 | |
| 	tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP);
 | |
| 	strcpy(tgrp->name, "#TempGroup");
 | |
| 		
 | |
| 	/* Move any action-channels not already moved, to the temp group */
 | |
| 	if (act->chanbase.first) {
 | |
| 		/* start of list */
 | |
| 		achan= act->chanbase.first;
 | |
| 		achan->prev= NULL;
 | |
| 		tgrp->channels.first= achan;
 | |
| 		act->chanbase.first= NULL;
 | |
| 		
 | |
| 		/* end of list */
 | |
| 		achan= act->chanbase.last;
 | |
| 		achan->next= NULL;
 | |
| 		tgrp->channels.last= achan;
 | |
| 		act->chanbase.last= NULL;
 | |
| 	}
 | |
| 	
 | |
| 	/* Add temp-group to list */
 | |
| 	BLI_addtail(&act->groups, tgrp);
 | |
| }
 | |
| 
 | |
| /* link lists of channels that groups have */
 | |
| static void join_groups_action_temp (bAction *act)
 | |
| {
 | |
| 	bActionGroup *agrp;
 | |
| 	bActionChannel *achan;
 | |
| 	
 | |
| 	for (agrp= act->groups.first; agrp; agrp= agrp->next) {
 | |
| 		ListBase tempGroup;
 | |
| 		
 | |
| 		/* add list of channels to action's channels */
 | |
| 		tempGroup= agrp->channels;
 | |
| 		addlisttolist(&act->chanbase, &agrp->channels);
 | |
| 		agrp->channels= tempGroup;
 | |
| 		
 | |
| 		/* clear moved flag */
 | |
| 		agrp->flag &= ~AGRP_MOVED;
 | |
| 		
 | |
| 		/* if temp-group... remove from list (but don't free as it's on the stack!) */
 | |
| 		if (agrp->flag & AGRP_TEMP) {
 | |
| 			BLI_remlink(&act->groups, agrp);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* clear "moved" flag from all achans */
 | |
| 	for (achan= act->chanbase.first; achan; achan= achan->next) 
 | |
| 		achan->flag &= ~ACHAN_MOVED;
 | |
| }
 | |
| 
 | |
| 
 | |
| static short rearrange_actchannel_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_ACHAN) {
 | |
| 		bActionChannel *achan= (bActionChannel *)channel;
 | |
| 		
 | |
| 		if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED))
 | |
| 			return 1;
 | |
| 	}
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static short rearrange_actchannel_after_ok (Link *channel, short type)
 | |
| {
 | |
| 	if (type == ANIMTYPE_GROUP) {
 | |
| 		bActionGroup *agrp= (bActionGroup *)channel;
 | |
| 		
 | |
| 		if (agrp->flag & AGRP_TEMP)
 | |
| 			return 0;
 | |
| 	}
 | |
| 	
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static short rearrange_actchannel_top (ListBase *list, Link *channel, short type)
 | |
| {
 | |
| 	if (rearrange_actchannel_is_ok(channel, type)) {
 | |
| 		/* take it out off the chain keep data */
 | |
| 		BLI_remlink(list, channel);
 | |
| 		
 | |
| 		/* make it first element */
 | |
| 		BLI_insertlinkbefore(list, list->first, channel);
 | |
| 		
 | |
| 		return 1;
 | |
| 	}
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static short rearrange_actchannel_up (ListBase *list, Link *channel, short type)
 | |
| {
 | |
| 	if (rearrange_actchannel_is_ok(channel, type)) {
 | |
| 		Link *prev= channel->prev;
 | |
| 		
 | |
| 		if (prev) {
 | |
| 			/* take it out off the chain keep data */
 | |
| 			BLI_remlink(list, channel);
 | |
| 			
 | |
| 			/* push it up */
 | |
| 			BLI_insertlinkbefore(list, prev, channel);
 | |
| 			
 | |
| 			return 1;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static short rearrange_actchannel_down (ListBase *list, Link *channel, short type)
 | |
| {
 | |
| 	if (rearrange_actchannel_is_ok(channel, type)) {
 | |
| 		Link *next = (channel->next) ? channel->next->next : NULL;
 | |
| 		
 | |
| 		if (next) {
 | |
| 			/* take it out off the chain keep data */
 | |
| 			BLI_remlink(list, channel);
 | |
| 			
 | |
| 			/* move it down */
 | |
| 			BLI_insertlinkbefore(list, next, channel);
 | |
| 			
 | |
| 			return 1;
 | |
| 		}
 | |
| 		else if (rearrange_actchannel_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;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static short rearrange_actchannel_bottom (ListBase *list, Link *channel, short type)
 | |
| {
 | |
| 	if (rearrange_actchannel_is_ok(channel, type)) {
 | |
| 		if (rearrange_actchannel_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;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Change the order of action-channels 
 | |
|  *	mode: REARRANGE_ACTCHAN_*  
 | |
|  */
 | |
| static void rearrange_action_channels (bAnimContext *ac, short mode)
 | |
| {
 | |
| 	bAction *act;
 | |
| 	bActionChannel *achan, *chan;
 | |
| 	bActionGroup *agrp, *grp;
 | |
| 	bActionGroup tgrp;
 | |
| 	
 | |
| 	short (*rearrange_func)(ListBase *, Link *, short);
 | |
| 	short do_channels = 1;
 | |
| 	
 | |
| 	/* Get the active action, exit if none are selected */
 | |
| 	act= (bAction *)ac->data;
 | |
| 	
 | |
| 	/* exit if invalid mode */
 | |
| 	switch (mode) {
 | |
| 		case REARRANGE_ACTCHAN_TOP:
 | |
| 			rearrange_func= rearrange_actchannel_top;
 | |
| 			break;
 | |
| 		case REARRANGE_ACTCHAN_UP:
 | |
| 			rearrange_func= rearrange_actchannel_up;
 | |
| 			break;
 | |
| 		case REARRANGE_ACTCHAN_DOWN:
 | |
| 			rearrange_func= rearrange_actchannel_down;
 | |
| 			break;
 | |
| 		case REARRANGE_ACTCHAN_BOTTOM:
 | |
| 			rearrange_func= rearrange_actchannel_bottom;
 | |
| 			break;
 | |
| 		default:
 | |
| 			return;
 | |
| 	}
 | |
| 	
 | |
| 	/* make sure we're only operating with groups */
 | |
| 	split_groups_action_temp(act, &tgrp);
 | |
| 	
 | |
| 	/* rearrange groups first (and then, only consider channels if the groups weren't moved) */
 | |
| 	#define GET_FIRST(list) ((mode > 0) ? (list.first) : (list.last))
 | |
| 	#define GET_NEXT(item) ((mode > 0) ? (item->next) : (item->prev))
 | |
| 	
 | |
| 	for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
 | |
| 		/* Get next group to consider */
 | |
| 		grp= GET_NEXT(agrp);
 | |
| 		
 | |
| 		/* try to do group first */
 | |
| 		if (rearrange_func(&act->groups, (Link *)agrp, ANIMTYPE_GROUP)) {
 | |
| 			do_channels= 0;
 | |
| 			agrp->flag |= AGRP_MOVED;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	if (do_channels) {
 | |
| 		for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
 | |
| 			/* Get next group to consider */
 | |
| 			grp= GET_NEXT(agrp);
 | |
| 			
 | |
| 			/* only consider action-channels if they're visible (group expanded) */
 | |
| 			if (EXPANDED_AGRP(agrp)) {
 | |
| 				for (achan= GET_FIRST(agrp->channels); achan; achan= chan) {
 | |
| 					/* Get next channel to consider */
 | |
| 					chan= GET_NEXT(achan);
 | |
| 					
 | |
| 					/* Try to do channel */
 | |
| 					if (rearrange_func(&agrp->channels, (Link *)achan, ANIMTYPE_ACHAN))
 | |
| 						achan->flag |= ACHAN_MOVED;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	#undef GET_FIRST
 | |
| 	#undef GET_NEXT
 | |
| 	
 | |
| 	/* assemble lists into one list (and clear moved tags) */
 | |
| 	join_groups_action_temp(act);
 | |
| }
 | |
| 
 | |
| /* ------------------- */
 | |
| 
 | |
| static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	short mode;
 | |
| 	
 | |
| 	/* get editor data - only for Action Editor (for now) */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 	if (ac.datatype != ANIMCONT_ACTION)
 | |
| 		return OPERATOR_PASS_THROUGH;
 | |
| 		
 | |
| 	/* get mode, then rearrange channels */
 | |
| 	mode= RNA_enum_get(op->ptr, "direction");
 | |
| 	rearrange_action_channels(&ac, mode);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
|  
 | |
| 
 | |
| void ANIM_OT_channels_move_up (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Move Channel(s) Up";
 | |
| 	ot->idname= "ANIM_OT_channels_move_up";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_rearrange_exec;
 | |
| 	ot->poll= ED_operator_areaactive;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_UP, "Direction", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_move_down (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Move Channel(s) Down";
 | |
| 	ot->idname= "ANIM_OT_channels_move_down";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_rearrange_exec;
 | |
| 	ot->poll= ED_operator_areaactive;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_DOWN, "Direction", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_move_top (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Move Channel(s) to Top";
 | |
| 	ot->idname= "ANIM_OT_channels_move_to_top";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_rearrange_exec;
 | |
| 	ot->poll= ED_operator_areaactive;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_TOP, "Direction", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_move_bottom (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Move Channel(s) to Bottom";
 | |
| 	ot->idname= "ANIM_OT_channels_move_to_bottom";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_rearrange_exec;
 | |
| 	ot->poll= ED_operator_areaactive;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_BOTTOM, "Direction", "");
 | |
| }
 | |
| 
 | |
| #endif // XXX old animation system - needs to be updated for new system...
 | |
| 
 | |
| /* ******************** Delete Channel Operator *********************** */
 | |
| 
 | |
| static int animchannels_delete_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 	
 | |
| 	/* cannot delete in shapekey */
 | |
| 	if (ac.datatype == ANIMCONT_SHAPEKEY) 
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 		
 | |
| 	/* do groups only first (unless in Drivers mode, where there are none) */
 | |
| 	if (ac.datatype != ANIMCONT_DRIVERS) {
 | |
| 		/* filter data */
 | |
| 		filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
 | |
| 		ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
 | |
| 		
 | |
| 		/* delete selected groups and their associated channels */
 | |
| 		for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 			/* only groups - don't check other types yet, since they may no-longer exist */
 | |
| 			if (ale->type == ANIMTYPE_GROUP) {
 | |
| 				bActionGroup *agrp= (bActionGroup *)ale->data;
 | |
| 				AnimData *adt= ale->adt;
 | |
| 				FCurve *fcu, *fcn;
 | |
| 				
 | |
| 				/* skip this group if no AnimData available, as we can't safely remove the F-Curves */
 | |
| 				if (adt == NULL)
 | |
| 					continue;
 | |
| 				
 | |
| 				/* delete all of the Group's F-Curves, but no others */
 | |
| 				for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcn) {
 | |
| 					fcn= fcu->next;
 | |
| 					
 | |
| 					/* remove from group and action, then free */
 | |
| 					action_groups_remove_channel(adt->action, fcu);
 | |
| 					free_fcurve(fcu);
 | |
| 				}
 | |
| 				
 | |
| 				/* free the group itself */
 | |
| 				if (adt->action)
 | |
| 					BLI_freelinkN(&adt->action->groups, agrp);
 | |
| 				else
 | |
| 					MEM_freeN(agrp);
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		/* cleanup */
 | |
| 		BLI_freelistN(&anim_data);
 | |
| 	}
 | |
| 	
 | |
| 	/* now do F-Curves */
 | |
| 	if (ac.datatype != ANIMCONT_GPENCIL) {
 | |
| 		/* filter data */
 | |
| 		filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
 | |
| 		ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
 | |
| 		
 | |
| 		/* delete selected F-Curves */
 | |
| 		for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 			/* only F-Curves, and only if we can identify its parent */
 | |
| 			if (ale->type == ANIMTYPE_FCURVE) {
 | |
| 				AnimData *adt= ale->adt;
 | |
| 				FCurve *fcu= (FCurve *)ale->data;
 | |
| 				
 | |
| 				/* try to free F-Curve */
 | |
| 				ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		/* cleanup */
 | |
| 		BLI_freelistN(&anim_data);
 | |
| 	}
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
|  
 | |
| void ANIM_OT_channels_delete (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Delete Channels";
 | |
| 	ot->idname= "ANIM_OT_channels_delete";
 | |
| 	ot->description= "Delete all selected animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_delete_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| }
 | |
| 
 | |
| /* ******************** Set Channel Visibility Operator *********************** */
 | |
| /* NOTE: this operator is only valid in the Graph Editor channels region */
 | |
| 
 | |
| static int animchannels_visibility_set_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	ListBase all_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 	
 | |
| 	/* get list of all channels that selection may need to be flushed to */
 | |
| 	filter= ANIMFILTER_CHANNELS;
 | |
| 	ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
 | |
| 	
 | |
| 	/* hide all channels not selected */
 | |
| 	filter= (ANIMFILTER_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
 | |
| 	ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
 | |
| 	
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		/* clear setting first */
 | |
| 		ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
 | |
| 		
 | |
| 		/* now also flush selection status as appropriate 
 | |
| 		 * NOTE: in some cases, this may result in repeat flushing being performed
 | |
| 		 */
 | |
| 		ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
 | |
| 	}
 | |
| 	
 | |
| 	BLI_freelistN(&anim_data);
 | |
| 	
 | |
| 	/* make all the selected channels visible */
 | |
| 	filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
 | |
| 	ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
 | |
| 	
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		/* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
 | |
| 		// TODO: find out why this is the case, and fix that
 | |
| 		if (ale->type == ANIMTYPE_OBJECT)
 | |
| 			continue;
 | |
| 		
 | |
| 		/* enable the setting */
 | |
| 		ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
 | |
| 		
 | |
| 		/* now, also flush selection status up/down as appropriate */
 | |
| 		ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
 | |
| 	}
 | |
| 	
 | |
| 	BLI_freelistN(&anim_data);
 | |
| 	BLI_freelistN(&all_data);
 | |
| 	
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_visibility_set (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Set Visibility";
 | |
| 	ot->idname= "ANIM_OT_channels_visibility_set";
 | |
| 	ot->description= "Make only the selected animation channels visible in the Graph Editor";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_visibility_set_exec;
 | |
| 	ot->poll= ED_operator_ipo_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ******************** Toggle Channel Visibility Operator *********************** */
 | |
| /* NOTE: this operator is only valid in the Graph Editor channels region */
 | |
| 
 | |
| static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	ListBase all_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	short vis= ACHANNEL_SETFLAG_ADD;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 	/* get list of all channels that selection may need to be flushed to */
 | |
| 	filter= (ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS);
 | |
| 	ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
 | |
| 		
 | |
| 	/* filter data */
 | |
| 	filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
 | |
| 	ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
 | |
| 	
 | |
| 	/* See if we should be making showing all selected or hiding */
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		/* set the setting in the appropriate way (if available) */
 | |
| 		if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
 | |
| 			vis= ACHANNEL_SETFLAG_CLEAR;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Now set the flags */
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		/* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
 | |
| 		// TODO: find out why this is the case, and fix that
 | |
| 		if (ale->type == ANIMTYPE_OBJECT)
 | |
| 			continue;
 | |
| 		
 | |
| 		/* change the setting */
 | |
| 		ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
 | |
| 		
 | |
| 		/* now, also flush selection status up/down as appropriate */
 | |
| 		ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
 | |
| 	}
 | |
| 	
 | |
| 	/* cleanup */
 | |
| 	BLI_freelistN(&anim_data);
 | |
| 	BLI_freelistN(&all_data);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Toggle Visibility";
 | |
| 	ot->idname= "ANIM_OT_channels_visibility_toggle";
 | |
| 	ot->description= "Toggle visibility in Graph Editor of all selected animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_visibility_toggle_exec;
 | |
| 	ot->poll= ED_operator_ipo_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| }
 | |
| 
 | |
| /* ********************** Set Flags Operator *********************** */
 | |
| 
 | |
| /* defines for setting animation-channel flags */
 | |
| EnumPropertyItem prop_animchannel_setflag_types[] = {
 | |
| 	{ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
 | |
| 	{ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
 | |
| 	{ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
 | |
| 	{ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""},
 | |
| 	{0, NULL, 0, NULL, NULL}
 | |
| };
 | |
| 
 | |
| /* defines for set animation-channel settings */
 | |
| // TODO: could add some more types, but those are really quite dependent on the mode...
 | |
| EnumPropertyItem prop_animchannel_settings_types[] = {
 | |
| 	{ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
 | |
| 	{ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
 | |
| 	{0, NULL, 0, NULL, NULL}
 | |
| };
 | |
| 
 | |
| 
 | |
| /* ------------------- */
 | |
| 
 | |
| /* macro to be used in setflag_anim_channels */
 | |
| #define ASUBCHANNEL_SEL_OK(ale) ( (onlysel == 0) || \
 | |
| 		((ale->id) && (GS(ale->id->name)==ID_OB) && (((Object *)ale->id)->flag & SELECT)) ) 
 | |
| 
 | |
| /* Set/clear a particular flag (setting) for all selected + visible channels 
 | |
|  *	setting: the setting to modify
 | |
|  *	mode: eAnimChannels_SetFlag
 | |
|  *	onlysel: only selected channels get the flag set
 | |
|  */
 | |
| // TODO: enable a setting which turns flushing on/off?
 | |
| static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, short onlysel, short flush)
 | |
| {
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	ListBase all_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	
 | |
| 	/* filter data that we need if flush is on */
 | |
| 	if (flush) {
 | |
| 		/* get list of all channels that selection may need to be flushed to */
 | |
| 		filter= ANIMFILTER_CHANNELS;
 | |
| 		ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype);
 | |
| 	}
 | |
| 	
 | |
| 	/* filter data that we're working on */
 | |
| 	// XXX: noduplis enabled so that results don't cancel, but will be problematic for some channels where only type differs
 | |
| 	filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS);
 | |
| 	if (onlysel) filter |= ANIMFILTER_SEL;
 | |
| 	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
 | |
| 	
 | |
| 	/* if toggling, check if disable or enable */
 | |
| 	if (mode == ACHANNEL_SETFLAG_TOGGLE) {
 | |
| 		/* default to turn all on, unless we encounter one that's on... */
 | |
| 		mode= ACHANNEL_SETFLAG_ADD;
 | |
| 		
 | |
| 		/* see if we should turn off instead... */
 | |
| 		for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 			/* set the setting in the appropriate way (if available) */
 | |
| 			if (ANIM_channel_setting_get(ac, ale, setting) > 0) {
 | |
| 				mode= ACHANNEL_SETFLAG_CLEAR;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	/* apply the setting */
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		/* skip channel if setting is not available */
 | |
| 		if (ANIM_channel_setting_get(ac, ale, setting) == -1)
 | |
| 			continue;
 | |
| 		
 | |
| 		/* set the setting in the appropriate way */
 | |
| 		ANIM_channel_setting_set(ac, ale, setting, mode);
 | |
| 		
 | |
| 		/* if flush status... */
 | |
| 		if (flush)
 | |
| 			ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
 | |
| 	}
 | |
| 	
 | |
| 	BLI_freelistN(&anim_data);
 | |
| 	BLI_freelistN(&all_data);
 | |
| }
 | |
| 
 | |
| /* ------------------- */
 | |
| 
 | |
| static int animchannels_setflag_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	short mode, setting;
 | |
| 	short flush=1;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 	/* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
 | |
| 	mode= RNA_enum_get(op->ptr, "mode");
 | |
| 	setting= RNA_enum_get(op->ptr, "type");
 | |
| 	
 | |
| 	/* check if setting is flushable */
 | |
| 	if (setting == ACHANNEL_SETTING_EXPAND)
 | |
| 		flush= 0;
 | |
| 	
 | |
| 	/* modify setting 
 | |
| 	 *	- only selected channels are affected
 | |
| 	 */
 | |
| 	setflag_anim_channels(&ac, setting, mode, 1, flush);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
| 
 | |
| 
 | |
| void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Enable Channel Setting";
 | |
| 	ot->idname= "ANIM_OT_channels_setting_enable";
 | |
| 	ot->description= "Enable specified setting on all selected animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->invoke= WM_menu_invoke;
 | |
| 	ot->exec= animchannels_setflag_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 		/* flag-setting mode */
 | |
| 	RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
 | |
| 		/* setting to set */
 | |
| 	ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Disable Channel Setting";
 | |
| 	ot->idname= "ANIM_OT_channels_setting_disable";
 | |
| 	ot->description= "Disable specified setting on all selected animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->invoke= WM_menu_invoke;
 | |
| 	ot->exec= animchannels_setflag_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 		/* flag-setting mode */
 | |
| 	RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
 | |
| 		/* setting to set */
 | |
| 	ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_setting_invert (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Invert Channel Setting";
 | |
| 	ot->idname= "ANIM_OT_channels_setting_toggle";
 | |
| 	ot->description= "Invert specified setting on all selected animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->invoke= WM_menu_invoke;
 | |
| 	ot->exec= animchannels_setflag_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 		/* flag-setting mode */
 | |
| 	RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_INVERT, "Mode", "");
 | |
| 		/* setting to set */
 | |
| 	ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Toggle Channel Setting";
 | |
| 	ot->idname= "ANIM_OT_channels_setting_toggle";
 | |
| 	ot->description= "Toggle specified setting on all selected animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->invoke= WM_menu_invoke;
 | |
| 	ot->exec= animchannels_setflag_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 		/* flag-setting mode */
 | |
| 	RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
 | |
| 		/* setting to set */
 | |
| 	ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_editable_toggle (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Toggle Channel Editability";
 | |
| 	ot->idname= "ANIM_OT_channels_editable_toggle";
 | |
| 	ot->description= "Toggle editability of selected channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_setflag_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 		/* flag-setting mode */
 | |
| 	RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
 | |
| 		/* setting to set */
 | |
| 	RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
 | |
| }
 | |
| 
 | |
| /* ********************** Expand Channels Operator *********************** */
 | |
| 
 | |
| static int animchannels_expand_exec (bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	short onlysel= 1;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 	/* only affect selected channels? */
 | |
| 	if (RNA_boolean_get(op->ptr, "all"))
 | |
| 		onlysel= 0;
 | |
| 	
 | |
| 	/* modify setting */
 | |
| 	setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_expand (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Expand Channels";
 | |
| 	ot->idname= "ANIM_OT_channels_expand";
 | |
| 	ot->description= "Expand (i.e. open) all selected expandable animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_expand_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
 | |
| }
 | |
| 
 | |
| /* ********************** Collapse Channels Operator *********************** */
 | |
| 
 | |
| static int animchannels_collapse_exec (bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	short onlysel= 1;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 	/* only affect selected channels? */
 | |
| 	if (RNA_boolean_get(op->ptr, "all"))
 | |
| 		onlysel= 0;
 | |
| 	
 | |
| 	/* modify setting */
 | |
| 	setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
| 
 | |
| void ANIM_OT_channels_collapse (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Collapse Channels";
 | |
| 	ot->idname= "ANIM_OT_channels_collapse";
 | |
| 	ot->description= "Collapse (i.e. close) all selected expandable animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_collapse_exec;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
 | |
| }
 | |
| 
 | |
| /* ********************** Select All Operator *********************** */
 | |
| 
 | |
| static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 	/* 'standard' behaviour - check if selected, then apply relevant selection */
 | |
| 	if (RNA_boolean_get(op->ptr, "invert"))
 | |
| 		ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
 | |
| 	else
 | |
| 		ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
|  
 | |
| void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Select All";
 | |
| 	ot->idname= "ANIM_OT_channels_select_all_toggle";
 | |
| 	ot->description= "Toggle selection of all animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->exec= animchannels_deselectall_exec;
 | |
| 	ot->poll= animedit_poll_channels_nla_tweakmode_off;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* props */
 | |
| 	ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
 | |
| }
 | |
| 
 | |
| /* ******************** Borderselect Operator *********************** */
 | |
| 
 | |
| static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
 | |
| {
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	
 | |
| 	View2D *v2d= &ac->ar->v2d;
 | |
| 	rctf rectf;
 | |
| 	float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
 | |
| 	
 | |
| 	/* convert border-region to view coordinates */
 | |
| 	UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
 | |
| 	UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
 | |
| 	
 | |
| 	/* filter data */
 | |
| 	filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
 | |
| 	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
 | |
| 	
 | |
| 	/* loop over data, doing border select */
 | |
| 	for (ale= anim_data.first; ale; ale= ale->next) {
 | |
| 		ymin= ymax - ACHANNEL_STEP;
 | |
| 		
 | |
| 		/* if channel is within border-select region, alter it */
 | |
| 		if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
 | |
| 			/* set selection flags only */
 | |
| 			ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode);
 | |
| 			
 | |
| 			/* type specific actions */
 | |
| 			switch (ale->type) {
 | |
| 				case ANIMTYPE_GROUP:
 | |
| 				{
 | |
| 					bActionGroup *agrp= (bActionGroup *)ale->data;
 | |
| 					
 | |
| 					/* always clear active flag after doing this */
 | |
| 					agrp->flag &= ~AGRP_ACTIVE;
 | |
| 				}
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		/* set minimum extent to be the maximum of the next channel */
 | |
| 		ymax= ymin;
 | |
| 	}
 | |
| 	
 | |
| 	/* cleanup */
 | |
| 	BLI_freelistN(&anim_data);
 | |
| }
 | |
| 
 | |
| /* ------------------- */
 | |
| 
 | |
| static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	rcti rect;
 | |
| 	short selectmode=0;
 | |
| 	int gesture_mode;
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 	
 | |
| 	/* get settings from operator */
 | |
| 	rect.xmin= RNA_int_get(op->ptr, "xmin");
 | |
| 	rect.ymin= RNA_int_get(op->ptr, "ymin");
 | |
| 	rect.xmax= RNA_int_get(op->ptr, "xmax");
 | |
| 	rect.ymax= RNA_int_get(op->ptr, "ymax");
 | |
| 		
 | |
| 	gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
 | |
| 	if (gesture_mode == GESTURE_MODAL_SELECT)
 | |
| 		selectmode = ACHANNEL_SETFLAG_ADD;
 | |
| 	else
 | |
| 		selectmode = ACHANNEL_SETFLAG_CLEAR;
 | |
| 	
 | |
| 	/* apply borderselect animation channels */
 | |
| 	borderselect_anim_channels(&ac, &rect, selectmode);
 | |
| 	
 | |
| 	/* send notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| } 
 | |
| 
 | |
| void ANIM_OT_channels_select_border(wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Border Select";
 | |
| 	ot->idname= "ANIM_OT_channels_select_border";
 | |
| 	ot->description= "Select all animation channels within the specified region";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->invoke= WM_border_select_invoke;
 | |
| 	ot->exec= animchannels_borderselect_exec;
 | |
| 	ot->modal= WM_border_select_modal;
 | |
| 	
 | |
| 	ot->poll= animedit_poll_channels_nla_tweakmode_off;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* rna */
 | |
| 	WM_operator_properties_gesture_border(ot, FALSE);
 | |
| }
 | |
| 
 | |
| /* ******************** Mouse-Click Operator *********************** */
 | |
| /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */
 | |
| 
 | |
| static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
 | |
| {
 | |
| 	ListBase anim_data = {NULL, NULL};
 | |
| 	bAnimListElem *ale;
 | |
| 	int filter;
 | |
| 	int notifierFlags = 0;
 | |
| 	
 | |
| 	/* get the channel that was clicked on */
 | |
| 		/* filter channels */
 | |
| 	filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
 | |
| 	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
 | |
| 	
 | |
| 		/* get channel from index */
 | |
| 	ale= BLI_findlink(&anim_data, channel_index);
 | |
| 	if (ale == NULL) {
 | |
| 		/* channel not found */
 | |
| 		if (G.f & G_DEBUG)
 | |
| 			printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
 | |
| 		
 | |
| 		BLI_freelistN(&anim_data);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	
 | |
| 	/* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
 | |
| 	// TODO: should this feature be extended to work with other channel types too?
 | |
| 	if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
 | |
| 		/* normal channels should not behave normally in this case */
 | |
| 		BLI_freelistN(&anim_data);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	
 | |
| 	/* action to take depends on what channel we've got */
 | |
| 	// WARNING: must keep this in sync with the equivalent function in nla_channels.c
 | |
| 	switch (ale->type) {
 | |
| 		case ANIMTYPE_SCENE:
 | |
| 		{
 | |
| 			Scene *sce= (Scene *)ale->data;
 | |
| 			AnimData *adt= sce->adt;
 | |
| 			
 | |
| 			/* set selection status */
 | |
| 			if (selectmode == SELECT_INVERT) {
 | |
| 				/* swap select */
 | |
| 				sce->flag ^= SCE_DS_SELECTED;
 | |
| 				if (adt) adt->flag ^= ADT_UI_SELECTED;
 | |
| 			}
 | |
| 			else {
 | |
| 				sce->flag |= SCE_DS_SELECTED;
 | |
| 				if (adt) adt->flag |= ADT_UI_SELECTED;
 | |
| 			}
 | |
| 			
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
 | |
| 		}
 | |
| 			break;
 | |
| 		case ANIMTYPE_OBJECT:
 | |
| 		{
 | |
| 			bDopeSheet *ads= (bDopeSheet *)ac->data;
 | |
| 			Scene *sce= (Scene *)ads->source;
 | |
| 			Base *base= (Base *)ale->data;
 | |
| 			Object *ob= base->object;
 | |
| 			AnimData *adt= ob->adt;
 | |
| 			
 | |
| 			/* set selection status */
 | |
| 			if (selectmode == SELECT_INVERT) {
 | |
| 				/* swap select */
 | |
| 				base->flag ^= SELECT;
 | |
| 				ob->flag= base->flag;
 | |
| 				
 | |
| 				if (adt) adt->flag ^= ADT_UI_SELECTED;
 | |
| 			}
 | |
| 			else {
 | |
| 				Base *b;
 | |
| 				
 | |
| 				/* deselect all */
 | |
| 				// TODO: should this deselect all other types of channels too?
 | |
| 				for (b= sce->base.first; b; b= b->next) {
 | |
| 					b->flag &= ~SELECT;
 | |
| 					b->object->flag= b->flag;
 | |
| 					if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE);
 | |
| 				}
 | |
| 				
 | |
| 				/* select object now */
 | |
| 				base->flag |= SELECT;
 | |
| 				ob->flag |= SELECT;
 | |
| 				if (adt) adt->flag |= ADT_UI_SELECTED;
 | |
| 			}
 | |
| 			
 | |
| 			if ((adt) && (adt->flag & ADT_UI_SELECTED))
 | |
| 				adt->flag |= ADT_UI_ACTIVE;
 | |
| 			
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
 | |
| 		}
 | |
| 			break;
 | |
| 		
 | |
| 		case ANIMTYPE_FILLACTD: /* Action Expander */
 | |
| 		case ANIMTYPE_DSMAT:	/* Datablock AnimData Expanders */
 | |
| 		case ANIMTYPE_DSLAM:
 | |
| 		case ANIMTYPE_DSCAM:
 | |
| 		case ANIMTYPE_DSCUR:
 | |
| 		case ANIMTYPE_DSSKEY:
 | |
| 		case ANIMTYPE_DSWOR:
 | |
| 		case ANIMTYPE_DSPART:
 | |
| 		case ANIMTYPE_DSMBALL:
 | |
| 		case ANIMTYPE_DSARM:
 | |
| 		case ANIMTYPE_DSMESH:
 | |
| 		case ANIMTYPE_DSNTREE:
 | |
| 		case ANIMTYPE_DSTEX:
 | |
| 		{
 | |
| 			/* sanity checking... */
 | |
| 			if (ale->adt) {
 | |
| 				/* select/deselect */
 | |
| 				if (selectmode == SELECT_INVERT) {
 | |
| 					/* inverse selection status of this AnimData block only */
 | |
| 					ale->adt->flag ^= ADT_UI_SELECTED;
 | |
| 				}
 | |
| 				else {
 | |
| 					/* select AnimData block by itself */
 | |
| 					ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
 | |
| 					ale->adt->flag |= ADT_UI_SELECTED;
 | |
| 				}
 | |
| 				
 | |
| 				/* set active? */
 | |
| 				if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
 | |
| 					ale->adt->flag |= ADT_UI_ACTIVE;
 | |
| 			}
 | |
| 			
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
 | |
| 		}	
 | |
| 			break;
 | |
| 		
 | |
| 		case ANIMTYPE_GROUP: 
 | |
| 		{
 | |
| 			bActionGroup *agrp= (bActionGroup *)ale->data;
 | |
| 			
 | |
| 			/* select/deselect group */
 | |
| 			if (selectmode == SELECT_INVERT) {
 | |
| 				/* inverse selection status of this group only */
 | |
| 				agrp->flag ^= AGRP_SELECTED;
 | |
| 			}
 | |
| 			else if (selectmode == -1) {
 | |
| 				/* select all in group (and deselect everthing else) */	
 | |
| 				FCurve *fcu;
 | |
| 				
 | |
| 				/* deselect all other channels */
 | |
| 				ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
 | |
| 				
 | |
| 				/* only select channels in group and group itself */
 | |
| 				for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
 | |
| 					fcu->flag |= FCURVE_SELECTED;
 | |
| 				agrp->flag |= AGRP_SELECTED;					
 | |
| 			}
 | |
| 			else {
 | |
| 				/* select group by itself */
 | |
| 				ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
 | |
| 				agrp->flag |= AGRP_SELECTED;
 | |
| 			}
 | |
| 			
 | |
| 			/* if group is selected now, make group the 'active' one in the visible list */
 | |
| 			if (agrp->flag & AGRP_SELECTED)
 | |
| 				ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
 | |
| 				
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
 | |
| 		}
 | |
| 			break;
 | |
| 		case ANIMTYPE_FCURVE: 
 | |
| 		{
 | |
| 			FCurve *fcu= (FCurve *)ale->data;
 | |
| 			
 | |
| 			/* select/deselect */
 | |
| 			if (selectmode == SELECT_INVERT) {
 | |
| 				/* inverse selection status of this F-Curve only */
 | |
| 				fcu->flag ^= FCURVE_SELECTED;
 | |
| 			}
 | |
| 			else {
 | |
| 				/* select F-Curve by itself */
 | |
| 				ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
 | |
| 				fcu->flag |= FCURVE_SELECTED;
 | |
| 			}
 | |
| 			
 | |
| 			/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
 | |
| 			if (fcu->flag & FCURVE_SELECTED)
 | |
| 				ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
 | |
| 				
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
 | |
| 		}
 | |
| 			break;
 | |
| 		case ANIMTYPE_SHAPEKEY: 
 | |
| 		{
 | |
| 			KeyBlock *kb= (KeyBlock *)ale->data;
 | |
| 			
 | |
| 			/* select/deselect */
 | |
| 			if (selectmode == SELECT_INVERT) {
 | |
| 				/* inverse selection status of this ShapeKey only */
 | |
| 				kb->flag ^= KEYBLOCK_SEL;
 | |
| 			}
 | |
| 			else {
 | |
| 				/* select ShapeKey by itself */
 | |
| 				ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
 | |
| 				kb->flag |= KEYBLOCK_SEL;
 | |
| 			}
 | |
| 				
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
 | |
| 		}
 | |
| 			break;
 | |
| 		case ANIMTYPE_GPDATABLOCK:
 | |
| 		{
 | |
| 			bGPdata *gpd= (bGPdata *)ale->data;
 | |
| 			
 | |
| 			/* toggle expand */
 | |
| 			gpd->flag ^= GP_DATA_EXPAND;
 | |
| 			
 | |
| 			notifierFlags |= (ND_ANIMCHAN|NA_EDITED);
 | |
| 		}
 | |
| 			break;
 | |
| 		case ANIMTYPE_GPLAYER:
 | |
| 		{
 | |
| #if 0 // XXX future of this is unclear
 | |
| 			bGPdata *gpd= (bGPdata *)ale->owner; // xxx depreceated
 | |
| 			bGPDlayer *gpl= (bGPDlayer *)ale->data;
 | |
| 			
 | |
| 			if (x >= (ACHANNEL_NAMEWIDTH-16)) {
 | |
| 				/* toggle lock */
 | |
| 				gpl->flag ^= GP_LAYER_LOCKED;
 | |
| 			}
 | |
| 			else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
 | |
| 				/* toggle hide */
 | |
| 				gpl->flag ^= GP_LAYER_HIDE;
 | |
| 			}
 | |
| 			else {
 | |
| 				/* select/deselect */
 | |
| 				//if (G.qual & LR_SHIFTKEY) {
 | |
| 					//select_gplayer_channel(gpd, gpl, SELECT_INVERT);
 | |
| 				//}
 | |
| 				//else {
 | |
| 					//deselect_gpencil_layers(data, 0);
 | |
| 					//select_gplayer_channel(gpd, gpl, SELECT_INVERT);
 | |
| 				//}
 | |
| 			}
 | |
| #endif // XXX future of this is unclear
 | |
| 		}
 | |
| 			break;
 | |
| 		default:
 | |
| 			if (G.f & G_DEBUG)
 | |
| 				printf("Error: Invalid channel type in mouse_anim_channels() \n");
 | |
| 	}
 | |
| 	
 | |
| 	/* free channels */
 | |
| 	BLI_freelistN(&anim_data);
 | |
| 	
 | |
| 	/* return notifier flags */
 | |
| 	return notifierFlags;
 | |
| }
 | |
| 
 | |
| /* ------------------- */
 | |
| 
 | |
| /* handle clicking */
 | |
| static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
 | |
| {
 | |
| 	bAnimContext ac;
 | |
| 	Scene *scene;
 | |
| 	ARegion *ar;
 | |
| 	View2D *v2d;
 | |
| 	int mval[2], channel_index;
 | |
| 	int notifierFlags = 0;
 | |
| 	short selectmode;
 | |
| 	float x, y;
 | |
| 	
 | |
| 	
 | |
| 	/* get editor data */
 | |
| 	if (ANIM_animdata_get_context(C, &ac) == 0)
 | |
| 		return OPERATOR_CANCELLED;
 | |
| 		
 | |
| 	/* get useful pointers from animation context data */
 | |
| 	scene= ac.scene;
 | |
| 	ar= ac.ar;
 | |
| 	v2d= &ar->v2d;
 | |
| 	
 | |
| 	/* get mouse coordinates (in region coordinates) */
 | |
| 	mval[0]= (event->x - ar->winrct.xmin);
 | |
| 	mval[1]= (event->y - ar->winrct.ymin);
 | |
| 	
 | |
| 	/* select mode is either replace (deselect all, then add) or add/extend */
 | |
| 	if (RNA_boolean_get(op->ptr, "extend"))
 | |
| 		selectmode= SELECT_INVERT;
 | |
| 	else if (RNA_boolean_get(op->ptr, "children_only"))
 | |
| 		selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
 | |
| 	else
 | |
| 		selectmode= SELECT_REPLACE;
 | |
| 	
 | |
| 	/* figure out which channel user clicked in 
 | |
| 	 * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
 | |
| 	 *		so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
 | |
| 	 *		ACHANNEL_HEIGHT_HALF.
 | |
| 	 */
 | |
| 	UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
 | |
| 	UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
 | |
| 	
 | |
| 	/* handle mouse-click in the relevant channel then */
 | |
| 	notifierFlags= mouse_anim_channels(&ac, x, channel_index, selectmode);
 | |
| 	
 | |
| 	/* set notifier that things have changed */
 | |
| 	WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL);
 | |
| 	
 | |
| 	return OPERATOR_FINISHED;
 | |
| }
 | |
|  
 | |
| void ANIM_OT_channels_click (wmOperatorType *ot)
 | |
| {
 | |
| 	/* identifiers */
 | |
| 	ot->name= "Mouse Click on Channels";
 | |
| 	ot->idname= "ANIM_OT_channels_click";
 | |
| 	ot->description= "Handle mouse-clicks over animation channels";
 | |
| 	
 | |
| 	/* api callbacks */
 | |
| 	ot->invoke= animchannels_mouseclick_invoke;
 | |
| 	ot->poll= animedit_poll_channels_active;
 | |
| 	
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 | |
| 	
 | |
| 	/* id-props */
 | |
| 	RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
 | |
| 	RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
 | |
| }
 | |
| 
 | |
| /* ************************************************************************** */
 | |
| /* Operator Registration */
 | |
| 
 | |
| void ED_operatortypes_animchannels(void)
 | |
| {
 | |
| 	WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_select_border);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_click);
 | |
| 	
 | |
| 	WM_operatortype_append(ANIM_OT_channels_setting_enable);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_setting_disable);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_setting_invert);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_setting_toggle);
 | |
| 	
 | |
| 	WM_operatortype_append(ANIM_OT_channels_delete);
 | |
| 	
 | |
| 		// XXX does this need to be a separate operator?
 | |
| 	WM_operatortype_append(ANIM_OT_channels_editable_toggle);
 | |
| 	
 | |
| 		// XXX these need to be updated for new system... todo...
 | |
| 	//WM_operatortype_append(ANIM_OT_channels_move_up);
 | |
| 	//WM_operatortype_append(ANIM_OT_channels_move_down);
 | |
| 	//WM_operatortype_append(ANIM_OT_channels_move_top);
 | |
| 	//WM_operatortype_append(ANIM_OT_channels_move_bottom);
 | |
| 	
 | |
| 	WM_operatortype_append(ANIM_OT_channels_expand);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_collapse);
 | |
| 	
 | |
| 	WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
 | |
| 	WM_operatortype_append(ANIM_OT_channels_visibility_set);
 | |
| }
 | |
| 
 | |
| // TODO: check on a poll callback for this, to get hotkeys into menus
 | |
| void ED_keymap_animchannels(wmKeyConfig *keyconf)
 | |
| {
 | |
| 	wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
 | |
| 	
 | |
| 	/* selection */
 | |
| 		/* click-select */
 | |
| 		// XXX for now, only leftmouse.... 
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
 | |
| 	RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
 | |
| 	RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "children_only", 1);
 | |
| 	
 | |
| 		/* deselect all */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
 | |
| 	RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
 | |
| 	
 | |
| 		/* borderselect */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
 | |
| 	
 | |
| 	/* delete */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
 | |
| 	
 | |
| 	/* settings */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
 | |
| 	
 | |
| 	/* settings - specialised hotkeys */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
 | |
| 	
 | |
| 	/* expand/collapse */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
 | |
| 	
 | |
| 	RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
 | |
| 	RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
 | |
| 	
 | |
| 	/* rearranging - actions only */
 | |
| 	//WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
 | |
| 	//WM_keymap_add_item(keymap, "ANIM_OT_channels_move_down", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
 | |
| 	//WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_top", PAGEUPKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
 | |
| 	//WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_bottom", PAGEDOWNKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
 | |
| 	
 | |
| 	/* Graph Editor only */
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
 | |
| 	WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
 | |
| }
 | |
| 
 | |
| /* ************************************************************************** */
 |