Example #1
0
/**
 * Find the extents of the active channel
 *
 * \param[out] min Bottom y-extent of channel
 * \param[out] max Top y-extent of channel
 * \return Success of finding a selected channel
 */
static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale;
	int filter;
	
	short found = 0; /* NOTE: not bool, since we want prioritise individual channels over expanders */
	float y;
	
	/* get all items - we need to do it this way */
	filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
	
	/* loop through all channels, finding the first one that's selected */
	y = (float)ACHANNEL_FIRST;
	
	for (ale = anim_data.first; ale; ale = ale->next) {
		const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
		
		/* must be selected... */
		if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && 
		    ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT))
		{
			/* update best estimate */
			*min = (float)(y - ACHANNEL_HEIGHT_HALF);
			*max = (float)(y + ACHANNEL_HEIGHT_HALF);
			
			/* is this high enough priority yet? */
			found = acf->channel_role;
			
			/* only stop our search when we've found an actual channel
			 * - datablock expanders get less priority so that we don't abort prematurely
			 */
			if (found == ACHANNEL_ROLE_CHANNEL) {
				break;
			}
		}
		
		/* adjust y-position for next one */
		y -= ACHANNEL_STEP;
	}
	
	/* free all temp data */
	ANIM_animdata_freelist(&anim_data);
	
	return (found != 0);
}
Example #2
0
/* draw keyframes in each channel */
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale;
	int filter;
	
	View2D *v2d = &ar->v2d;
	bDopeSheet *ads = &saction->ads;
	AnimData *adt = NULL;
	
	float act_start, act_end, y;
	size_t items;
	int height;
	
	unsigned char col1[3], col2[3];
	unsigned char col1a[3], col2a[3];
	unsigned char col1b[3], col2b[3];
	
	
	/* get theme colors */
	UI_GetThemeColor3ubv(TH_BACK, col2);
	UI_GetThemeColor3ubv(TH_HILITE, col1);
	
	UI_GetThemeColor3ubv(TH_GROUP, col2a);
	UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
	
	UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
	UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
	
	/* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */

	/* if in NLA there's a strip active, map the view */
	if (ac->datatype == ANIMCONT_ACTION) {
		/* adt= ANIM_nla_mapping_get(ac, NULL); */ /* UNUSED */
		
		/* start and end of action itself */
		calc_action_range(ac->data, &act_start, &act_end, 0);
	}
	
	/* build list of channels to draw */
	filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
	items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
	
	/* Update max-extent of channels here (taking into account scrollers):
	 *  - this is done to allow the channel list to be scrollable, but must be done here
	 *    to avoid regenerating the list again and/or also because channels list is drawn first
	 *	- offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
	 *	  start of list offset, and the second is as a correction for the scrollers.
	 */
	height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2));
	/* don't use totrect set, as the width stays the same 
	 * (NOTE: this is ok here, the configuration is pretty straightforward) 
	 */
	v2d->tot.ymin = (float)(-height);
	
	/* first backdrop strips */
	y = (float)(-ACHANNEL_HEIGHT);
	glEnable(GL_BLEND);
	
	for (ale = anim_data.first; ale; ale = ale->next) {
		const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
		const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
		
		/* check if visible */
		if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
		    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
		{
			bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
			int sel = 0;
			
			/* determine if any need to draw channel */
			if (ale->datatype != ALE_NONE) {
				/* determine if channel is selected */
				if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
					sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
				
				if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
					switch (ale->type) {
						case ANIMTYPE_SUMMARY:
						{
							/* reddish color from NLA */
							UI_ThemeColor4(TH_ANIM_ACTIVE);
						}
						break;
						
						case ANIMTYPE_SCENE:
						case ANIMTYPE_OBJECT:
						{
							if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45); 
							else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22); 
						}
						break;
						
						case ANIMTYPE_FILLACTD:
						case ANIMTYPE_DSSKEY:
						case ANIMTYPE_DSWOR:
						{
							if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45); 
							else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22); 
						}
						break;
						
						case ANIMTYPE_GROUP:
						{
							if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
							else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
						}
						break;
						
						default:
						{
							if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
							else glColor4ub(col2[0], col2[1], col2[2], 0x22);
						}
						break;
					}
					
					/* draw region twice: firstly backdrop, then the current range */
					glRectf(v2d->cur.xmin,  (float)y - ACHANNEL_HEIGHT_HALF,  v2d->cur.xmax + EXTRA_SCROLL_PAD,  (float)y + ACHANNEL_HEIGHT_HALF);
					
					if (ac->datatype == ANIMCONT_ACTION)
						glRectf(act_start,  (float)y - ACHANNEL_HEIGHT_HALF,  act_end,  (float)y + ACHANNEL_HEIGHT_HALF);
				}
				else if (ac->datatype == ANIMCONT_GPENCIL) {
					/* frames less than one get less saturated background */
					if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
					else glColor4ub(col2[0], col2[1], col2[2], 0x22);
					glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF);
					
					/* frames one and higher get a saturated background */
					if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
					else glColor4ub(col2[0], col2[1], col2[2], 0x44);
					glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD,  (float)y + ACHANNEL_HEIGHT_HALF);
				}
				else if (ac->datatype == ANIMCONT_MASK) {
					/* TODO --- this is a copy of gpencil */
					/* frames less than one get less saturated background */
					if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
					else glColor4ub(col2[0], col2[1], col2[2], 0x22);
					glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF);

					/* frames one and higher get a saturated background */
					if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
					else glColor4ub(col2[0], col2[1], col2[2], 0x44);
					glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD,  (float)y + ACHANNEL_HEIGHT_HALF);
				}
			}
		}
		
		/*	Increment the step */
		y -= ACHANNEL_STEP;
	}		
	glDisable(GL_BLEND);
	
	/* Draw keyframes 
	 *	1) Only channels that are visible in the Action Editor get drawn/evaluated.
	 *	   This is to try to optimize this for heavier data sets
	 *	2) Keyframes which are out of view horizontally are disregarded 
	 */
	y = (float)(-ACHANNEL_HEIGHT);
	
	for (ale = anim_data.first; ale; ale = ale->next) {
		const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF);
		const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF);
		
		/* check if visible */
		if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
		    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
		{
			/* check if anything to show for this channel */
			if (ale->datatype != ALE_NONE) {
				adt = ANIM_nla_mapping_get(ac, ale);
				
				/* draw 'keyframes' for each specific datatype */
				switch (ale->datatype) {
					case ALE_ALL:
						draw_summary_channel(v2d, ale->data, y);
						break;
					case ALE_SCE:
						draw_scene_channel(v2d, ads, ale->key_data, y);
						break;
					case ALE_OB:
						draw_object_channel(v2d, ads, ale->key_data, y);
						break;
					case ALE_ACT:
						draw_action_channel(v2d, adt, ale->key_data, y);
						break;
					case ALE_GROUP:
						draw_agroup_channel(v2d, adt, ale->data, y);
						break;
					case ALE_FCURVE:
						draw_fcurve_channel(v2d, adt, ale->key_data, y);
						break;
					case ALE_GPFRAME:
						draw_gpl_channel(v2d, ads, ale->data, y);
						break;
					case ALE_MASKLAY:
						draw_masklay_channel(v2d, ads, ale->data, y);
						break;
				}
			}
		}
		
		y -= ACHANNEL_STEP;
	}
	
	/* free tempolary channels used for drawing */
	BLI_freelistN(&anim_data);

	/* black line marking 'current frame' for Time-Slide transform mode */
	if (saction->flag & SACTION_MOVING) {
		glColor3f(0.0f, 0.0f, 0.0f);
		
		glBegin(GL_LINES);
		glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
		glVertex2f(saction->timeslide, v2d->cur.ymax);
		glEnd();
	}
}
Example #3
0
static void graph_panel_properties(const bContext *C, Panel *pa)
{
	bAnimListElem *ale;
	FCurve *fcu;
	PointerRNA fcu_ptr;
	uiLayout *layout = pa->layout;
	uiLayout *col, *row, *sub;
	// uiBlock *block;  // UNUSED
	char name[256];
	int icon = 0;

	if (!graph_panel_context(C, &ale, &fcu))
		return;
	
	// UNUSED
	// block = uiLayoutGetBlock(layout);
	// UI_block_func_handle_set(block, do_graph_region_buttons, NULL);
	
	/* F-Curve pointer */
	RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
	
	/* user-friendly 'name' for F-Curve */
	col = uiLayoutColumn(layout, false);
	if (ale->type == ANIMTYPE_FCURVE) {
		/* get user-friendly name for F-Curve */
		icon = getname_anim_fcurve(name, ale->id, fcu);
	}
	else {
		/* NLA Control Curve, etc. */
		const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
		
		/* get name */
		if (acf && acf->name) {
			acf->name(ale, name);
		}
		else {
			strcpy(name, IFACE_("<invalid>"));
			icon = ICON_ERROR;
		}
		
		/* icon */
		if (ale->type == ANIMTYPE_NLACURVE)
			icon = ICON_NLA;
	}
	uiItemL(col, name, icon);
		
	/* RNA-Path Editing - only really should be enabled when things aren't working */
	col = uiLayoutColumn(layout, true);
	uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED) != 0);
	uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
	uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE);
		
	/* color settings */
	col = uiLayoutColumn(layout, true);
	uiItemL(col, IFACE_("Display Color:"), ICON_NONE);
		
	row = uiLayoutRow(col, true);
	uiItemR(row, &fcu_ptr, "color_mode", 0, "", ICON_NONE);
			
	sub = uiLayoutRow(row, true);
	uiLayoutSetEnabled(sub, (fcu->color_mode == FCURVE_COLOR_CUSTOM));
	uiItemR(sub, &fcu_ptr, "color", 0, "", ICON_NONE);
	
	MEM_freeN(ale);
}