NLA SoC: Start of integration of Meta-strips in Transform
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung (major recode)
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <float.h>
34
35 #include "DNA_listBase.h"
36 #include "DNA_anim_types.h"
37 #include "DNA_action_types.h"
38 #include "DNA_armature_types.h"
39 #include "DNA_camera_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_screen_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_lamp_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_userdef_types.h"
50 #include "DNA_windowmanager_types.h"
51 #include "DNA_world_types.h"
52 #include "DNA_vec_types.h"
53
54 #include "MEM_guardedalloc.h"
55
56 #include "BLI_blenlib.h"
57 #include "BLI_arithb.h"
58 #include "BLI_rand.h"
59
60 #include "BKE_animsys.h"
61 #include "BKE_nla.h"
62 #include "BKE_context.h"
63 #include "BKE_screen.h"
64 #include "BKE_utildefines.h"
65
66 #include "ED_anim_api.h"
67 #include "ED_keyframes_draw.h"
68 #include "ED_space_api.h"
69 #include "ED_screen.h"
70
71 #include "BIF_gl.h"
72 #include "BIF_glutil.h"
73
74 #include "WM_api.h"
75 #include "WM_types.h"
76
77 #include "UI_interface.h"
78 #include "UI_interface_icons.h"
79 #include "UI_resources.h"
80 #include "UI_view2d.h"
81
82 #include "ED_markers.h"
83
84 #include "nla_intern.h" // own include
85
86 /* XXX */
87 extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad);
88 extern void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
89
90 /* *********************************************** */
91 /* Strips */
92
93 /* Keyframe Ghosts ---------------------- */
94
95 /* helper func - draw keyframe as a frame only */
96 static void draw_nla_keyframe_ghost (float x, float y, float xscale, float hsize)
97 {
98         static GLuint displist=0;
99         
100         /* initialise empty diamond shape */
101         if (displist == 0) {
102                 const float dist= 1.0f;
103                 
104                 displist= glGenLists(1);
105                 glNewList(displist, GL_COMPILE);
106                 
107                 glBegin(GL_LINE_LOOP);
108                         glVertex2f(0.0f,  dist);
109                         glVertex2f(dist,  0.0f);
110                         glVertex2f(0.0f, -dist);
111                         glVertex2f(-dist, 0.0f);
112                 glEnd();
113                 
114                 glEndList();
115         }
116         
117         /* adjust view transform before starting */
118         glTranslatef(x, y, 0.0f);
119         glScalef(1.0f/xscale*hsize, hsize, 1.0f);
120         
121         /* anti-aliased lines for more consistent appearance */
122         glEnable(GL_LINE_SMOOTH);
123         
124         /* draw! */
125         glCallList(displist);
126         
127         glDisable(GL_LINE_SMOOTH);
128         
129         /* restore view transform */
130         glScalef(xscale/hsize, 1.0f/hsize, 1.0);
131         glTranslatef(-x, -y, 0.0f);
132 }
133
134 /* draw the keyframes in the specified Action */
135 static void nla_action_draw_keyframes (AnimData *adt, View2D *v2d, float y)
136 {
137         ListBase keys = {NULL, NULL};
138         ActKeyColumn *ak;
139         float xscale;
140         
141         /* for now, color is hardcoded to be black */
142         glColor3f(0.0f, 0.0f, 0.0f);
143         
144         /* get a list of the keyframes with NLA-scaling applied */
145         action_nlascaled_to_keylist(adt, adt->action, &keys, NULL, NULL);
146         
147         /* get View2D scaling factor */
148         UI_view2d_getscale(v2d, &xscale, NULL);
149         
150         /* just draw each keyframe as a simple dot (regardless of the selection status) */
151         for (ak= keys.first; ak; ak= ak->next)
152                 draw_nla_keyframe_ghost(ak->cfra, y, xscale, 3.0f);
153         
154         /* free icons */
155         BLI_freelistN(&keys);
156 }
157
158 /* Strips (Proper) ---------------------- */
159
160 static void nla_strip_get_color_inside (AnimData *adt, NlaStrip *strip, float color[3])
161 {
162         if (strip->type == NLASTRIP_TYPE_TRANSITION) {
163                 /* Transition Clip */
164                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
165                         /* selected - use a bright blue color */
166                         // FIXME: hardcoded temp-hack colors
167                         color[0]= 0.18f;
168                         color[1]= 0.46f;
169                         color[2]= 0.86f;
170                 }
171                 else {
172                         /* normal, unselected strip - use (hardly noticable) blue tinge */
173                         // FIXME: hardcoded temp-hack colors
174                         color[0]= 0.11f;
175                         color[1]= 0.15f;
176                         color[2]= 0.19f;
177                 }
178         }       
179         else if (strip->type == NLASTRIP_TYPE_META) {
180                 /* Meta Clip */
181                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
182                         /* selected - use a bold purple color */
183                         // FIXME: hardcoded temp-hack colors
184                         color[0]= 0.41f;
185                         color[1]= 0.13f;
186                         color[2]= 0.59f;
187                 }
188                 else {
189                         /* normal, unselected strip - use (hardly noticable) dark purple tinge */
190                         // FIXME: hardcoded temp-hack colors
191                         color[0]= 0.20f;
192                         color[1]= 0.15f;
193                         color[2]= 0.26f;
194                 }
195         }       
196         else {
197                 /* Action Clip (default/normal type of strip) */
198                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) && (adt && (adt->flag & ADT_NLA_EDIT_ON))) {
199                         /* active strip should be drawn green when it is acting as the tweaking strip.
200                          * however, this case should be skipped for when not in EditMode...
201                          */
202                         // FIXME: hardcoded temp-hack colors
203                         color[0]= 0.3f;
204                         color[1]= 0.95f;
205                         color[2]= 0.1f;
206                 }
207                 else if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) {
208                         /* alert user that this strip is also used by the tweaking track (this is set when going into
209                          * 'editmode' for that strip), since the edits made here may not be what the user anticipated
210                          */
211                         // FIXME: hardcoded temp-hack colors
212                         color[0]= 0.85f;
213                         color[1]= 0.0f;
214                         color[2]= 0.0f;
215                 }
216                 else if (strip->flag & NLASTRIP_FLAG_SELECT) {
217                         /* selected strip - use theme color for selected */
218                         UI_GetThemeColor3fv(TH_STRIP_SELECT, color);
219                 }
220                 else {
221                         /* normal, unselected strip - use standard strip theme color */
222                         UI_GetThemeColor3fv(TH_STRIP, color);
223                 }
224         }
225 }
226
227 static void nla_draw_strip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
228 {
229         float color[3];
230         
231         /* get color of strip */
232         nla_strip_get_color_inside(adt, strip, color);
233         
234         /* draw extrapolation info first (as backdrop) */
235         if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
236                 /* enable transparency... */
237                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
238                 glEnable(GL_BLEND);
239                 
240                 switch (strip->extendmode) {
241                         /* since this does both sides, only do the 'before' side, and leave the rest to the next case */
242                         case NLASTRIP_EXTEND_HOLD: 
243                                 /* only need to draw here if there's no strip before since 
244                                  * it only applies in such a situation 
245                                  */
246                                 if (strip->prev == NULL) {
247                                         /* set the drawing color to the color of the strip, but with very faint alpha */
248                                         glColor4f(color[0], color[1], color[2], 0.15f);
249                                         
250                                         /* draw the rect to the edge of the screen */
251                                         glBegin(GL_QUADS);
252                                                 glVertex2f(v2d->cur.xmin, yminc);
253                                                 glVertex2f(v2d->cur.xmin, ymaxc);
254                                                 glVertex2f(strip->start, ymaxc);
255                                                 glVertex2f(strip->start, yminc);
256                                         glEnd();
257                                 }
258                                 /* no break needed... */
259                                 
260                         /* this only draws after the strip */
261                         case NLASTRIP_EXTEND_HOLD_FORWARD: 
262                                 /* only need to try and draw if the next strip doesn't occur immediately after */
263                                 if ((strip->next == NULL) || (IS_EQ(strip->next->start, strip->end)==0)) {
264                                         /* set the drawing color to the color of the strip, but this time less faint */
265                                         glColor4f(color[0], color[1], color[2], 0.3f);
266                                         
267                                         /* draw the rect to the next strip or the edge of the screen */
268                                         glBegin(GL_QUADS);
269                                                 glVertex2f(strip->end, yminc);
270                                                 glVertex2f(strip->end, ymaxc);
271                                                 
272                                                 if (strip->next) {
273                                                         glVertex2f(strip->next->start, ymaxc);
274                                                         glVertex2f(strip->next->start, yminc);
275                                                 }
276                                                 else {
277                                                         glVertex2f(v2d->cur.xmax, ymaxc);
278                                                         glVertex2f(v2d->cur.xmax, yminc);
279                                                 }
280                                         glEnd();
281                                 }
282                                 break;
283                 }
284                 
285                 glDisable(GL_BLEND);
286         }
287         
288         /* draw 'inside' of strip itself */
289         glColor3fv(color);
290         uiSetRoundBox(15); /* all corners rounded */
291         gl_round_box_shade(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
292         
293         
294         /* draw strip outline 
295          *      - color used here is to indicate active vs non-active
296          */
297         if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
298                 /* strip should appear 'sunken', so draw a light border around it */
299                 glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
300         }
301         else {
302                 /* strip should appear to stand out, so draw a dark border around it */
303                 glColor3f(0.0f, 0.0f, 0.0f);
304         }
305         
306         /* - line style: dotted for muted */
307         if (strip->flag & NLASTRIP_FLAG_MUTED)
308                 setlinestyle(4);
309                 
310         /* draw outline */
311         gl_round_box_shade(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
312         
313         /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
314         if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQ(strip->repeat, 1.0f)==0) {
315                 float repeatLen = (strip->actend - strip->actstart) * strip->scale;
316                 int i;
317                 
318                 /* only draw lines for whole-numbered repeats, starting from the first full-repeat
319                  * up to the last full repeat (but not if it lies on the end of the strip)
320                  */
321                 for (i = 1; i < strip->repeat; i++) {
322                         float repeatPos = strip->start + (repeatLen * i);
323                         
324                         /* don't draw if line would end up on or after the end of the strip */
325                         if (repeatPos < strip->end)
326                                 fdrawline(repeatPos, yminc, repeatPos, ymaxc);
327                 }
328         }
329         /* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
330         else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
331                 NlaStrip *cs;
332                 float y= (ymaxc-yminc)/2.0f + yminc;
333                 
334                 /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
335                 for (cs= strip->strips.first; cs; cs= cs->next) {
336                         /* draw start-line if not same as end of previous (and only if not the first strip) 
337                          *      - on upper half of strip
338                          */
339                         if ((cs->prev) && IS_EQ(cs->prev->end, cs->start)==0)
340                                 fdrawline(cs->start, y, cs->start, ymaxc);
341                                 
342                         /* draw end-line if not the last strip
343                          *      - on lower half of strip
344                          */
345                         if (cs->next) 
346                                 fdrawline(cs->end, yminc, cs->end, y);
347                 }
348         }
349         
350         /* reset linestyle */
351         setlinestyle(0);
352
353
354 /* add the relevant text to the cache of text-strings to draw in pixelspace */
355 static void nla_draw_strip_text (NlaTrack *nlt, NlaStrip *strip, int index, View2D *v2d, float yminc, float ymaxc)
356 {
357         char str[256], dir[3];
358         rctf rect;
359         
360         /* 'dir' - direction that strip is played in */
361         if (strip->flag & NLASTRIP_FLAG_REVERSE)
362                 sprintf(dir, "<-");
363         else
364                 sprintf(dir, "->");
365         
366         /* for now, just init the string with fixed-formats */
367         switch (strip->type) {
368                 case NLASTRIP_TYPE_TRANSITION: /* Transition */
369                         sprintf(str, "%d | Transition | %.2f %s %.2f", 
370                                 index, strip->start, dir, strip->end);
371                         break;
372                         
373                 case NLASTRIP_TYPE_META: /* Meta */
374                         sprintf(str, "%d | %sMeta | %.2f %s %.2f", 
375                                 index, ((strip->flag & NLASTRIP_FLAG_TEMP_META)?"Temp-":""), 
376                                 strip->start, dir, strip->end);
377                         break;
378                 
379                 case NLASTRIP_TYPE_CLIP:        /* Action-Clip (default) */
380                 default:
381                         if (strip->act)
382                                 sprintf(str, "%d | Act: %s | %.2f %s %.2f", 
383                                         index, strip->act->id.name+2, strip->start, dir, strip->end);
384                         else
385                                 sprintf(str, "%d | Act: <NONE>", index); // xxx... need a better format?
386                         break;
387         }
388         
389         /* set text colour - if colours (see above) are light, draw black text, otherwise draw white */
390         if (strip->flag & (NLASTRIP_FLAG_ACTIVE|NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_TWEAKUSER))
391                 glColor3f(0.0f, 0.0f, 0.0f);
392         else
393                 glColor3f(1.0f, 1.0f, 1.0f);
394         
395         /* set bounding-box for text 
396          *      - padding of 2 'units' on either side
397          */
398         // TODO: make this centered?
399         rect.xmin= strip->start + 2;
400         rect.ymin= yminc;
401         rect.xmax= strip->end - 2;
402         rect.ymax= ymaxc;
403         
404         /* add this string to the cache of texts to draw*/
405         UI_view2d_text_cache_rectf(v2d, &rect, str);
406 }
407
408 /* ---------------------- */
409
410 void draw_nla_main_data (bAnimContext *ac, SpaceNla *snla, ARegion *ar)
411 {
412         ListBase anim_data = {NULL, NULL};
413         bAnimListElem *ale;
414         int filter;
415         
416         View2D *v2d= &ar->v2d;
417         float y= 0.0f;
418         int items, height;
419         
420         /* build list of channels to draw */
421         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
422         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
423         
424         /* Update max-extent of channels here (taking into account scrollers):
425          *      - this is done to allow the channel list to be scrollable, but must be done here
426          *        to avoid regenerating the list again and/or also because channels list is drawn first
427          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
428          *        start of list offset, and the second is as a correction for the scrollers.
429          */
430         height= ((items*NLACHANNEL_STEP) + (NLACHANNEL_HEIGHT*2));
431         /* don't use totrect set, as the width stays the same 
432          * (NOTE: this is ok here, the configuration is pretty straightforward) 
433          */
434         v2d->tot.ymin= (float)(-height);
435         
436         /* loop through channels, and set up drawing depending on their type  */        
437         y= (float)(-NLACHANNEL_HEIGHT);
438         
439         for (ale= anim_data.first; ale; ale= ale->next) {
440                 const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF);
441                 const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF);
442                 
443                 /* check if visible */
444                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
445                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
446                 {
447                         /* data to draw depends on the type of channel */
448                         switch (ale->type) {
449                                 case ANIMTYPE_NLATRACK:
450                                 {
451                                         AnimData *adt= BKE_animdata_from_id(ale->id);
452                                         NlaTrack *nlt= (NlaTrack *)ale->data;
453                                         NlaStrip *strip;
454                                         int index;
455                                         
456                                         /* draw each strip in the track (if visible) */
457                                         for (strip=nlt->strips.first, index=1; strip; strip=strip->next, index++) {
458                                                 if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
459                                                         /* draw the visualisation of the strip */
460                                                         nla_draw_strip(adt, nlt, strip, v2d, yminc, ymaxc);
461                                                         
462                                                         /* add the text for this strip to the cache */
463                                                         nla_draw_strip_text(nlt, strip, index, v2d, yminc, ymaxc);
464                                                 }
465                                         }
466                                 }
467                                         break;
468                                         
469                                 case ANIMTYPE_NLAACTION:
470                                 {
471                                         AnimData *adt= BKE_animdata_from_id(ale->id);
472                                         
473                                         /* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
474                                          * and a second darker rect within which we draw keyframe indicator dots if there's data
475                                          */
476                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
477                                         glEnable(GL_BLEND);
478                                                 
479                                         // TODO: if tweaking some action, use the same color as for the tweaked track (quick hack done for now)
480                                         if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
481                                                 // greenish color (same as tweaking strip) - hardcoded for now
482                                                 glColor4f(0.3f, 0.95f, 0.1f, 0.3f);
483                                         }
484                                         else {
485                                                 if (ale->data)
486                                                         glColor4f(0.8f, 0.2f, 0.0f, 0.4f);      // reddish color - hardcoded for now 
487                                                 else
488                                                         glColor4f(0.6f, 0.5f, 0.5f, 0.3f);      // greyish-red color - hardcoded for now
489                                         }
490                                                 
491                                         /* draw slightly shifted up for greater separation from standard channels,
492                                          * but also slightly shorter for some more contrast when viewing the strips
493                                          */
494                                         glBegin(GL_QUADS);
495                                                 glVertex2f(v2d->cur.xmin, yminc+NLACHANNEL_SKIP);
496                                                 glVertex2f(v2d->cur.xmin, ymaxc-NLACHANNEL_SKIP);
497                                                 glVertex2f(v2d->cur.xmax, ymaxc-NLACHANNEL_SKIP);
498                                                 glVertex2f(v2d->cur.xmax, yminc+NLACHANNEL_SKIP);
499                                         glEnd();
500                                         
501                                         /* draw keyframes in the action */
502                                         nla_action_draw_keyframes(adt, v2d, y);
503                                         
504                                         /* draw 'embossed' lines above and below the strip for effect */
505                                                 /* white base-lines */
506                                         glLineWidth(2.0f);
507                                         glColor4f(1.0f, 1.0f, 1.0f, 0.3);
508                                         fdrawline(v2d->cur.xmin, yminc+NLACHANNEL_SKIP, v2d->cur.xmax, yminc+NLACHANNEL_SKIP);
509                                         fdrawline(v2d->cur.xmin, ymaxc-NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc-NLACHANNEL_SKIP);
510                                         
511                                                 /* black top-lines */
512                                         glLineWidth(1.0f);
513                                         glColor3f(0.0f, 0.0f, 0.0f);
514                                         fdrawline(v2d->cur.xmin, yminc+NLACHANNEL_SKIP, v2d->cur.xmax, yminc+NLACHANNEL_SKIP);
515                                         fdrawline(v2d->cur.xmin, ymaxc-NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc-NLACHANNEL_SKIP);
516                                         
517                                         glDisable(GL_BLEND);
518                                 }
519                                         break;
520                         }
521                 }
522                 
523                 /* adjust y-position for next one */
524                 y -= NLACHANNEL_STEP;
525         }
526         
527         /* free tempolary channels */
528         BLI_freelistN(&anim_data);
529 }
530
531 /* *********************************************** */
532 /* Channel List */
533
534 void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar)
535 {
536         ListBase anim_data = {NULL, NULL};
537         bAnimListElem *ale;
538         int filter;
539         
540         View2D *v2d= &ar->v2d;
541         float x= 0.0f, y= 0.0f;
542         int items, height;
543         
544         /* build list of channels to draw */
545         filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
546         items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
547         
548         /* Update max-extent of channels here (taking into account scrollers):
549          *      - this is done to allow the channel list to be scrollable, but must be done here
550          *        to avoid regenerating the list again and/or also because channels list is drawn first
551          *      - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
552          *        start of list offset, and the second is as a correction for the scrollers.
553          */
554         height= ((items*NLACHANNEL_STEP) + (NLACHANNEL_HEIGHT*2));
555         /* don't use totrect set, as the width stays the same 
556          * (NOTE: this is ok here, the configuration is pretty straightforward) 
557          */
558         v2d->tot.ymin= (float)(-height);
559         
560         /* loop through channels, and set up drawing depending on their type  */        
561         y= (float)(-NLACHANNEL_HEIGHT);
562         
563         for (ale= anim_data.first; ale; ale= ale->next) {
564                 const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF);
565                 const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF);
566                 const float ydatac= (float)(y - 7);
567                 
568                 /* check if visible */
569                 if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
570                          IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) 
571                 {
572                         short indent= 0, offset= 0, sel= 0, group= 0;
573                         int expand= -1, protect = -1, special= -1, mute = -1;
574                         char name[128];
575                         
576                         /* determine what needs to be drawn */
577                         switch (ale->type) {
578                                 case ANIMTYPE_SCENE: /* scene */
579                                 {
580                                         Scene *sce= (Scene *)ale->data;
581                                         
582                                         group= 4;
583                                         indent= 0;
584                                         
585                                         special= ICON_SCENE_DATA;
586                                         
587                                         /* only show expand if there are any channels */
588                                         if (EXPANDED_SCEC(sce))
589                                                 expand= ICON_TRIA_DOWN;
590                                         else
591                                                 expand= ICON_TRIA_RIGHT;
592                                         
593                                         sel = SEL_SCEC(sce);
594                                         strcpy(name, sce->id.name+2);
595                                 }
596                                         break;
597                                 case ANIMTYPE_OBJECT: /* object */
598                                 {
599                                         Base *base= (Base *)ale->data;
600                                         Object *ob= base->object;
601                                         
602                                         group= 4;
603                                         indent= 0;
604                                         
605                                         /* icon depends on object-type */
606                                         if (ob->type == OB_ARMATURE)
607                                                 special= ICON_ARMATURE_DATA;
608                                         else    
609                                                 special= ICON_OBJECT_DATA;
610                                                 
611                                         /* only show expand if there are any channels */
612                                         if (EXPANDED_OBJC(ob))
613                                                 expand= ICON_TRIA_DOWN;
614                                         else
615                                                 expand= ICON_TRIA_RIGHT;
616                                         
617                                         sel = SEL_OBJC(base);
618                                         strcpy(name, ob->id.name+2);
619                                 }
620                                         break;
621                                 case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */
622                                 {
623                                         Object *ob = (Object *)ale->data;
624                                         
625                                         group = 4;
626                                         indent = 1;
627                                         special = ICON_MATERIAL_DATA;
628                                         
629                                         if (FILTER_MAT_OBJC(ob))
630                                                 expand = ICON_TRIA_DOWN;
631                                         else
632                                                 expand = ICON_TRIA_RIGHT;
633                                                 
634                                         strcpy(name, "Materials");
635                                 }
636                                         break;
637                                 
638                                 
639                                 case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */
640                                 {
641                                         Material *ma = (Material *)ale->data;
642                                         
643                                         group = 0;
644                                         indent = 0;
645                                         special = ICON_MATERIAL_DATA;
646                                         offset = 21;
647                                         
648                                         if (FILTER_MAT_OBJD(ma))
649                                                 expand = ICON_TRIA_DOWN;
650                                         else
651                                                 expand = ICON_TRIA_RIGHT;
652                                         
653                                         strcpy(name, ma->id.name+2);
654                                 }
655                                         break;
656                                 case ANIMTYPE_DSLAM: /* lamp (dopesheet) expand widget */
657                                 {
658                                         Lamp *la = (Lamp *)ale->data;
659                                         
660                                         group = 4;
661                                         indent = 1;
662                                         special = ICON_LAMP_DATA;
663                                         
664                                         if (FILTER_LAM_OBJD(la))
665                                                 expand = ICON_TRIA_DOWN;
666                                         else
667                                                 expand = ICON_TRIA_RIGHT;
668                                         
669                                         strcpy(name, la->id.name+2);
670                                 }
671                                         break;
672                                 case ANIMTYPE_DSCAM: /* camera (dopesheet) expand widget */
673                                 {
674                                         Camera *ca = (Camera *)ale->data;
675                                         
676                                         group = 4;
677                                         indent = 1;
678                                         special = ICON_CAMERA_DATA;
679                                         
680                                         if (FILTER_CAM_OBJD(ca))
681                                                 expand = ICON_TRIA_DOWN;
682                                         else
683                                                 expand = ICON_TRIA_RIGHT;
684                                         
685                                         strcpy(name, ca->id.name+2);
686                                 }
687                                         break;
688                                 case ANIMTYPE_DSCUR: /* curve (dopesheet) expand widget */
689                                 {
690                                         Curve *cu = (Curve *)ale->data;
691                                         
692                                         group = 4;
693                                         indent = 1;
694                                         special = ICON_CURVE_DATA;
695                                         
696                                         if (FILTER_CUR_OBJD(cu))
697                                                 expand = ICON_TRIA_DOWN;
698                                         else
699                                                 expand = ICON_TRIA_RIGHT;
700                                         
701                                         strcpy(name, cu->id.name+2);
702                                 }
703                                         break;
704                                 case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */
705                                 {
706                                         Key *key= (Key *)ale->data;
707                                         
708                                         group = 4;
709                                         indent = 1;
710                                         special = ICON_SHAPEKEY_DATA; // XXX 
711                                         
712                                         if (FILTER_SKE_OBJD(key))       
713                                                 expand = ICON_TRIA_DOWN;
714                                         else
715                                                 expand = ICON_TRIA_RIGHT;
716                                                 
717                                         //sel = SEL_OBJC(base);
718                                         strcpy(name, "Shape Keys");
719                                 }
720                                         break;
721                                 case ANIMTYPE_DSWOR: /* world (dopesheet) expand widget */
722                                 {
723                                         World *wo= (World *)ale->data;
724                                         
725                                         group = 4;
726                                         indent = 1;
727                                         special = ICON_WORLD_DATA;
728                                         
729                                         if (FILTER_WOR_SCED(wo))        
730                                                 expand = ICON_TRIA_DOWN;
731                                         else
732                                                 expand = ICON_TRIA_RIGHT;
733                                         
734                                         strcpy(name, wo->id.name+2);
735                                 }
736                                         break;
737                                 
738                                 case ANIMTYPE_NLATRACK: /* NLA Track */
739                                 {
740                                         NlaTrack *nlt= (NlaTrack *)ale->data;
741                                         
742                                         indent= 0;
743                                         
744                                         if (ale->id) {
745                                                 /* special exception for materials */
746                                                 if (GS(ale->id->name) == ID_MA) {
747                                                         offset= 21;
748                                                         indent= 1;
749                                                 }
750                                                 else
751                                                         offset= 14;
752                                         }
753                                         else
754                                                 offset= 0;
755                                         
756                                         /* FIXME: 'solo' as the 'special' button?
757                                          *      - need special icons for these
758                                          */
759                                         if (nlt->flag & NLATRACK_SOLO)
760                                                 special= ICON_LAYER_ACTIVE;
761                                         else
762                                                 special= ICON_LAYER_USED;
763                                                 
764                                         /* if this track is active and we're tweaking it, don't draw these toggles */
765                                         // TODO: need a special macro for this...
766                                         if ( ((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0 ) 
767                                         {
768                                                 if (nlt->flag & NLATRACK_MUTED)
769                                                         mute = ICON_MUTE_IPO_ON;
770                                                 else    
771                                                         mute = ICON_MUTE_IPO_OFF;
772                                                         
773                                                 if (EDITABLE_NLT(nlt))
774                                                         protect = ICON_UNLOCKED;
775                                                 else
776                                                         protect = ICON_LOCKED;
777                                         }
778                                                 
779                                         sel = SEL_NLT(nlt);
780                                         strcpy(name, nlt->name);
781                                 }
782                                         break;
783                                 case ANIMTYPE_NLAACTION: /* NLA Action-Line */
784                                 {
785                                         bAction *act= (bAction *)ale->data;
786                                         
787                                         group = 5;
788                                         
789                                         if (ale->id) {
790                                                 /* special exception for materials */
791                                                 if (GS(ale->id->name) == ID_MA) {
792                                                         offset= 21;
793                                                         indent= 1;
794                                                 }
795                                                 else
796                                                         offset= 14;
797                                         }
798                                         else
799                                                 offset= 0;
800                                         
801                                         special = ICON_ACTION;
802                                         
803                                         if (act)
804                                                 sprintf(name, "ActAction: <%s>", act->id.name+2);
805                                         else
806                                                 sprintf(name, "<No Action>");
807                                 }
808                                         break;
809                         }       
810                         
811                         /* now, start drawing based on this information */
812                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
813                         glEnable(GL_BLEND);
814                         
815                         /* draw backing strip behind channel name */
816                         if (group == 4) {
817                                 /* only used in dopesheet... */
818                                 if (ELEM(ale->type, ANIMTYPE_SCENE, ANIMTYPE_OBJECT)) {
819                                         /* object channel - darker */
820                                         UI_ThemeColor(TH_DOPESHEET_CHANNELOB);
821                                         uiSetRoundBox((expand == ICON_TRIA_DOWN)? (8):(1|8));
822                                         gl_round_box(GL_POLYGON, x+offset,  yminc, (float)NLACHANNEL_NAMEWIDTH, ymaxc, 10);
823                                 }
824                                 else {
825                                         /* sub-object folders - lighter */
826                                         UI_ThemeColor(TH_DOPESHEET_CHANNELSUBOB);
827                                         
828                                         offset += 7 * indent;
829                                         glBegin(GL_QUADS);
830                                                 glVertex2f(x+offset, yminc);
831                                                 glVertex2f(x+offset, ymaxc);
832                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc);
833                                                 glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc);
834                                         glEnd();
835                                         
836                                         /* clear group value, otherwise we cause errors... */
837                                         group = 0;
838                                 }
839                         }
840                         else if (group == 5) {
841                                 /* Action Line */
842                                 AnimData *adt= BKE_animdata_from_id(ale->id);
843                                 
844                                 // TODO: if tweaking some action, use the same color as for the tweaked track (quick hack done for now)
845                                 if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
846                                         // greenish color (same as tweaking strip) - hardcoded for now
847                                         glColor3f(0.3f, 0.95f, 0.1f);
848                                 }
849                                 else {
850                                         if (ale->data)
851                                                 glColor3f(0.8f, 0.2f, 0.0f);    // reddish color - hardcoded for now 
852                                         else
853                                                 glColor3f(0.6f, 0.5f, 0.5f);    // greyish-red color - hardcoded for now
854                                 }
855                                 
856                                 offset += 7 * indent;
857                                 
858                                 /* only on top two corners, to show that this channel sits on top of the preceeding ones */
859                                 uiSetRoundBox((1|2)); 
860                                 
861                                 /* draw slightly shifted up vertically to look like it has more separtion from other channels,
862                                  * but we then need to slightly shorten it so that it doesn't look like it overlaps
863                                  */
864                                 gl_round_box(GL_POLYGON, x+offset,  yminc+NLACHANNEL_SKIP, (float)NLACHANNEL_NAMEWIDTH, ymaxc+NLACHANNEL_SKIP-1, 8);
865                                 
866                                 /* clear group value, otherwise we cause errors... */
867                                 group = 0;
868                         }
869                         else {
870                                 /* for normal channels 
871                                  *      - use 3 shades of color group/standard color for 3 indention level
872                                  */
873                                 UI_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40));
874                                 
875                                 indent += group;
876                                 offset += 7 * indent;
877                                 glBegin(GL_QUADS);
878                                         glVertex2f(x+offset, yminc);
879                                         glVertex2f(x+offset, ymaxc);
880                                         glVertex2f((float)NLACHANNEL_NAMEWIDTH, ymaxc);
881                                         glVertex2f((float)NLACHANNEL_NAMEWIDTH, yminc);
882                                 glEnd();
883                         }
884                         
885                         /* draw expand/collapse triangle */
886                         if (expand > 0) {
887                                 UI_icon_draw(x+offset, ydatac, expand);
888                                 offset += 17;
889                         }
890                         
891                         /* draw special icon indicating certain data-types */
892                         if (special > -1) {
893                                 /* for normal channels */
894                                 UI_icon_draw(x+offset, ydatac, special);
895                                 offset += 17;
896                         }
897                         glDisable(GL_BLEND);
898                         
899                         /* draw name */
900                         if (sel)
901                                 UI_ThemeColor(TH_TEXT_HI);
902                         else
903                                 UI_ThemeColor(TH_TEXT);
904                         offset += 3;
905                         UI_DrawString(x+offset, y-4, name);
906                         
907                         /* reset offset - for RHS of panel */
908                         offset = 0;
909                         
910                         /* set blending again, as text drawing may clear it */
911                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
912                         glEnable(GL_BLEND);
913                         
914                         /* draw protect 'lock' */
915                         if (protect > -1) {
916                                 offset = 16;
917                                 UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, protect);
918                         }
919                         
920                         /* draw mute 'eye' */
921                         if (mute > -1) {
922                                 offset += 16;
923                                 UI_icon_draw((float)(NLACHANNEL_NAMEWIDTH-offset), ydatac, mute);
924                         }
925                         
926                         /* draw NLA-action line 'status-icons' - only when there's an action */
927                         if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) {
928                                 AnimData *adt= BKE_animdata_from_id(ale->id);
929                                 
930                                 offset += 16;
931                                 
932                                 /* now draw some indicator icons  */
933                                 if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
934                                         /* toggle for tweaking with mapping/no-mapping (i.e. 'in place editing' toggle) */
935                                         // for now, use pin icon to symbolise this
936                                         if (adt->flag & ADT_NLA_EDIT_NOMAP)
937                                                 UI_icon_draw((float)(NLACHANNEL_NAMEWIDTH-offset), ydatac, ICON_PINNED);
938                                         else
939                                                 UI_icon_draw((float)(NLACHANNEL_NAMEWIDTH-offset), ydatac, ICON_UNPINNED);
940                                         
941                                         fdrawline((float)(NLACHANNEL_NAMEWIDTH-offset), yminc, 
942                                                           (float)(NLACHANNEL_NAMEWIDTH-offset), ymaxc);
943                                         offset += 16;;
944                                         
945                                         /* 'tweaking action' indicator - not a button */
946                                         UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_EDIT); 
947                                 }
948                                 else {
949                                         /* XXX firstly draw a little rect to help identify that it's different from the toggles */
950                                         glBegin(GL_LINE_LOOP);
951                                                 glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y-7);
952                                                 glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y+9);
953                                                 glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y+9);
954                                                 glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y-7);
955                                         glEnd(); // GL_LINES
956                                         
957                                         /* 'push down' icon for normal active-actions */
958                                         UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_FREEZE);
959                                 }
960                         }
961                         
962                         glDisable(GL_BLEND);
963                 }
964                 
965                 /* adjust y-position for next one */
966                 y -= NLACHANNEL_STEP;
967         }
968         
969         /* free tempolary channels */
970         BLI_freelistN(&anim_data);
971 }
972
973 /* *********************************************** */