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