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