Cleanup: strip trailing space in editors
[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_dlrbTree.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_fcurve.h"
49 #include "BKE_nla.h"
50 #include "BKE_context.h"
51 #include "BKE_screen.h"
52
53 #include "ED_anim_api.h"
54 #include "ED_keyframes_draw.h"
55
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58
59 #include "WM_types.h"
60
61 #include "UI_interface.h"
62 #include "UI_resources.h"
63 #include "UI_view2d.h"
64
65 #include "nla_private.h"
66 #include "nla_intern.h" /* own include */
67
68
69 /* *********************************************** */
70 /* Strips */
71
72 /* Action-Line ---------------------- */
73
74 /* get colors for drawing Action-Line
75  * NOTE: color returned includes fine-tuned alpha!
76  */
77 void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
78 {
79         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
80                 /* greenish color (same as tweaking strip) */
81                 UI_GetThemeColor4fv(TH_NLA_TWEAK, color);
82         }
83         else {
84                 if (act) {
85                         /* reddish color - same as dopesheet summary */
86                         UI_GetThemeColor4fv(TH_ANIM_ACTIVE, color);
87                 }
88                 else {
89                         /* grayish-red color */
90                         UI_GetThemeColor4fv(TH_ANIM_INACTIVE, color);
91                 }
92         }
93
94         /* when an NLA track is tagged "solo", action doesn't contribute, so shouldn't be as prominent */
95         if (adt && (adt->flag & ADT_NLA_SOLO_TRACK))
96                 color[3] *= 0.15f;
97 }
98
99 /* draw the keyframes in the specified Action */
100 static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax)
101 {
102         DLRBT_Tree keys;
103         ActKeyColumn *ak;
104         float xscale, f1, f2;
105         float color[4];
106
107         /* get a list of the keyframes with NLA-scaling applied */
108         BLI_dlrbTree_init(&keys);
109         action_to_keylist(adt, act, &keys, NULL);
110         BLI_dlrbTree_linkedlist_sync(&keys);
111
112         if (ELEM(NULL, act, keys.first))
113                 return;
114
115         /* draw a darkened region behind the strips
116          *      - get and reset the background color, this time without the alpha to stand out better
117          *        (amplified alpha is used instead)
118          */
119         nla_action_get_color(adt, act, color);
120         color[3] *= 2.5f;
121
122         glColor4fv(color);
123         /*  - draw a rect from the first to the last frame (no extra overlaps for now)
124          *        that is slightly stumpier than the track background (hardcoded 2-units here)
125          */
126         f1 = ((ActKeyColumn *)keys.first)->cfra;
127         f2 = ((ActKeyColumn *)keys.last)->cfra;
128
129         glRectf(f1, ymin + 2, f2, ymax - 2);
130
131
132         /* get View2D scaling factor */
133         UI_view2d_scale_get(v2d, &xscale, NULL);
134
135         /* for now, color is hardcoded to be black */
136         glColor3f(0.0f, 0.0f, 0.0f);
137
138         /* just draw each keyframe as a simple dot (regardless of the selection status)
139          *      - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction
140          */
141         for (ak = keys.first; ak; ak = ak->next)
142                 draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f);
143
144         /* free icons */
145         BLI_dlrbTree_free(&keys);
146 }
147
148 /* Strip Markers ------------------------ */
149
150 /* Markers inside an action strip */
151 static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
152 {
153         bAction *act = strip->act;
154         TimeMarker *marker;
155
156         if (ELEM(NULL, strip->act, strip->act->markers.first))
157                 return;
158
159         for (marker = act->markers.first; marker; marker = marker->next) {
160                 if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
161                         float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
162
163                         /* just a simple line for now */
164                         // XXX: draw a triangle instead...
165                         fdrawline(frame, yminc + 1, frame, ymaxc - 1);
166                 }
167         }
168 }
169
170 /* Markers inside a NLA-Strip */
171 static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
172 {
173         glLineWidth(2.0);
174
175         if (strip->type == NLASTRIP_TYPE_CLIP) {
176                 /* try not to be too conspicuous, while being visible enough when transforming */
177                 if (strip->flag & NLASTRIP_FLAG_SELECT)
178                         UI_ThemeColorShade(TH_STRIP_SELECT, -60);
179                 else
180                         UI_ThemeColorShade(TH_STRIP_SELECT, -40);
181
182                 setlinestyle(3);
183
184                 /* just draw the markers in this clip */
185                 nla_actionclip_draw_markers(strip, yminc, ymaxc);
186
187                 setlinestyle(0);
188         }
189         else if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
190                 /* just a solid color, so that it is very easy to spot */
191                 UI_ThemeColorShade(TH_STRIP_SELECT, 20);
192
193                 /* draw the markers in the first level of strips only (if they are actions) */
194                 for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
195                         if (nls->type == NLASTRIP_TYPE_CLIP) {
196                                 nla_actionclip_draw_markers(nls, yminc, ymaxc);
197                         }
198                 }
199         }
200
201         glLineWidth(1.0);
202 }
203
204 /* Strips (Proper) ---------------------- */
205
206 /* get colors for drawing NLA-Strips */
207 static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float color[3])
208 {
209         if (strip->type == NLASTRIP_TYPE_TRANSITION) {
210                 /* Transition Clip */
211                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
212                         /* selected - use a bright blue color */
213                         UI_GetThemeColor3fv(TH_NLA_TRANSITION_SEL, color);
214                 }
215                 else {
216                         /* normal, unselected strip - use (hardly noticeable) blue tinge */
217                         UI_GetThemeColor3fv(TH_NLA_TRANSITION, color);
218                 }
219         }
220         else if (strip->type == NLASTRIP_TYPE_META) {
221                 /* Meta Clip */
222                 // TODO: should temporary metas get different colors too?
223                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
224                         /* selected - use a bold purple color */
225                         UI_GetThemeColor3fv(TH_NLA_META_SEL, color);
226                 }
227                 else {
228                         /* normal, unselected strip - use (hardly noticeable) dark purple tinge */
229                         UI_GetThemeColor3fv(TH_NLA_META, color);
230                 }
231         }
232         else if (strip->type == NLASTRIP_TYPE_SOUND) {
233                 /* Sound Clip */
234                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
235                         /* selected - use a bright teal color */
236                         UI_GetThemeColor3fv(TH_NLA_SOUND_SEL, color);
237                 }
238                 else {
239                         /* normal, unselected strip - use (hardly noticeable) teal tinge */
240                         UI_GetThemeColor3fv(TH_NLA_SOUND, color);
241                 }
242         }
243         else {
244                 /* Action Clip (default/normal type of strip) */
245                 if (adt && (adt->flag & ADT_NLA_EDIT_ON) && (adt->actstrip == strip)) {
246                         /* active strip should be drawn green when it is acting as the tweaking strip.
247                          * however, this case should be skipped for when not in EditMode...
248                          */
249                         UI_GetThemeColor3fv(TH_NLA_TWEAK, color);
250                 }
251                 else if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) {
252                         /* alert user that this strip is also used by the tweaking track (this is set when going into
253                          * 'editmode' for that strip), since the edits made here may not be what the user anticipated
254                          */
255                         UI_GetThemeColor3fv(TH_NLA_TWEAK_DUPLI, color);
256                 }
257                 else if (strip->flag & NLASTRIP_FLAG_SELECT) {
258                         /* selected strip - use theme color for selected */
259                         UI_GetThemeColor3fv(TH_STRIP_SELECT, color);
260                 }
261                 else {
262                         /* normal, unselected strip - use standard strip theme color */
263                         UI_GetThemeColor3fv(TH_STRIP, color);
264                 }
265         }
266 }
267
268 /* helper call for drawing influence/time control curves for a given NLA-strip */
269 static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
270 {
271         const float yheight = ymaxc - yminc;
272
273         /* drawing color is simply a light-gray */
274         // TODO: is this color suitable?
275         // XXX nasty hacked color for now... which looks quite bad too...
276         glColor3f(0.7f, 0.7f, 0.7f);
277
278         /* draw with AA'd line */
279         glEnable(GL_LINE_SMOOTH);
280         glEnable(GL_BLEND);
281
282         /* influence -------------------------- */
283         if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
284                 FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
285                 float cfra;
286
287                 /* plot the curve (over the strip's main region) */
288                 if (fcu) {
289                         glBegin(GL_LINE_STRIP);
290
291                         /* sample at 1 frame intervals, and draw
292                          *      - min y-val is yminc, max is y-maxc, so clamp in those regions
293                          */
294                         for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
295                                 float y = evaluate_fcurve(fcu, cfra);
296                                 CLAMP(y, 0.0f, 1.0f);
297                                 glVertex2f(cfra, ((y * yheight) + yminc));
298                         }
299
300                         glEnd(); // GL_LINE_STRIP
301                 }
302         }
303         else {
304                 /* use blend in/out values only if both aren't zero */
305                 if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
306                         glBegin(GL_LINE_STRIP);
307                         /* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */
308                         if (IS_EQF(strip->blendin, 0.0f) == 0) {
309                                 glVertex2f(strip->start,                    yminc);
310                                 glVertex2f(strip->start + strip->blendin,   ymaxc);
311                         }
312                         else
313                                 glVertex2f(strip->start, ymaxc);
314
315                         /* end of strip */
316                         if (IS_EQF(strip->blendout, 0.0f) == 0) {
317                                 glVertex2f(strip->end - strip->blendout,    ymaxc);
318                                 glVertex2f(strip->end,                      yminc);
319                         }
320                         else
321                                 glVertex2f(strip->end, ymaxc);
322                         glEnd(); // GL_LINE_STRIP
323                 }
324         }
325
326         /* time -------------------------- */
327         // XXX do we want to draw this curve? in a different color too?
328
329         /* turn off AA'd lines */
330         glDisable(GL_LINE_SMOOTH);
331         glDisable(GL_BLEND);
332 }
333
334 /* main call for drawing a single NLA-strip */
335 static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
336 {
337         const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
338         float color[3];
339
340         /* get color of strip */
341         nla_strip_get_color_inside(adt, strip, color);
342
343         /* draw extrapolation info first (as backdrop)
344          *      - but this should only be drawn if track has some contribution
345          */
346         if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) {
347                 /* enable transparency... */
348                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
349                 glEnable(GL_BLEND);
350
351                 switch (strip->extendmode) {
352                         /* since this does both sides, only do the 'before' side, and leave the rest to the next case */
353                         case NLASTRIP_EXTEND_HOLD:
354                                 /* only need to draw here if there's no strip before since
355                                  * it only applies in such a situation
356                                  */
357                                 if (strip->prev == NULL) {
358                                         /* set the drawing color to the color of the strip, but with very faint alpha */
359                                         glColor4f(color[0], color[1], color[2], 0.15f);
360
361                                         /* draw the rect to the edge of the screen */
362                                         glBegin(GL_QUADS);
363                                         glVertex2f(v2d->cur.xmin, yminc);
364                                         glVertex2f(v2d->cur.xmin, ymaxc);
365                                         glVertex2f(strip->start, ymaxc);
366                                         glVertex2f(strip->start, yminc);
367                                         glEnd();
368                                 }
369                                 ATTR_FALLTHROUGH;
370
371                         /* this only draws after the strip */
372                         case NLASTRIP_EXTEND_HOLD_FORWARD:
373                                 /* only need to try and draw if the next strip doesn't occur immediately after */
374                                 if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) {
375                                         /* set the drawing color to the color of the strip, but this time less faint */
376                                         glColor4f(color[0], color[1], color[2], 0.3f);
377
378                                         /* draw the rect to the next strip or the edge of the screen */
379                                         glBegin(GL_QUADS);
380                                         glVertex2f(strip->end, yminc);
381                                         glVertex2f(strip->end, ymaxc);
382
383                                         if (strip->next) {
384                                                 glVertex2f(strip->next->start, ymaxc);
385                                                 glVertex2f(strip->next->start, yminc);
386                                         }
387                                         else {
388                                                 glVertex2f(v2d->cur.xmax, ymaxc);
389                                                 glVertex2f(v2d->cur.xmax, yminc);
390                                         }
391                                         glEnd();
392                                 }
393                                 break;
394                 }
395
396                 glDisable(GL_BLEND);
397         }
398
399
400         /* draw 'inside' of strip itself */
401         if (non_solo == 0) {
402                 /* strip is in normal track */
403                 glColor3fv(color);
404                 UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
405
406                 UI_draw_roundbox_shade_x(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
407         }
408         else {
409                 /* strip is in disabled track - make less visible */
410                 glColor4f(color[0], color[1], color[2], 0.1f);
411
412                 glEnable(GL_BLEND);
413                 glRectf(strip->start, yminc, strip->end, ymaxc);
414                 glDisable(GL_BLEND);
415         }
416
417
418         /* draw strip's control 'curves'
419          *      - only if user hasn't hidden them...
420          */
421         if ((snla->flag & SNLA_NOSTRIPCURVES) == 0)
422                 nla_draw_strip_curves(strip, yminc, ymaxc);
423
424
425         /* draw markings indicating locations of local markers (useful for lining up different actions) */
426         if ((snla->flag & SNLA_NOLOCALMARKERS) == 0)
427                 nla_strip_draw_markers(strip, yminc, ymaxc);
428
429         /* draw strip outline
430          *      - color used here is to indicate active vs non-active
431          */
432         if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
433                 /* strip should appear 'sunken', so draw a light border around it */
434                 glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
435         }
436         else {
437                 /* strip should appear to stand out, so draw a dark border around it */
438                 glColor3f(0.0f, 0.0f, 0.0f);
439         }
440
441         /* - line style: dotted for muted */
442         if ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED))
443                 setlinestyle(4);
444
445         /* draw outline */
446         UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
447
448         /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
449         if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) {
450                 float repeatLen = (strip->actend - strip->actstart) * strip->scale;
451                 int i;
452
453                 /* only draw lines for whole-numbered repeats, starting from the first full-repeat
454                  * up to the last full repeat (but not if it lies on the end of the strip)
455                  */
456                 for (i = 1; i < strip->repeat; i++) {
457                         float repeatPos = strip->start + (repeatLen * i);
458
459                         /* don't draw if line would end up on or after the end of the strip */
460                         if (repeatPos < strip->end)
461                                 fdrawline(repeatPos, yminc + 4, repeatPos, ymaxc - 4);
462                 }
463         }
464         /* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
465         else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
466                 NlaStrip *cs;
467                 float y = (ymaxc - yminc) / 2.0f + yminc;
468
469                 /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
470                 for (cs = strip->strips.first; cs; cs = cs->next) {
471                         /* draw start-line if not same as end of previous (and only if not the first strip)
472                          *      - on upper half of strip
473                          */
474                         if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0)
475                                 fdrawline(cs->start, y, cs->start, ymaxc);
476
477                         /* draw end-line if not the last strip
478                          *      - on lower half of strip
479                          */
480                         if (cs->next)
481                                 fdrawline(cs->end, yminc, cs->end, y);
482                 }
483         }
484
485         /* reset linestyle */
486         setlinestyle(0);
487 }
488
489 /* add the relevant text to the cache of text-strings to draw in pixelspace */
490 static void nla_draw_strip_text(
491         AnimData *adt, NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d,
492         float xminc, float xmaxc, float yminc, float ymaxc)
493 {
494         const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
495         char str[256];
496         size_t str_len;
497         char col[4];
498         rctf rect;
499
500         /* just print the name and the range */
501         if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
502                 str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
503         }
504         else {
505                 str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
506         }
507
508         /* set text color - if colors (see above) are light, draw black text, otherwise draw white */
509         if (strip->flag & (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_TWEAKUSER)) {
510                 col[0] = col[1] = col[2] = 0;
511         }
512         else {
513                 col[0] = col[1] = col[2] = 255;
514         }
515
516         /* text opacity depends on whether if there's a solo'd track, this isn't it */
517         if (non_solo == 0)
518                 col[3] = 255;
519         else
520                 col[3] = 128;
521
522         /* set bounding-box for text
523          *      - padding of 2 'units' on either side
524          */
525         // TODO: make this centered?
526         rect.xmin = xminc;
527         rect.ymin = yminc;
528         rect.xmax = xmaxc;
529         rect.ymax = ymaxc;
530
531         /* add this string to the cache of texts to draw */
532         UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
533 }
534
535 /* add frame extents to cache of text-strings to draw in pixelspace
536  * for now, only used when transforming strips
537  */
538 static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float UNUSED(yminc), float ymaxc)
539 {
540         const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */
541         const char col[4] = {220, 220, 220, 255}; /* light gray */
542         char numstr[32];
543         size_t numstr_len;
544
545
546         /* Always draw times above the strip, whereas sequencer drew below + above.
547          * However, we should be fine having everything on top, since these tend to be
548          * quite spaced out.
549          *      - 1 dp is compromise between lack of precision (ints only, as per sequencer)
550          *        while also preserving some accuracy, since we do use floats
551          */
552         /* start frame */
553         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
554         UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
555
556         /* end frame */
557         numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end);
558         UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
559 }
560
561 /* ---------------------- */
562
563 void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
564 {
565         ListBase anim_data = {NULL, NULL};
566         bAnimListElem *ale;
567         int filter;
568
569         View2D *v2d = &ar->v2d;
570         float y = 0.0f;
571         size_t items;
572         int height;
573         const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
574         const float text_margin_x = (8 * UI_DPI_FAC) * pixelx;
575
576         /* build list of channels to draw */
577         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
578         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
579
580         /* Update max-extent of channels here (taking into account scrollers):
581          *  - this is done to allow the channel list to be scrollable, but must be done here
582          *    to avoid regenerating the list again and/or also because channels list is drawn first
583          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
584          *        start of list offset, and the second is as a correction for the scrollers.
585          */
586         height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
587         /* don't use totrect set, as the width stays the same
588          * (NOTE: this is ok here, the configuration is pretty straightforward)
589          */
590         v2d->tot.ymin = (float)(-height);
591
592         /* loop through channels, and set up drawing depending on their type  */
593         y = (float)(-NLACHANNEL_HEIGHT(snla));
594
595         for (ale = anim_data.first; ale; ale = ale->next) {
596                 const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
597                 const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
598
599                 /* check if visible */
600                 if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
601                     IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
602                 {
603                         /* data to draw depends on the type of channel */
604                         switch (ale->type) {
605                                 case ANIMTYPE_NLATRACK:
606                                 {
607                                         AnimData *adt = ale->adt;
608                                         NlaTrack *nlt = (NlaTrack *)ale->data;
609                                         NlaStrip *strip;
610                                         int index;
611
612                                         /* draw each strip in the track (if visible) */
613                                         for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
614                                                 if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
615                                                         const float xminc = strip->start + text_margin_x;
616                                                         const float xmaxc = strip->end + text_margin_x;
617
618                                                         /* draw the visualization of the strip */
619                                                         nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc);
620
621                                                         /* add the text for this strip to the cache */
622                                                         if (xminc < xmaxc) {
623                                                                 nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, yminc, ymaxc);
624                                                         }
625
626                                                         /* if transforming strips (only real reason for temp-metas currently),
627                                                          * add to the cache the frame numbers of the strip's extents
628                                                          */
629                                                         if (strip->flag & NLASTRIP_FLAG_TEMP_META)
630                                                                 nla_draw_strip_frames_text(nlt, strip, v2d, yminc, ymaxc);
631                                                 }
632                                         }
633                                         break;
634                                 }
635                                 case ANIMTYPE_NLAACTION:
636                                 {
637                                         AnimData *adt = ale->adt;
638                                         float color[4];
639
640                                         /* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
641                                          * and a second darker rect within which we draw keyframe indicator dots if there's data
642                                          */
643                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
644                                         glEnable(GL_BLEND);
645
646                                         /* get colors for drawing */
647                                         nla_action_get_color(adt, ale->data, color);
648                                         glColor4fv(color);
649
650                                         /* draw slightly shifted up for greater separation from standard channels,
651                                          * but also slightly shorter for some more contrast when viewing the strips
652                                          */
653                                         glRectf(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
654
655                                         /* draw keyframes in the action */
656                                         nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
657
658                                         /* draw 'embossed' lines above and below the strip for effect */
659                                         /* white base-lines */
660                                         glLineWidth(2.0f);
661                                         glColor4f(1.0f, 1.0f, 1.0f, 0.3);
662                                         fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
663                                         fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
664
665                                         /* black top-lines */
666                                         glLineWidth(1.0f);
667                                         glColor3f(0.0f, 0.0f, 0.0f);
668                                         fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
669                                         fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
670
671                                         glDisable(GL_BLEND);
672                                         break;
673                                 }
674                         }
675                 }
676
677                 /* adjust y-position for next one */
678                 y -= NLACHANNEL_STEP(snla);
679         }
680
681         /* free tempolary channels */
682         ANIM_animdata_freelist(&anim_data);
683 }
684
685 /* *********************************************** */
686 /* Channel List */
687
688 void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
689 {
690         ListBase anim_data = {NULL, NULL};
691         bAnimListElem *ale;
692         int filter;
693
694         SpaceNla *snla = (SpaceNla *)ac->sl;
695         View2D *v2d = &ar->v2d;
696         float y = 0.0f;
697         size_t items;
698         int height;
699
700         /* build list of channels to draw */
701         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
702         items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
703
704         /* Update max-extent of channels here (taking into account scrollers):
705          *  - this is done to allow the channel list to be scrollable, but must be done here
706          *    to avoid regenerating the list again and/or also because channels list is drawn first
707          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
708          *        start of list offset, and the second is as a correction for the scrollers.
709          */
710         height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
711         /* don't use totrect set, as the width stays the same
712          * (NOTE: this is ok here, the configuration is pretty straightforward)
713          */
714         v2d->tot.ymin = (float)(-height);
715         /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
716         UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
717
718         /* draw channels */
719         {   /* first pass: just the standard GL-drawing for backdrop + text */
720                 size_t channel_index = 0;
721
722                 y = (float)(-NLACHANNEL_HEIGHT(snla));
723
724                 for (ale = anim_data.first; ale; ale = ale->next) {
725                         float yminc = (float)(y -  NLACHANNEL_HEIGHT_HALF(snla));
726                         float ymaxc = (float)(y +  NLACHANNEL_HEIGHT_HALF(snla));
727
728                         /* check if visible */
729                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
730                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
731                         {
732                                 /* draw all channels using standard channel-drawing API */
733                                 ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
734                         }
735
736                         /* adjust y-position for next one */
737                         y -= NLACHANNEL_STEP(snla);
738                         channel_index++;
739                 }
740         }
741         {   /* second pass: UI widgets */
742                 uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
743                 size_t channel_index = 0;
744
745                 y = (float)(-NLACHANNEL_HEIGHT(snla));
746
747                 /* set blending again, as may not be set in previous step */
748                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
749                 glEnable(GL_BLEND);
750
751                 /* loop through channels, and set up drawing depending on their type  */
752                 for (ale = anim_data.first; ale; ale = ale->next) {
753                         const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
754                         const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
755
756                         /* check if visible */
757                         if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
758                             IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
759                         {
760                                 /* draw all channels using standard channel-drawing API */
761                                 ANIM_channel_draw_widgets(C, ac, ale, block, yminc, ymaxc, channel_index);
762                         }
763
764                         /* adjust y-position for next one */
765                         y -= NLACHANNEL_STEP(snla);
766                         channel_index++;
767                 }
768
769                 UI_block_end(C, block);
770                 UI_block_draw(C, block);
771
772                 glDisable(GL_BLEND);
773         }
774
775         /* free temporary channels */
776         ANIM_animdata_freelist(&anim_data);
777 }
778
779 /* *********************************************** */