Exemplo n.º 1
0
void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale;
	int filter;
	
	SpaceNla *snla = (SpaceNla *)ac->sl;
	View2D *v2d = &ar->v2d;
	float y = 0.0f;
	size_t items;
	int height;
	
	/* 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 NLACHANNEL_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 * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 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);
	/* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
	UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
	
	/* draw channels */
	{   /* first pass: just the standard GL-drawing for backdrop + text */
		y = (float)(-NLACHANNEL_HEIGHT(snla));
		
		for (ale = anim_data.first; ale; ale = ale->next) {
			float yminc = (float)(y -  NLACHANNEL_HEIGHT_HALF(snla));
			float ymaxc = (float)(y +  NLACHANNEL_HEIGHT_HALF(snla));
			
			/* check if visible */
			if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
			    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
			{
				/* draw all channels using standard channel-drawing API */
				ANIM_channel_draw(ac, ale, yminc, ymaxc);
			}
			
			/* adjust y-position for next one */
			y -= NLACHANNEL_STEP(snla);
		}
	}
	{   /* second pass: UI widgets */
		uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
		size_t channel_index = 0;
		
		y = (float)(-NLACHANNEL_HEIGHT(snla));
		
		/* set blending again, as may not be set in previous step */
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		
		/* loop through channels, and set up drawing depending on their type  */
		for (ale = anim_data.first; ale; ale = ale->next) {
			const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
			const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
			
			/* check if visible */
			if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
			    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
			{
				/* draw all channels using standard channel-drawing API */
				ANIM_channel_draw_widgets(C, ac, ale, block, yminc, ymaxc, channel_index);
			}
			
			/* adjust y-position for next one */
			y -= NLACHANNEL_STEP(snla);
			channel_index++;
		}
		
		UI_block_end(C, block);
		UI_block_draw(C, block);
		
		glDisable(GL_BLEND);
	}
	
	/* free temporary channels */
	ANIM_animdata_freelist(&anim_data);
}
Exemplo n.º 2
0
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale;
	int filter;
	
	View2D *v2d = &ar->v2d;
	float y = 0.0f;
	size_t items;
	int height;
	
	/* 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 NLACHANNEL_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 * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 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);
	
	/* loop through channels, and set up drawing depending on their type  */
	y = (float)(-NLACHANNEL_HEIGHT(snla));
	
	for (ale = anim_data.first; ale; ale = ale->next) {
		const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
		const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
		
		/* check if visible */
		if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
		    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
		{
			/* data to draw depends on the type of channel */
			switch (ale->type) {
				case ANIMTYPE_NLATRACK:
				{
					AnimData *adt = ale->adt;
					NlaTrack *nlt = (NlaTrack *)ale->data;
					NlaStrip *strip;
					int index;
					
					/* draw each strip in the track (if visible) */
					for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
						if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
							/* draw the visualization of the strip */
							nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc);
							
							/* add the text for this strip to the cache */
							nla_draw_strip_text(adt, nlt, strip, index, v2d, yminc, ymaxc);
							
							/* if transforming strips (only real reason for temp-metas currently), 
							 * add to the cache the frame numbers of the strip's extents
							 */
							if (strip->flag & NLASTRIP_FLAG_TEMP_META)
								nla_draw_strip_frames_text(nlt, strip, v2d, yminc, ymaxc);
						}
					}
					break;
				}
				case ANIMTYPE_NLAACTION:
				{
					AnimData *adt = ale->adt;
					float color[4];
					
					/* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
					 * and a second darker rect within which we draw keyframe indicator dots if there's data
					 */
					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
					glEnable(GL_BLEND);
						
					/* get colors for drawing */
					nla_action_get_color(adt, ale->data, color);
					glColor4fv(color);
					
					/* draw slightly shifted up for greater separation from standard channels,
					 * but also slightly shorter for some more contrast when viewing the strips
					 */
					glRectf(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
					
					/* draw keyframes in the action */
					nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
					
					/* draw 'embossed' lines above and below the strip for effect */
					/* white base-lines */
					glLineWidth(2.0f);
					glColor4f(1.0f, 1.0f, 1.0f, 0.3);
					fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
					fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
					
					/* black top-lines */
					glLineWidth(1.0f);
					glColor3f(0.0f, 0.0f, 0.0f);
					fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
					fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
					
					glDisable(GL_BLEND);
					break;
				}
			}
		}
		
		/* adjust y-position for next one */
		y -= NLACHANNEL_STEP(snla);
	}
	
	/* free tempolary channels */
	ANIM_animdata_freelist(&anim_data);
}
Exemplo n.º 3
0
/* select strip directly under mouse */
static void mouse_nla_strips(bContext *C, bAnimContext *ac, const int mval[2], short select_mode)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale = NULL;
	int filter;
	
	SpaceNla *snla = (SpaceNla *)ac->sl;
	View2D *v2d = &ac->ar->v2d;
	Scene *scene = ac->scene;
	NlaStrip *strip = NULL;
	int channel_index;
	float xmin, xmax;
	float x, y;
	
	
	/* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
	UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
	UI_view2d_listview_view_to_cell(v2d, 0, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
	
	/* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click 
	 * (that is the size of keyframe icons, so user should be expecting similar tolerances) 
	 */
	xmin = UI_view2d_region_to_view_x(v2d, mval[0] - 7);
	xmax = UI_view2d_region_to_view_x(v2d, mval[0] + 7);
	
	/* filter data */
	filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
	
	/* try to get channel */
	ale = BLI_findlink(&anim_data, channel_index);
	if (ale == NULL) {
		/* channel not found */
		printf("Error: animation channel (index = %d) not found in mouse_nla_strips()\n", channel_index);
		ANIM_animdata_freelist(&anim_data);
		return;
	}
	else {
		/* found some channel - we only really should do somethign when its an Nla-Track */
		if (ale->type == ANIMTYPE_NLATRACK) {
			NlaTrack *nlt = (NlaTrack *)ale->data;
			
			/* loop over NLA-strips in this track, trying to find one which occurs in the necessary bounds */
			for (strip = nlt->strips.first; strip; strip = strip->next) {
				if (BKE_nlastrip_within_bounds(strip, xmin, xmax))
					break;
			}
		}
		
		/* remove active channel from list of channels for separate treatment (since it's needed later on) */
		BLI_remlink(&anim_data, ale);
		
		/* free list of channels, since it's not used anymore */
		ANIM_animdata_freelist(&anim_data);
	}
	
	/* if currently in tweakmode, exit tweakmode before changing selection states
	 * now that we've found our target...
	 */
	if (scene->flag & SCE_NLA_EDIT_ON)
		WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
	
	/* for replacing selection, firstly need to clear existing selection */
	if (select_mode == SELECT_REPLACE) {
		/* reset selection mode for next steps */
		select_mode = SELECT_ADD;
		
		/* deselect all strips */
		deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
		
		/* deselect all other channels first */
		ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
	}
	
	/* only select strip if we clicked on a valid channel and hit something */
	if (ale) {
		/* select the strip accordingly (if a matching one was found) */
		if (strip) {
			select_mode = selmodes_to_flagmodes(select_mode);
			ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
			
			/* if we selected it, we can make it active too
			 *	- we always need to clear the active strip flag though... 
			 *  - as well as selecting its track...
			 */
			deselect_nla_strips(ac, DESELECT_STRIPS_CLEARACTIVE, 0);
			
			if (strip->flag & NLASTRIP_FLAG_SELECT) {
				strip->flag |= NLASTRIP_FLAG_ACTIVE;
				
				/* Highlight NLA-Track */
				if (ale->type == ANIMTYPE_NLATRACK) {
					NlaTrack *nlt = (NlaTrack *)ale->data;
					
					nlt->flag |= NLATRACK_SELECTED;
					ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK);
				}
			}
		}
		
		/* free this channel */
		MEM_freeN(ale);
	}
}
Exemplo n.º 4
0
// TODO: depreceate this code...
static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View2D *v2d, float y)
{
	SpaceNla *snla = (SpaceNla *)ac->sl;
	bAnimListElem *ale;
	float x = 0.0f;
	
	/* loop through channels, and set up drawing depending on their type  */
	for (ale = anim_data->first; ale; ale = ale->next) {
		const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
		const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
		const float ydatac = (float)(y - 0.35f * U.widget_unit);
		
		/* check if visible */
		if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
		    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
		{
			AnimData *adt = ale->adt;
			
			short indent = 0, offset = 0, sel = 0, group = 0;
			int special = -1;
			char name[128];
			bool do_draw = false;
			
			/* determine what needs to be drawn */
			switch (ale->type) {
				case ANIMTYPE_NLAACTION: /* NLA Action-Line */
				{
					bAction *act = (bAction *)ale->data;
					
					group = 5;
					
					special = ICON_ACTION;
					
					BLI_strncpy(name, act ? act->id.name + 2 : "<No Action>", sizeof(name));

					/* draw manually still */
					do_draw = TRUE;
					break;
				}
				default: /* handled by standard channel-drawing API */
					/* (draw backdrops only...) */
					ANIM_channel_draw(ac, ale, yminc, ymaxc);
					break;
			}
			
			/* if special types, draw manually for now... */
			if (do_draw) {
				if (ale->id) {
					/* special exception for textures */
					if (GS(ale->id->name) == ID_TE) {
						offset = 0.7f * U.widget_unit;
						indent = 1;
					}
					/* special exception for nodetrees */
					else if (GS(ale->id->name) == ID_NT) {
						bNodeTree *ntree = (bNodeTree *)ale->id;
						
						switch (ntree->type) {
							case NTREE_SHADER:
							{
								/* same as for textures */
								offset = 0.7f * U.widget_unit;
								indent = 1;
								break;
							}
							case NTREE_TEXTURE:
							{
								/* even more */
								offset = U.widget_unit;
								indent = 1;
								break;
							}
							default:
								/* normal will do */
								offset = 0.7f * U.widget_unit;
								break;
						}
					}
					else {
						offset = 0.7f * U.widget_unit;
					}
				}
				else {
					offset = 0;
				}
				
				/* now, start drawing based on this information */
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glEnable(GL_BLEND);
				
				/* draw backing strip behind channel name */
				if (group == 5) {
					float color[4];
					
					/* Action Line
					 *   The alpha values action_get_color returns are only useful for drawing 
					 *   strips backgrounds but here we're doing channel list backgrounds instead
					 *   so we ignore that and use our own when needed
					 */
					nla_action_get_color(adt, (bAction *)ale->data, color);
					
					if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
						/* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */
						glColor3fv(color);
					}
					else {
						float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
						glColor4f(color[0], color[1], color[2], alpha);
					}
					
					offset += 0.35f * U.widget_unit * indent;
					
					/* only on top two corners, to show that this channel sits on top of the preceding ones */
					uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
					
					/* draw slightly shifted up vertically to look like it has more separation from other channels,
					 * but we then need to slightly shorten it so that it doesn't look like it overlaps
					 */
					uiDrawBox(GL_POLYGON, x + offset,  yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
					
					/* clear group value, otherwise we cause errors... */
					group = 0;
				}
				
				
				/* draw special icon indicating certain data-types */
				if (special > -1) {
					/* for normal channels */
					UI_icon_draw(x + offset, ydatac, special);
					offset += 0.85f * U.widget_unit;
				}
				glDisable(GL_BLEND);
				
				/* draw name */
				if (sel)
					UI_ThemeColor(TH_TEXT_HI);
				else
					UI_ThemeColor(TH_TEXT);
				offset += 3;
				UI_DrawString(x + offset, y - 4, name);
				
				/* reset offset - for RHS of panel */
				offset = 0;
				
				/* set blending again, as text drawing may clear it */
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glEnable(GL_BLEND);
				
				
				/* draw NLA-action line 'status-icons' - only when there's an action */
				if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) {
					offset += 0.8f * U.widget_unit;
					
					/* now draw some indicator icons  */
					if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
						/* toggle for tweaking with mapping/no-mapping (i.e. 'in place editing' toggle) */
						// for now, use pin icon to symbolise this
						if (adt->flag & ADT_NLA_EDIT_NOMAP)
							UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_PINNED);
						else
							UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_UNPINNED);
						
						fdrawline((float)(v2d->cur.xmax - offset), yminc,
						          (float)(v2d->cur.xmax - offset), ymaxc);
						offset += 0.8f * U.widget_unit;
						
						/* 'tweaking action' indicator - not a button */
						UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_EDIT);
					}
					else {
						/* XXX firstly draw a little rect to help identify that it's different from the toggles */
						glBegin(GL_LINE_LOOP);
						glVertex2f((float)v2d->cur.xmax - offset - 1, y - 0.35f * U.widget_unit);
						glVertex2f((float)v2d->cur.xmax - offset - 1, y + 0.45f * U.widget_unit);
						glVertex2f((float)v2d->cur.xmax - 1, y + 0.45f * U.widget_unit);
						glVertex2f((float)v2d->cur.xmax - 1, y - 0.35f * U.widget_unit);
						glEnd();
						
						/* 'push down' icon for normal active-actions */
						UI_icon_draw((float)v2d->cur.xmax - offset, ydatac, ICON_FREEZE);
					}
				}
				
				glDisable(GL_BLEND);
			}
		}
		
		/* adjust y-position for next one */
		y -= NLACHANNEL_STEP(snla);
	}
}
Exemplo n.º 5
0
/* handle clicking */
static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
	bAnimContext ac;
	SpaceNla *snla;
	ARegion *ar;
	View2D *v2d;
	int 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 */
	snla = (SpaceNla *)ac.sl;
	ar = ac.ar;
	v2d = &ar->v2d;
	
	/* select mode is either replace (deselect all, then add) or add/extend */
	if (RNA_boolean_get(op->ptr, "extend"))
		selectmode = SELECT_INVERT;
	else
		selectmode = SELECT_REPLACE;
	
	/* figure out which channel user clicked in 
	 * Note: although channels technically start at y= NLACHANNEL_FIRST, we need to adjust by half a channel's height
	 *		so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use
	 *		NLACHANNEL_HEIGHT_HALF.
	 */
	UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
	UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
	
	/* handle mouse-click in the relevant channel then */
	notifierFlags = mouse_nla_channels(C, &ac, x, channel_index, selectmode);
	
	/* set notifier that things have changed */
	WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
	
	return OPERATOR_FINISHED;
}
Exemplo n.º 6
0
// TODO: depreceate this code...
static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View2D *v2d, float y)
{
	SpaceNla *snla = (SpaceNla *)ac->sl;
	bAnimListElem *ale;
	float x = 0.0f;
	
	/* loop through channels, and set up drawing depending on their type  */	
	for (ale = anim_data->first; ale; ale = ale->next) {
		const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
		const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
		const float ydatac = (float)(y - 7);
		
		/* check if visible */
		if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
		    IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
		{
			AnimData *adt = ale->adt;
			
			short indent = 0, offset = 0, sel = 0, group = 0, nonSolo = 0;
			int expand = -1, protect = -1, special = -1, mute = -1;
			char name[128];
			short do_draw = FALSE;
			
			/* determine what needs to be drawn */
			switch (ale->type) {
				case ANIMTYPE_NLATRACK: /* NLA Track */
				{
					NlaTrack *nlt = (NlaTrack *)ale->data;
					
					/* 'solo' as the 'special' button? */
					if (nlt->flag & NLATRACK_SOLO)
						special = ICON_SOLO_ON;
					else
						special = ICON_SOLO_OFF;
						
					/* if this track is active and we're tweaking it, don't draw these toggles */
					// TODO: need a special macro for this...
					if (((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0) {
						if (nlt->flag & NLATRACK_MUTED)
							mute = ICON_MUTE_IPO_ON;
						else
							mute = ICON_MUTE_IPO_OFF;
							
						if (EDITABLE_NLT(nlt))
							protect = ICON_UNLOCKED;
						else
							protect = ICON_LOCKED;
					}
					
					/* is track enabled for solo drawing? */
					if ((adt) && (adt->flag & ADT_NLA_SOLO_TRACK)) {
						if ((nlt->flag & NLATRACK_SOLO) == 0) {
							/* tag for special non-solo handling; also hide the mute toggles */
							nonSolo = 1;
							mute = 0;
						}
					}
						
					sel = SEL_NLT(nlt);
					BLI_strncpy(name, nlt->name, sizeof(name));
					
					/* draw manually still */
					do_draw = TRUE;
				}
				break;
				case ANIMTYPE_NLAACTION: /* NLA Action-Line */
				{
					bAction *act = (bAction *)ale->data;
					
					group = 5;
					
					special = ICON_ACTION;
					
					if (act)
						BLI_snprintf(name, sizeof(name), "%s", act->id.name + 2);
					else
						BLI_strncpy(name, "<No Action>", sizeof(name));
						
					/* draw manually still */
					do_draw = TRUE;
				}
				break;
					
				default: /* handled by standard channel-drawing API */
					// draw backdrops only...
					ANIM_channel_draw(ac, ale, yminc, ymaxc);
					break;
			}	
			
			/* if special types, draw manually for now... */
			if (do_draw) {
				if (ale->id) {
					/* special exception for textures */
					if (GS(ale->id->name) == ID_TE) {
						offset = 14;
						indent = 1;
					}
					/* special exception for nodetrees */
					else if (GS(ale->id->name) == ID_NT) {
						bNodeTree *ntree = (bNodeTree *)ale->id;
						
						switch (ntree->type) {
							case NTREE_SHADER:
							{
								/* same as for textures */
								offset = 14;
								indent = 1;
							}
							break;
								
							case NTREE_TEXTURE:
							{
								/* even more */
								offset = 21;
								indent = 1;
							}	
							break;
								
							default:
								/* normal will do */
								offset = 14;
								break;
						}
					}
					else {
						offset = 14;
					}
				}
				else {
					offset = 0;
				}
				
				/* now, start drawing based on this information */
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glEnable(GL_BLEND);
				
				/* draw backing strip behind channel name */
				// FIXME: hardcoded colors!!!
				if (group == 5) {
					float color[4];
					
					/* Action Line
					 *   The alpha values action_get_color returns are only useful for drawing 
					 *   strips backgrounds but here we're doing channel list backgrounds instead
					 *   so we ignore that and use our own when needed
					 */
					nla_action_get_color(adt, (bAction *)ale->data, color);
					
					if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
						/* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */
						glColor3fv(color);
					}
					else {
						float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3 : 1.0f;
						glColor4f(color[0], color[1], color[2], alpha);
					}
					
					offset += 7 * indent;
					
					/* only on top two corners, to show that this channel sits on top of the preceding ones */
					uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
					
					/* draw slightly shifted up vertically to look like it has more separation from other channels,
					 * but we then need to slightly shorten it so that it doesn't look like it overlaps
					 */
					uiDrawBox(GL_POLYGON, x + offset,  yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
					
					/* clear group value, otherwise we cause errors... */
					group = 0;
				}
				else {
					/* NLA tracks - darker color if not solo track when we're showing solo */
					UI_ThemeColorShade(TH_HEADER, ((nonSolo == 0) ? 20 : -20));
					
					indent += group;
					offset += 7 * indent;
					glBegin(GL_QUADS);
					glVertex2f(x + offset, yminc);
					glVertex2f(x + offset, ymaxc);
					glVertex2f((float)v2d->cur.xmax, ymaxc);
					glVertex2f((float)v2d->cur.xmax, yminc);
					glEnd();
				}
				
				/* draw expand/collapse triangle */
				if (expand > 0) {
					UI_icon_draw(x + offset, ydatac, expand);
					offset += 17;
				}
				
				/* draw special icon indicating certain data-types */
				if (special > -1) {
					/* for normal channels */
					UI_icon_draw(x + offset, ydatac, special);
					offset += 17;
				}
				glDisable(GL_BLEND);
				
				/* draw name */
				if (sel)
					UI_ThemeColor(TH_TEXT_HI);
				else
					UI_ThemeColor(TH_TEXT);
				offset += 3;
				UI_DrawString(x + offset, y - 4, name);
				
				/* reset offset - for RHS of panel */
				offset = 0;
				
				/* set blending again, as text drawing may clear it */
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glEnable(GL_BLEND);
				
				/* draw protect 'lock' */
				if (protect > -1) {
					offset = 16;
					UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, protect);
				}
				
				/* draw mute 'eye' */
				if (mute > -1) {
					offset += 16;
					UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, mute);
				}
				
				/* draw NLA-action line 'status-icons' - only when there's an action */
				if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) {
					AnimData *adt = ale->adt;
					
					offset += 16;
					
					/* now draw some indicator icons  */
					if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
						/* toggle for tweaking with mapping/no-mapping (i.e. 'in place editing' toggle) */
						// for now, use pin icon to symbolise this
						if (adt->flag & ADT_NLA_EDIT_NOMAP)
							UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_PINNED);
						else
							UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_UNPINNED);
						
						fdrawline((float)(v2d->cur.xmax - offset), yminc,
						          (float)(v2d->cur.xmax - offset), ymaxc);
						offset += 16;
						
						/* 'tweaking action' indicator - not a button */
						UI_icon_draw((float)(v2d->cur.xmax - offset), ydatac, ICON_EDIT);
					}
					else {
						/* XXX firstly draw a little rect to help identify that it's different from the toggles */
						glBegin(GL_LINE_LOOP);
						glVertex2f((float)v2d->cur.xmax - offset - 1, y - 7);
						glVertex2f((float)v2d->cur.xmax - offset - 1, y + 9);
						glVertex2f((float)v2d->cur.xmax - 1, y + 9);
						glVertex2f((float)v2d->cur.xmax - 1, y - 7);
						glEnd(); // GL_LINES
						
						/* 'push down' icon for normal active-actions */
						UI_icon_draw((float)v2d->cur.xmax - offset, ydatac, ICON_FREEZE);
					}
				}
				
				glDisable(GL_BLEND);
			}
		}
		
		/* adjust y-position for next one */
		y -= NLACHANNEL_STEP(snla);
	}
}