doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / space_nla / nla_draw.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung (major recode)
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <float.h>
34
35 #include "DNA_anim_types.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_windowmanager_types.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_math.h"
42 #include "BLI_rand.h"
43 #include "BLI_dlrbTree.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_fcurve.h"
47 #include "BKE_nla.h"
48 #include "BKE_context.h"
49 #include "BKE_screen.h"
50
51 #include "ED_anim_api.h"
52 #include "ED_keyframes_draw.h"
53
54 #include "BIF_gl.h"
55 #include "BIF_glutil.h"
56
57 #include "WM_types.h"
58
59 #include "UI_interface.h"
60 #include "UI_interface_icons.h"
61 #include "UI_resources.h"
62 #include "UI_view2d.h"
63
64
65 #include "nla_intern.h" // own include
66
67
68 /* *********************************************** */
69 /* Strips */
70
71 /* Action-Line ---------------------- */
72
73 /* get colors for drawing Action-Line 
74  * NOTE: color returned includes fine-tuned alpha!
75  */
76 static void nla_action_get_color (AnimData *adt, bAction *act, float color[4])
77 {
78         // TODO: if tweaking some action, use the same color as for the tweaked track (quick hack done for now)
79         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
80                 // greenish color (same as tweaking strip) - hardcoded for now
81                 color[0]= 0.30f;
82                 color[1]= 0.95f;
83                 color[2]= 0.10f;
84                 color[3]= 0.30f;
85         }
86         else {
87                 if (act) {
88                         // reddish color - hardcoded for now    
89                         color[0]= 0.8f;
90                         color[1]= 0.2f;
91                         color[2]= 0.0f;
92                         color[3]= 0.4f;
93                 }
94                 else {
95                         // greyish-red color - hardcoded for now
96                         color[0]= 0.6f;
97                         color[1]= 0.5f;
98                         color[2]= 0.5f;
99                         color[3]= 0.3f;
100                 }
101         }
102 }
103
104 /* draw the keyframes in the specified Action */
105 static void nla_action_draw_keyframes (AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax)
106 {
107         DLRBT_Tree keys;
108         ActKeyColumn *ak;
109         float xscale, f1, f2;
110         float color[4];
111         
112         /* get a list of the keyframes with NLA-scaling applied */
113         BLI_dlrbTree_init(&keys);
114         action_to_keylist(adt, act, &keys, NULL);
115         BLI_dlrbTree_linkedlist_sync(&keys);
116         
117         if ELEM(NULL, act, keys.first)
118                 return;
119         
120         /* draw a darkened region behind the strips 
121          *      - get and reset the background color, this time without the alpha to stand out better 
122          */
123         nla_action_get_color(adt, act, color);
124         glColor3fv(color);
125         /*      - draw a rect from the first to the last frame (no extra overlaps for now) 
126          *        that is slightly stumpier than the track background (hardcoded 2-units here)
127          */
128         f1= ((ActKeyColumn *)keys.first)->cfra;
129         f2= ((ActKeyColumn *)keys.last)->cfra;
130         
131         glRectf(f1, ymin+2, f2, ymax-2);
132         
133         
134         /* get View2D scaling factor */
135         UI_view2d_getscale(v2d, &xscale, NULL);
136         
137         /* for now, color is hardcoded to be black */
138         glColor3f(0.0f, 0.0f, 0.0f);
139         
140         /* just draw each keyframe as a simple dot (regardless of the selection status) 
141          *      - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction
142          */
143         for (ak= keys.first; ak; ak= ak->next)
144                 draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f);
145         
146         /* free icons */
147         BLI_dlrbTree_free(&keys);
148 }
149
150 /* Strips (Proper) ---------------------- */
151
152 /* get colors for drawing NLA-Strips */
153 static void nla_strip_get_color_inside (AnimData *adt, NlaStrip *strip, float color[3])
154 {
155         if (strip->type == NLASTRIP_TYPE_TRANSITION) {
156                 /* Transition Clip */
157                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
158                         /* selected - use a bright blue color */
159                         // FIXME: hardcoded temp-hack colors
160                         color[0]= 0.18f;
161                         color[1]= 0.46f;
162                         color[2]= 0.86f;
163                 }
164                 else {
165                         /* normal, unselected strip - use (hardly noticable) blue tinge */
166                         // FIXME: hardcoded temp-hack colors
167                         color[0]= 0.11f;
168                         color[1]= 0.15f;
169                         color[2]= 0.19f;
170                 }
171         }       
172         else if (strip->type == NLASTRIP_TYPE_META) {
173                 /* Meta Clip */
174                 // TODO: should temporary metas get different colors too?
175                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
176                         /* selected - use a bold purple color */
177                         // FIXME: hardcoded temp-hack colors
178                         color[0]= 0.41f;
179                         color[1]= 0.13f;
180                         color[2]= 0.59f;
181                 }
182                 else {
183                         /* normal, unselected strip - use (hardly noticable) dark purple tinge */
184                         // FIXME: hardcoded temp-hack colors
185                         color[0]= 0.20f;
186                         color[1]= 0.15f;
187                         color[2]= 0.26f;
188                 }
189         }       
190         else {
191                 /* Action Clip (default/normal type of strip) */
192                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) && (adt && (adt->flag & ADT_NLA_EDIT_ON))) {
193                         /* active strip should be drawn green when it is acting as the tweaking strip.
194                          * however, this case should be skipped for when not in EditMode...
195                          */
196                         // FIXME: hardcoded temp-hack colors
197                         color[0]= 0.3f;
198                         color[1]= 0.95f;
199                         color[2]= 0.1f;
200                 }
201                 else if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) {
202                         /* alert user that this strip is also used by the tweaking track (this is set when going into
203                          * 'editmode' for that strip), since the edits made here may not be what the user anticipated
204                          */
205                         // FIXME: hardcoded temp-hack colors
206                         color[0]= 0.85f;
207                         color[1]= 0.0f;
208                         color[2]= 0.0f;
209                 }
210                 else if (strip->flag & NLASTRIP_FLAG_SELECT) {
211                         /* selected strip - use theme color for selected */
212                         UI_GetThemeColor3fv(TH_STRIP_SELECT, color);
213                 }
214                 else {
215                         /* normal, unselected strip - use standard strip theme color */
216                         UI_GetThemeColor3fv(TH_STRIP, color);
217                 }
218         }
219 }
220
221 /* helper call for drawing influence/time control curves for a given NLA-strip */
222 static void nla_draw_strip_curves (NlaStrip *strip, float yminc, float ymaxc)
223 {
224         const float yheight = ymaxc - yminc;
225         
226         /* drawing color is simply a light-grey */
227         // TODO: is this color suitable?
228         // XXX nasty hacked color for now... which looks quite bad too...
229         glColor3f(0.7f, 0.7f, 0.7f);
230         
231         /* draw with AA'd line */
232         glEnable(GL_LINE_SMOOTH);
233         glEnable(GL_BLEND);
234         
235         /* influence -------------------------- */
236         if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
237                 FCurve *fcu= list_find_fcurve(&strip->fcurves, "influence", 0);
238                 float cfra;
239                 
240                 /* plot the curve (over the strip's main region) */
241                 glBegin(GL_LINE_STRIP);
242                         /* sample at 1 frame intervals, and draw 
243                          *      - min y-val is yminc, max is y-maxc, so clamp in those regions
244                          */
245                         for (cfra= strip->start; cfra <= strip->end; cfra += 1.0f) {
246                                 float y= evaluate_fcurve(fcu, cfra); // assume this to be in 0-1 range
247                                 glVertex2f(cfra, ((y*yheight)+yminc));
248                         }
249                 glEnd(); // GL_LINE_STRIP
250         }
251         else {
252                 /* use blend in/out values only if both aren't zero */
253                 if ((IS_EQ(strip->blendin, 0.0f) && IS_EQ(strip->blendout, 0.0f))==0) {
254                         glBegin(GL_LINE_STRIP);
255                                 /* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */
256                                 if (IS_EQ(strip->blendin, 0.0f) == 0) {
257                                         glVertex2f(strip->start,                                        yminc);
258                                         glVertex2f(strip->start + strip->blendin,       ymaxc);
259                                 }
260                                 else
261                                         glVertex2f(strip->start, ymaxc);
262                                         
263                                 /* end of strip */
264                                 if (IS_EQ(strip->blendout, 0.0f) == 0) {
265                                         glVertex2f(strip->end - strip->blendout,        ymaxc);
266                                         glVertex2f(strip->end,                                          yminc);
267                                 }
268                                 else
269                                         glVertex2f(strip->end, ymaxc);
270                         glEnd(); // GL_LINE_STRIP
271                 }
272         }
273         
274         /* time -------------------------- */
275         // XXX do we want to draw this curve? in a different color too?
276         
277         /* turn off AA'd lines */
278         glDisable(GL_LINE_SMOOTH);
279         glDisable(GL_BLEND);
280 }
281
282 /* main call for drawing a single NLA-strip */
283 static void nla_draw_strip (SpaceNla *snla, AnimData *adt, NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
284 {
285         float color[3];
286         
287         /* get color of strip */
288         nla_strip_get_color_inside(adt, strip, color);
289         
290         /* draw extrapolation info first (as backdrop) */
291         if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
292                 /* enable transparency... */
293                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
294                 glEnable(GL_BLEND);
295                 
296                 switch (strip->extendmode) {
297                         /* since this does both sides, only do the 'before' side, and leave the rest to the next case */
298                         case NLASTRIP_EXTEND_HOLD: 
299                                 /* only need to draw here if there's no strip before since 
300                                  * it only applies in such a situation 
301                                  */
302                                 if (strip->prev == NULL) {
303                                         /* set the drawing color to the color of the strip, but with very faint alpha */
304                                         glColor4f(color[0], color[1], color[2], 0.15f);
305                                         
306                                         /* draw the rect to the edge of the screen */
307                                         glBegin(GL_QUADS);
308                                                 glVertex2f(v2d->cur.xmin, yminc);
309                                                 glVertex2f(v2d->cur.xmin, ymaxc);
310                                                 glVertex2f(strip->start, ymaxc);
311                                                 glVertex2f(strip->start, yminc);
312                                         glEnd();
313                                 }
314                                 /* no break needed... */
315                                 
316                         /* this only draws after the strip */
317                         case NLASTRIP_EXTEND_HOLD_FORWARD: 
318                                 /* only need to try and draw if the next strip doesn't occur immediately after */
319                                 if ((strip->next == NULL) || (IS_EQ(strip->next->start, strip->end)==0)) {
320                                         /* set the drawing color to the color of the strip, but this time less faint */
321                                         glColor4f(color[0], color[1], color[2], 0.3f);
322                                         
323                                         /* draw the rect to the next strip or the edge of the screen */
324                                         glBegin(GL_QUADS);
325                                                 glVertex2f(strip->end, yminc);
326                                                 glVertex2f(strip->end, ymaxc);
327                                                 
328                                                 if (strip->next) {
329                                                         glVertex2f(strip->next->start, ymaxc);
330                                                         glVertex2f(strip->next->start, yminc);
331                                                 }
332                                                 else {
333                                                         glVertex2f(v2d->cur.xmax, ymaxc);
334                                                         glVertex2f(v2d->cur.xmax, yminc);
335                                                 }
336                                         glEnd();
337                                 }
338                                 break;
339                 }
340                 
341                 glDisable(GL_BLEND);
342         }
343         
344         /* draw 'inside' of strip itself */
345         glColor3fv(color);
346         uiSetRoundBox(15); /* all corners rounded */
347         uiDrawBoxShade(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
348         
349         
350         /* draw strip's control 'curves'
351          *      - only if user hasn't hidden them...
352          */
353         if ((snla->flag & SNLA_NOSTRIPCURVES) == 0)
354                 nla_draw_strip_curves(strip, yminc, ymaxc);
355         
356         /* draw strip outline 
357          *      - color used here is to indicate active vs non-active
358          */
359         if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
360                 /* strip should appear 'sunken', so draw a light border around it */
361                 glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
362         }
363         else {
364                 /* strip should appear to stand out, so draw a dark border around it */
365                 glColor3f(0.0f, 0.0f, 0.0f);
366         }
367         
368         /* - line style: dotted for muted */
369         if (strip->flag & NLASTRIP_FLAG_MUTED)
370                 setlinestyle(4);
371                 
372         /* draw outline */
373         uiDrawBoxShade(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
374         
375         /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
376         if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQ(strip->repeat, 1.0f)==0) {
377                 float repeatLen = (strip->actend - strip->actstart) * strip->scale;
378                 int i;
379                 
380                 /* only draw lines for whole-numbered repeats, starting from the first full-repeat
381                  * up to the last full repeat (but not if it lies on the end of the strip)
382                  */
383                 for (i = 1; i < strip->repeat; i++) {
384                         float repeatPos = strip->start + (repeatLen * i);
385                         
386                         /* don't draw if line would end up on or after the end of the strip */
387                         if (repeatPos < strip->end)
388                                 fdrawline(repeatPos, yminc+4, repeatPos, ymaxc-4);
389                 }
390         }
391         /* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
392         else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
393                 NlaStrip *cs;
394                 float y= (ymaxc-yminc)/2.0f + yminc;
395                 
396                 /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
397                 for (cs= strip->strips.first; cs; cs= cs->next) {
398                         /* draw start-line if not same as end of previous (and only if not the first strip) 
399                          *      - on upper half of strip
400                          */
401                         if ((cs->prev) && IS_EQ(cs->prev->end, cs->start)==0)
402                                 fdrawline(cs->start, y, cs->start, ymaxc);
403                                 
404                         /* draw end-line if not the last strip
405                          *      - on lower half of strip
406                          */
407                         if (cs->next) 
408                                 fdrawline(cs->end, yminc, cs->end, y);
409                 }
410         }
411         
412         /* reset linestyle */
413         setlinestyle(0);
414
415
416 /* add the relevant text to the cache of text-strings to draw in pixelspace */
417 static void nla_draw_strip_text (NlaTrack *UNUSED(nlt), NlaStrip *strip, int UNUSED(index), View2D *v2d, float yminc, float ymaxc)
418 {
419         char str[256], dir[3];
420         char col[4];
421         rctf rect;
422         
423         /* 'dir' - direction that strip is played in */
424         if (strip->flag & NLASTRIP_FLAG_REVERSE)
425                 sprintf(dir, "<-");
426         else
427                 sprintf(dir, "->");
428         
429         /* just print the name and the range */
430         if (strip->flag & NLASTRIP_FLAG_TEMP_META)
431                 sprintf(str, "Temp-Meta | %.2f %s %.2f", strip->start, dir, strip->end);
432         else
433                 sprintf(str, "%s | %.2f %s %.2f", strip->name, strip->start, dir, strip->end);
434         
435         /* set text color - if colors (see above) are light, draw black text, otherwise draw white */
436         if (strip->flag & (NLASTRIP_FLAG_ACTIVE|NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_TWEAKUSER)) {
437                 col[0]= col[1]= col[2]= 0;
438         }
439         else {
440                 col[0]= col[1]= col[2]= 255;
441         }
442         col[3]= 1.0;
443
444         /* set bounding-box for text 
445          *      - padding of 2 'units' on either side
446          */
447         // TODO: make this centered?
448         rect.xmin= strip->start + 0.5f;
449         rect.ymin= yminc;
450         rect.xmax= strip->end - 0.5f;
451         rect.ymax= ymaxc;
452         
453         /* add this string to the cache of texts to draw*/
454
455         UI_view2d_text_cache_rectf(v2d, &rect, str, col);
456 }
457
458 /* ---------------------- */
459
460 void draw_nla_main_data (bAnimContext *ac, SpaceNla *snla, ARegion *ar)
461 {
462         ListBase anim_data = {NULL, NULL};
463         bAnimListElem *ale;
464         int filter;
465         
466         View2D *v2d= &ar->v2d;
467         float y= 0.0f;
468         int items, height;
469         
470         /* build list of channels to draw */
471         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
472         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
473         
474         /* Update max-extent of channels here (taking into account scrollers):
475          *      - this is done to allow the channel list to be scrollable, but must be done here
476          *        to avoid regenerating the list again and/or also because channels list is drawn first
477          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
478          *        start of list offset, and the second is as a correction for the scrollers.
479          */
480         height= ((items*NLACHANNEL_STEP) + (NLACHANNEL_HEIGHT*2));
481         /* don't use totrect set, as the width stays the same 
482          * (NOTE: this is ok here, the configuration is pretty straightforward) 
483          */
484         v2d->tot.ymin= (float)(-height);
485         
486         /* loop through channels, and set up drawing depending on their type  */        
487         y= (float)(-NLACHANNEL_HEIGHT);
488         
489         for (ale= anim_data.first; ale; ale= ale->next) {
490                 const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF);
491                 const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF);
492                 
493                 /* check if visible */
494                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
495                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
496                 {
497                         /* data to draw depends on the type of channel */
498                         switch (ale->type) {
499                                 case ANIMTYPE_NLATRACK:
500                                 {
501                                         AnimData *adt= ale->adt;
502                                         NlaTrack *nlt= (NlaTrack *)ale->data;
503                                         NlaStrip *strip;
504                                         int index;
505                                         
506                                         /* draw each strip in the track (if visible) */
507                                         for (strip=nlt->strips.first, index=1; strip; strip=strip->next, index++) {
508                                                 if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
509                                                         /* draw the visualisation of the strip */
510                                                         nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc);
511                                                         
512                                                         /* add the text for this strip to the cache */
513                                                         nla_draw_strip_text(nlt, strip, index, v2d, yminc, ymaxc);
514                                                 }
515                                         }
516                                 }
517                                         break;
518                                         
519                                 case ANIMTYPE_NLAACTION:
520                                 {
521                                         AnimData *adt= ale->adt;
522                                         float color[4];
523                                         
524                                         /* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
525                                          * and a second darker rect within which we draw keyframe indicator dots if there's data
526                                          */
527                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
528                                         glEnable(GL_BLEND);
529                                                 
530                                         /* get colors for drawing */
531                                         nla_action_get_color(adt, ale->data, color);
532                                         glColor4fv(color);
533                                         
534                                         /* draw slightly shifted up for greater separation from standard channels,
535                                          * but also slightly shorter for some more contrast when viewing the strips
536                                          */
537                                         glRectf(v2d->cur.xmin, yminc+NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc-NLACHANNEL_SKIP);
538                                         
539                                         /* draw keyframes in the action */
540                                         nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc+NLACHANNEL_SKIP, ymaxc-NLACHANNEL_SKIP);
541                                         
542                                         /* draw 'embossed' lines above and below the strip for effect */
543                                                 /* white base-lines */
544                                         glLineWidth(2.0f);
545                                         glColor4f(1.0f, 1.0f, 1.0f, 0.3);
546                                         fdrawline(v2d->cur.xmin, yminc+NLACHANNEL_SKIP, v2d->cur.xmax, yminc+NLACHANNEL_SKIP);
547                                         fdrawline(v2d->cur.xmin, ymaxc-NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc-NLACHANNEL_SKIP);
548                                         
549                                                 /* black top-lines */
550                                         glLineWidth(1.0f);
551                                         glColor3f(0.0f, 0.0f, 0.0f);
552                                         fdrawline(v2d->cur.xmin, yminc+NLACHANNEL_SKIP, v2d->cur.xmax, yminc+NLACHANNEL_SKIP);
553                                         fdrawline(v2d->cur.xmin, ymaxc-NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc-NLACHANNEL_SKIP);
554                                         
555                                         glDisable(GL_BLEND);
556                                 }
557                                         break;
558                         }
559                 }
560                 
561                 /* adjust y-position for next one */
562                 y -= NLACHANNEL_STEP;
563         }
564         
565         /* free tempolary channels */
566         BLI_freelistN(&anim_data);
567 }
568
569 /* *********************************************** */
570 /* Channel List */
571
572 /* old code for drawing NLA channels using GL only */
573 // TODO: depreceate this code...
574 static void draw_nla_channel_list_gl (bAnimContext *ac, ListBase *anim_data, View2D *v2d, float y)
575 {
576         bAnimListElem *ale;
577         float x = 0.0f;
578         
579         /* loop through channels, and set up drawing depending on their type  */        
580         for (ale= anim_data->first; ale; ale= ale->next) {
581                 const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF);
582                 const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF);
583                 const float ydatac= (float)(y - 7);
584                 
585                 /* check if visible */
586                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
587                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
588                 {
589                         short indent= 0, offset= 0, sel= 0, group= 0;
590                         int expand= -1, protect = -1, special= -1, mute = -1;
591                         char name[128];
592                         short doDraw=0;
593                         
594                         /* determine what needs to be drawn */
595                         switch (ale->type) {
596                                 case ANIMTYPE_NLATRACK: /* NLA Track */
597                                 {
598                                         NlaTrack *nlt= (NlaTrack *)ale->data;
599                                         
600                                         indent= 0;
601                                         
602                                         if (ale->id) {
603                                                 /* special exception for materials and particles */
604                                                 if (ELEM(GS(ale->id->name),ID_MA,ID_PA)) {
605                                                         offset= 21;
606                                                         indent= 1;
607                                                 }
608                                                 else
609                                                         offset= 14;
610                                         }
611                                         else
612                                                 offset= 0;
613                                         
614                                         /* FIXME: 'solo' as the 'special' button?
615                                          *      - need special icons for these
616                                          */
617                                         if (nlt->flag & NLATRACK_SOLO)
618                                                 special= ICON_LAYER_ACTIVE;
619                                         else
620                                                 special= ICON_LAYER_USED;
621                                                 
622                                         /* if this track is active and we're tweaking it, don't draw these toggles */
623                                         // TODO: need a special macro for this...
624                                         if ( ((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0 ) 
625                                         {
626                                                 if (nlt->flag & NLATRACK_MUTED)
627                                                         mute = ICON_MUTE_IPO_ON;
628                                                 else    
629                                                         mute = ICON_MUTE_IPO_OFF;
630                                                         
631                                                 if (EDITABLE_NLT(nlt))
632                                                         protect = ICON_UNLOCKED;
633                                                 else
634                                                         protect = ICON_LOCKED;
635                                         }
636                                                 
637                                         sel = SEL_NLT(nlt);
638                                         strcpy(name, nlt->name);
639                                         
640                                         // draw manually still
641                                         doDraw= 1;
642                                 }
643                                         break;
644                                 case ANIMTYPE_NLAACTION: /* NLA Action-Line */
645                                 {
646                                         bAction *act= (bAction *)ale->data;
647                                         
648                                         group = 5;
649                                         
650                                         if (ale->id) {
651                                                 /* special exception for materials and particles */
652                                                 if (ELEM(GS(ale->id->name),ID_MA,ID_PA)) {
653                                                         offset= 21;
654                                                         indent= 1;
655                                                 }
656                                                 else
657                                                         offset= 14;
658                                         }
659                                         else
660                                                 offset= 0;
661                                         
662                                         special = ICON_ACTION;
663                                         
664                                         if (act)
665                                                 sprintf(name, "ActAction: <%s>", act->id.name+2);
666                                         else
667                                                 sprintf(name, "<No Action>");
668                                                 
669                                         // draw manually still
670                                         doDraw= 1;
671                                 }
672                                         break;
673                                         
674                                 default: /* handled by standard channel-drawing API */
675                                         // draw backdrops only...
676                                         ANIM_channel_draw(ac, ale, yminc, ymaxc);
677                                         break;
678                         }       
679                         
680                         /* if special types, draw manually for now... */
681                         if (doDraw) {
682                                 /* now, start drawing based on this information */
683                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
684                                 glEnable(GL_BLEND);
685                                 
686                                 /* draw backing strip behind channel name */
687                                 if (group == 5) {
688                                         /* Action Line */
689                                         AnimData *adt= ale->adt;
690                                         
691                                         // TODO: if tweaking some action, use the same color as for the tweaked track (quick hack done for now)
692                                         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
693                                                 // greenish color (same as tweaking strip) - hardcoded for now
694                                                 glColor3f(0.3f, 0.95f, 0.1f);
695                                         }
696                                         else {
697                                                 if (ale->data)
698                                                         glColor3f(0.8f, 0.2f, 0.0f);    // reddish color - hardcoded for now 
699                                                 else
700                                                         glColor3f(0.6f, 0.5f, 0.5f);    // greyish-red color - hardcoded for now
701                                         }
702                                         
703                                         offset += 7 * indent;
704                                         
705                                         /* only on top two corners, to show that this channel sits on top of the preceding ones */
706                                         uiSetRoundBox((1|2)); 
707                                         
708                                         /* draw slightly shifted up vertically to look like it has more separtion from other channels,
709                                          * but we then need to slightly shorten it so that it doesn't look like it overlaps
710                                          */
711                                         uiDrawBox(GL_POLYGON, x+offset,  yminc+NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc+NLACHANNEL_SKIP-1, 8);
712                                         
713                                         /* clear group value, otherwise we cause errors... */
714                                         group = 0;
715                                 }
716                                 else {
717                                         /* for normal channels 
718                                          *      - use 3 shades of color group/standard color for 3 indention level
719                                          */
720                                         UI_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40));
721                                         
722                                         indent += group;
723                                         offset += 7 * indent;
724                                         glBegin(GL_QUADS);
725                                                 glVertex2f(x+offset, yminc);
726                                                 glVertex2f(x+offset, ymaxc);
727                                                 glVertex2f((float)v2d->cur.xmax, ymaxc);
728                                                 glVertex2f((float)v2d->cur.xmax, yminc);
729                                         glEnd();
730                                 }
731                                 
732                                 /* draw expand/collapse triangle */
733                                 if (expand > 0) {
734                                         UI_icon_draw(x+offset, ydatac, expand);
735                                         offset += 17;
736                                 }
737                                 
738                                 /* draw special icon indicating certain data-types */
739                                 if (special > -1) {
740                                         /* for normal channels */
741                                         UI_icon_draw(x+offset, ydatac, special);
742                                         offset += 17;
743                                 }
744                                 glDisable(GL_BLEND);
745                                 
746                                 /* draw name */
747                                 if (sel)
748                                         UI_ThemeColor(TH_TEXT_HI);
749                                 else
750                                         UI_ThemeColor(TH_TEXT);
751                                 offset += 3;
752                                 UI_DrawString(x+offset, y-4, name);
753                                 
754                                 /* reset offset - for RHS of panel */
755                                 offset = 0;
756                                 
757                                 /* set blending again, as text drawing may clear it */
758                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
759                                 glEnable(GL_BLEND);
760                                 
761                                 /* draw protect 'lock' */
762                                 if (protect > -1) {
763                                         offset = 16;
764                                         UI_icon_draw((float)(v2d->cur.xmax-offset), ydatac, protect);
765                                 }
766                                 
767                                 /* draw mute 'eye' */
768                                 if (mute > -1) {
769                                         offset += 16;
770                                         UI_icon_draw((float)(v2d->cur.xmax-offset), ydatac, mute);
771                                 }
772                                 
773                                 /* draw NLA-action line 'status-icons' - only when there's an action */
774                                 if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) {
775                                         AnimData *adt= ale->adt;
776                                         
777                                         offset += 16;
778                                         
779                                         /* now draw some indicator icons  */
780                                         if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
781                                                 /* toggle for tweaking with mapping/no-mapping (i.e. 'in place editing' toggle) */
782                                                 // for now, use pin icon to symbolise this
783                                                 if (adt->flag & ADT_NLA_EDIT_NOMAP)
784                                                         UI_icon_draw((float)(v2d->cur.xmax-offset), ydatac, ICON_PINNED);
785                                                 else
786                                                         UI_icon_draw((float)(v2d->cur.xmax-offset), ydatac, ICON_UNPINNED);
787                                                 
788                                                 fdrawline((float)(v2d->cur.xmax-offset), yminc, 
789                                                                   (float)(v2d->cur.xmax-offset), ymaxc);
790                                                 offset += 16;
791                                                 
792                                                 /* 'tweaking action' indicator - not a button */
793                                                 UI_icon_draw((float)(v2d->cur.xmax-offset), ydatac, ICON_EDIT); 
794                                         }
795                                         else {
796                                                 /* XXX firstly draw a little rect to help identify that it's different from the toggles */
797                                                 glBegin(GL_LINE_LOOP);
798                                                         glVertex2f((float)v2d->cur.xmax-offset-1, y-7);
799                                                         glVertex2f((float)v2d->cur.xmax-offset-1, y+9);
800                                                         glVertex2f((float)v2d->cur.xmax-1, y+9);
801                                                         glVertex2f((float)v2d->cur.xmax-1, y-7);
802                                                 glEnd(); // GL_LINES
803                                                 
804                                                 /* 'push down' icon for normal active-actions */
805                                                 UI_icon_draw((float)v2d->cur.xmax-offset, ydatac, ICON_FREEZE);
806                                         }
807                                 }
808                                 
809                                 glDisable(GL_BLEND);
810                         }
811                 }
812                 
813                 /* adjust y-position for next one */
814                 y -= NLACHANNEL_STEP;
815         }
816 }
817
818 void draw_nla_channel_list (bContext *C, bAnimContext *ac, ARegion *ar)
819 {
820         ListBase anim_data = {NULL, NULL};
821         bAnimListElem *ale;
822         int filter;
823         
824         View2D *v2d= &ar->v2d;
825         float y= 0.0f;
826         int items, height;
827         
828         /* build list of channels to draw */
829         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
830         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
831         
832         /* Update max-extent of channels here (taking into account scrollers):
833          *      - this is done to allow the channel list to be scrollable, but must be done here
834          *        to avoid regenerating the list again and/or also because channels list is drawn first
835          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
836          *        start of list offset, and the second is as a correction for the scrollers.
837          */
838         height= ((items*NLACHANNEL_STEP) + (NLACHANNEL_HEIGHT*2));
839         /* don't use totrect set, as the width stays the same 
840          * (NOTE: this is ok here, the configuration is pretty straightforward) 
841          */
842         v2d->tot.ymin= (float)(-height);
843         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
844         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
845         
846         /* draw channels */
847         {       /* first pass: backdrops + oldstyle drawing */
848                 y= (float)(-NLACHANNEL_HEIGHT);
849                 
850                 draw_nla_channel_list_gl(ac, &anim_data, v2d, y);
851         }
852         {       /* second pass: UI widgets */
853                 uiBlock *block= uiBeginBlock(C, ar, "NLA channel buttons", UI_EMBOSS);
854                 
855                 y= (float)(-NLACHANNEL_HEIGHT);
856                 
857                 /* set blending again, as may not be set in previous step */
858                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
859                 glEnable(GL_BLEND);
860                 
861                 /* loop through channels, and set up drawing depending on their type  */        
862                 for (ale= anim_data.first; ale; ale= ale->next) {
863                         const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF);
864                         const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF);
865                         
866                         /* check if visible */
867                         if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
868                                  IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
869                         {
870                                 /* draw all channels using standard channel-drawing API */
871                                 ANIM_channel_draw_widgets(ac, ale, block, yminc, ymaxc);
872                         }
873                         
874                         /* adjust y-position for next one */
875                         y -= NLACHANNEL_STEP;
876                 }
877                 
878                 uiEndBlock(C, block);
879                 uiDrawBlock(C, block);
880                 
881                 glDisable(GL_BLEND);
882         }
883         
884         /* free tempolary channels */
885         BLI_freelistN(&anim_data);
886 }
887
888 /* *********************************************** */