Fix for bug [#13479] Particle system "corrupts" when changing material colour and...
[blender.git] / source / blender / src / drawaction.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) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Drawing routines for the Action window type
29  */
30
31 /* System includes ----------------------------------------------------- */
32
33 #include <math.h>
34 #include <stdlib.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BMF_Api.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 /* Types --------------------------------------------------------------- */
48 #include "DNA_listBase.h"
49 #include "DNA_action_types.h"
50 #include "DNA_armature_types.h"
51 #include "DNA_curve_types.h"
52 #include "DNA_ipo_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_screen_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_constraint_types.h"
58 #include "DNA_key_types.h"
59
60 #include "BKE_action.h"
61 #include "BKE_depsgraph.h"
62 #include "BKE_ipo.h"
63 #include "BKE_key.h"
64 #include "BKE_object.h"
65 #include "BKE_global.h"
66 #include "BKE_utildefines.h"
67
68 /* Everything from source (BIF, BDR, BSE) ------------------------------ */ 
69
70 #include "BIF_editaction.h"
71 #include "BIF_editkey.h"
72 #include "BIF_editnla.h"
73 #include "BIF_interface.h"
74 #include "BIF_interface_icons.h"
75 #include "BIF_gl.h"
76 #include "BIF_glutil.h"
77 #include "BIF_resources.h"
78 #include "BIF_screen.h"
79 #include "BIF_mywindow.h"
80 #include "BIF_space.h"
81
82 #include "BDR_drawaction.h"
83 #include "BDR_editcurve.h"
84
85 #include "BSE_drawnla.h"
86 #include "BSE_drawipo.h"
87 #include "BSE_editaction_types.h"
88 #include "BSE_editipo.h"
89 #include "BSE_time.h"
90 #include "BSE_view.h"
91
92 /* 'old' stuff": defines and types, and own include -------------------- */
93
94 #include "blendef.h"
95 #include "interface.h"
96 #include "mydevice.h"
97
98 /********************************** Slider Stuff **************************** */
99
100 /* sliders for shapekeys */
101 static void meshactionbuts(SpaceAction *saction, Object *ob, Key *key)
102 {
103         int           i;
104         char          str[64];
105         float         x, y;
106         uiBlock       *block;
107         uiBut             *but;
108
109 #define XIC 20
110 #define YIC 20
111
112         /* lets make the rvk sliders */
113
114         /* reset the damn myortho2 or the sliders won't draw/redraw
115          * correctly *grumble*
116          */
117         mywinset(curarea->win);
118         myortho2(-0.375, curarea->winx-0.375, G.v2d->cur.ymin, G.v2d->cur.ymax);
119
120     sprintf(str, "actionbuttonswin %d", curarea->win);
121     block= uiNewBlock (&curarea->uiblocks, str, UI_EMBOSS, UI_HELV, curarea->win);
122
123         x = NAMEWIDTH + 1;
124     y = 0.0f;
125
126         /* make the little 'open the sliders' widget */
127         // should eventually be removed
128     BIF_ThemeColor(TH_FACE); // this slot was open... (???... Aligorith)
129         glRects(2,            y + 2*CHANNELHEIGHT - 2, ACTWIDTH - 2, y + CHANNELHEIGHT + 2);
130         glColor3ub(0, 0, 0);
131         glRasterPos2f(4, y + CHANNELHEIGHT + 6);
132         BMF_DrawString(G.font, "Sliders");
133
134         uiBlockSetEmboss(block, UI_EMBOSSN);
135
136         if (!(G.saction->flag & SACTION_SLIDERS)) {
137                 ACTWIDTH = NAMEWIDTH;
138                 but=uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR, 
139                                           ICON_DISCLOSURE_TRI_RIGHT,
140                                           NAMEWIDTH - XIC - 5, y + CHANNELHEIGHT,
141                                           XIC,YIC-2,
142                                           &(G.saction->flag), 0, 0, 0, 0, 
143                                           "Show action window sliders");
144                 /* no hilite, the winmatrix is not correct later on... */
145                 uiButSetFlag(but, UI_NO_HILITE);
146
147         }
148         else {
149                 but= uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR, 
150                                           ICON_DISCLOSURE_TRI_DOWN,
151                                           NAMEWIDTH - XIC - 5, y + CHANNELHEIGHT,
152                                           XIC,YIC-2,
153                                           &(G.saction->flag), 0, 0, 0, 0, 
154                                           "Hide action window sliders");
155                 /* no hilite, the winmatrix is not correct later on... */
156                 uiButSetFlag(but, UI_NO_HILITE);
157                                           
158                 ACTWIDTH = NAMEWIDTH + SLIDERWIDTH;
159
160                 /* sliders are open so draw them */
161                 BIF_ThemeColor(TH_FACE); 
162
163                 glRects(NAMEWIDTH,  0,  NAMEWIDTH+SLIDERWIDTH,  curarea->winy);
164                 uiBlockSetEmboss(block, UI_EMBOSS);
165                 for (i=1; i < key->totkey; i++) {
166                         make_rvk_slider(block, ob, i, 
167                                                         x, y, SLIDERWIDTH-2, CHANNELHEIGHT-1, "Slider to control Shape Keys");
168                         
169                         y-=CHANNELHEIGHT+CHANNELSKIP;
170                         
171                         /* see sliderval array in editkey.c */
172                         if(i >= 255) break;
173                 }
174         }
175         uiDrawBlock(block);
176 }
177
178 static void icu_slider_func(void *voidicu, void *voidignore) 
179 {
180         /* the callback for the icu sliders ... copies the
181          * value from the icu->curval into a bezier at the
182          * right frame on the right ipo curve (creating both the
183          * ipo curve and the bezier if needed).
184          */
185         IpoCurve  *icu= voidicu;
186         BezTriple *bezt=NULL;
187         float cfra, icuval;
188
189         cfra = frame_to_float(CFRA);
190         if (G.saction->pin==0 && OBACT)
191                 cfra= get_action_frame(OBACT, cfra);
192         
193         /* if the ipocurve exists, try to get a bezier
194          * for this frame
195          */
196         bezt = get_bezt_icu_time(icu, &cfra, &icuval);
197
198         /* create the bezier triple if one doesn't exist,
199          * otherwise modify it's value
200          */
201         if (bezt == NULL) {
202                 insert_vert_icu(icu, cfra, icu->curval, 0);
203         }
204         else {
205                 bezt->vec[1][1] = icu->curval;
206         }
207
208         /* make sure the Ipo's are properly processed and
209          * redraw as necessary
210          */
211         sort_time_ipocurve(icu);
212         testhandles_ipocurve(icu);
213         
214         /* nla-update (in case this affects anything) */
215         synchronize_action_strips();
216         
217         /* do redraw pushes, and also the depsgraph flushes */
218         if (OBACT->pose || ob_get_key(OBACT))
219                 DAG_object_flush_update(G.scene, OBACT, OB_RECALC);
220         else
221                 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB);
222         
223         allqueue(REDRAWVIEW3D, 0);
224         allqueue(REDRAWACTION, 0);
225         allqueue(REDRAWNLA, 0);
226         allqueue(REDRAWIPO, 0);
227         allspace(REMAKEIPO, 0);
228         allqueue(REDRAWBUTSALL, 0);
229 }
230
231 static void make_icu_slider(uiBlock *block, IpoCurve *icu,
232                                          int x, int y, int w, int h, char *tip)
233 {
234         /* create a slider for the ipo-curve*/
235         uiBut *but;
236         
237         if(icu == NULL) return;
238         
239         if (IS_EQ(icu->slide_max, icu->slide_min)) {
240                 if (IS_EQ(icu->ymax, icu->ymin)) {
241                         if (ELEM(icu->blocktype, ID_CO, ID_KE)) {
242                                 /* hack for constraints and shapekeys (and maybe a few others) */
243                                 icu->slide_min= 0.0;
244                                 icu->slide_max= 1.0;
245                         }
246                         else {
247                                 icu->slide_min= -100;
248                                 icu->slide_max= 100;
249                         }
250                 }
251                 else {
252                         icu->slide_min= icu->ymin;
253                         icu->slide_max= icu->ymax;
254                 }
255         }
256         if (icu->slide_min >= icu->slide_max) {
257                 SWAP(float, icu->slide_min, icu->slide_max);
258         }
259
260         but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "",
261                                   x, y , w, h,
262                                   &(icu->curval), icu->slide_min, icu->slide_max, 
263                                   10, 2, tip);
264         
265         uiButSetFunc(but, icu_slider_func, icu, NULL);
266         
267         // no hilite, the winmatrix is not correct later on...
268         uiButSetFlag(but, UI_NO_HILITE);
269 }
270
271 /* sliders for ipo-curves of active action-channel */
272 static void action_icu_buts(SpaceAction *saction)
273 {
274         ListBase act_data = {NULL, NULL};
275         bActListElem *ale;
276         int filter;
277         void *data;
278         short datatype;
279         
280         char          str[64];
281         float           x, y;
282         uiBlock       *block;
283
284         /* lets make the action sliders */
285
286         /* reset the damn myortho2 or the sliders won't draw/redraw
287          * correctly *grumble*
288          */
289         mywinset(curarea->win);
290         myortho2(-0.375, curarea->winx-0.375, G.v2d->cur.ymin, G.v2d->cur.ymax);
291         
292     sprintf(str, "actionbuttonswin %d", curarea->win);
293     block= uiNewBlock (&curarea->uiblocks, str, 
294                        UI_EMBOSS, UI_HELV, curarea->win);
295
296         x = NAMEWIDTH + 1;
297     y = 0.0f;
298         
299         uiBlockSetEmboss(block, UI_EMBOSSN);
300
301         if (G.saction->flag & SACTION_SLIDERS) {
302                 /* sliders are open so draw them */
303                 
304                 /* get editor data */
305                 data= get_action_context(&datatype);
306                 if (data == NULL) return;
307                 
308                 /* build list of channels to draw */
309                 filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS);
310                 actdata_filter(&act_data, filter, data, datatype);
311                 
312                 /* draw backdrop first */
313                 BIF_ThemeColor(TH_FACE); // change this color... it's ugly
314                 glRects(NAMEWIDTH,  G.v2d->cur.ymin,  NAMEWIDTH+SLIDERWIDTH,  G.v2d->cur.ymax);
315                 
316                 uiBlockSetEmboss(block, UI_EMBOSS);
317                 for (ale= act_data.first; ale; ale= ale->next) {
318                         const float yminc= y-CHANNELHEIGHT/2;
319                         const float ymaxc= y+CHANNELHEIGHT/2;
320                         
321                         /* check if visible */
322                         if ( IN_RANGE(yminc, G.v2d->cur.ymin, G.v2d->cur.ymax) ||
323                                  IN_RANGE(ymaxc, G.v2d->cur.ymin, G.v2d->cur.ymax) ) 
324                         {
325                                 /* determine what needs to be drawn */
326                                 switch (ale->type) {
327                                         case ACTTYPE_CONCHAN: /* constraint channel */
328                                         {
329                                                 bActionChannel *achan = (bActionChannel *)ale->owner;
330                                                 IpoCurve *icu = (IpoCurve *)ale->key_data;
331                                                 
332                                                 /* only show if action channel is selected */
333                                                 if (SEL_ACHAN(achan)) {
334                                                         make_icu_slider(block, icu,
335                                                                                         x, y, SLIDERWIDTH-2, CHANNELHEIGHT-2, 
336                                                                                         "Slider to control current value of Constraint Influence");
337                                                 }
338                                         }
339                                                 break;
340                                         case ACTTYPE_ICU: /* ipo-curve channel */
341                                         {
342                                                 bActionChannel *achan = (bActionChannel *)ale->owner;
343                                                 IpoCurve *icu = (IpoCurve *)ale->key_data;
344                                                 
345                                                 /* only show if action channel is selected */
346                                                 if (SEL_ACHAN(achan)) {
347                                                         make_icu_slider(block, icu,
348                                                                                         x, y, SLIDERWIDTH-2, CHANNELHEIGHT-2, 
349                                                                                         "Slider to control current value of IPO-Curve");
350                                                 }
351                                         }
352                                                 break;
353                                         case ACTTYPE_SHAPEKEY: /* shapekey channel */
354                                         {
355                                                 // TODO...
356                                         }
357                                                 break;
358                                 }
359                         }
360                         
361                         /* adjust y-position for next one */
362                         y-=CHANNELHEIGHT+CHANNELSKIP;
363                 }
364                 
365                 /* free tempolary channels */
366                 BLI_freelistN(&act_data);
367         }
368         uiDrawBlock(block);
369 }
370
371 /********************************** Current Frame **************************** */
372
373 void draw_cfra_action (void)
374 {
375         Object *ob;
376         float vec[2];
377         
378         /* Draw a light green line to indicate current frame */
379         vec[0]= (G.scene->r.cfra);
380         vec[0]*= G.scene->r.framelen;
381         
382         vec[1]= G.v2d->cur.ymin;
383         BIF_ThemeColor(TH_CFRAME);
384         glLineWidth(2.0);
385         
386         glBegin(GL_LINE_STRIP);
387         glVertex2fv(vec);
388         vec[1]= G.v2d->cur.ymax;
389         glVertex2fv(vec);
390         glEnd();
391         
392         /* Draw dark green line if slow-parenting/time-offset is enabled */
393         ob= (G.scene->basact) ? (G.scene->basact->object) : 0;
394         if ((ob) && (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0)) {
395                 vec[0]-= give_timeoffset(ob); /* could avoid calling twice */
396                 
397                 BIF_ThemeColorShade(TH_CFRAME, -30);
398                 
399                 glBegin(GL_LINE_STRIP);
400                 glVertex2fv(vec);
401                 vec[1]= G.v2d->cur.ymin;
402                 glVertex2fv(vec);
403                 glEnd();
404         }
405         
406         glLineWidth(1.0);
407 }
408
409 /********************************** Left-Hand Panel + Generics **************************** */
410
411 /* left hand part */
412 static void draw_channel_names(void) 
413 {
414         ListBase act_data = {NULL, NULL};
415         bActListElem *ale;
416         int filter;
417         void *data;
418         short datatype;
419         short ofsx = 0, ofsy = 0; 
420         float x= 0.0f, y= 0.0f;
421         
422         /* determine what type of data we are operating on */
423         data = get_action_context(&datatype);
424         if (data == NULL) return;
425         
426         /* Clip to the scrollable area */
427         if (curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
428                 if(G.v2d->scroll) {     
429                         ofsx= curarea->winrct.xmin;     
430                         ofsy= curarea->winrct.ymin;
431                         glViewport(ofsx,  ofsy+G.v2d->mask.ymin, NAMEWIDTH, 
432                                            (ofsy+G.v2d->mask.ymax) -
433                                            (ofsy+G.v2d->mask.ymin)); 
434                         glScissor(ofsx,  ofsy+G.v2d->mask.ymin, NAMEWIDTH, 
435                                           (ofsy+G.v2d->mask.ymax) -
436                                           (ofsy+G.v2d->mask.ymin));
437                 }
438         }
439         
440         /* prepare scaling for LHS panel */
441         myortho2(0,     NAMEWIDTH, G.v2d->cur.ymin, G.v2d->cur.ymax);
442         
443         /* set default color back to black */
444         glColor3ub(0x00, 0x00, 0x00);
445         
446         /* build list of channels to draw */
447         filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS);
448         actdata_filter(&act_data, filter, data, datatype);
449         
450         /* loop through channels, and set up drawing depending on their type  */
451         glEnable(GL_BLEND);
452         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
453         
454         for (ale= act_data.first; ale; ale= ale->next) {
455                 const float yminc= y-CHANNELHEIGHT/2;
456                 const float ymaxc= y+CHANNELHEIGHT/2;
457                 
458                 /* check if visible */
459                 if ( IN_RANGE(yminc, G.v2d->cur.ymin, G.v2d->cur.ymax) ||
460                          IN_RANGE(ymaxc, G.v2d->cur.ymin, G.v2d->cur.ymax) ) 
461                 {
462                         bActionGroup *grp = NULL;
463                         short indent= 0, offset= 0, sel= 0, group=0;
464                         int expand= -1, protect = -1, special= -1, mute = -1;
465                         char name[32];
466                         
467                         /* determine what needs to be drawn */
468                         switch (ale->type) {
469                                 case ACTTYPE_GROUP: /* action group */
470                                 {
471                                         bActionGroup *agrp= (bActionGroup *)ale->data;
472                                         
473                                         group= 2;
474                                         indent= 0;
475                                         special= -1;
476                                         
477                                         /* only show expand if there are any channels */
478                                         if (agrp->channels.first) {
479                                                 if (EXPANDED_AGRP(agrp))
480                                                         expand = ICON_TRIA_DOWN;
481                                                 else
482                                                         expand = ICON_TRIA_RIGHT;
483                                         }
484                                                 
485                                         if (EDITABLE_AGRP(agrp))
486                                                 protect = ICON_UNLOCKED;
487                                         else
488                                                 protect = ICON_LOCKED;
489                                                 
490                                         sel = SEL_AGRP(agrp);
491                                         sprintf(name, agrp->name);
492                                 }
493                                         break;
494                                 case ACTTYPE_ACHAN: /* action channel */
495                                 {
496                                         bActionChannel *achan= (bActionChannel *)ale->data;
497                                         
498                                         group= (ale->grp) ? 1 : 0;
499                                         grp= ale->grp;
500                                         
501                                         indent = 0;
502                                         special = -1;
503                                         
504                                         if (EXPANDED_ACHAN(achan))
505                                                 expand = ICON_TRIA_DOWN;
506                                         else
507                                                 expand = ICON_TRIA_RIGHT;
508                                                 
509                                         if (EDITABLE_ACHAN(achan))
510                                                 protect = ICON_UNLOCKED;
511                                         else
512                                                 protect = ICON_LOCKED;
513                                                 
514                                         if (achan->ipo) {
515                                                 if (achan->ipo->muteipo)
516                                                         mute = ICON_MUTE_IPO_ON;
517                                                 else
518                                                         mute = ICON_MUTE_IPO_OFF;
519                                         }
520                                         
521                                         sel = SEL_ACHAN(achan);
522                                         sprintf(name, achan->name);
523                                 }
524                                         break;
525                                 case ACTTYPE_CONCHAN: /* constraint channel */
526                                 {
527                                         bConstraintChannel *conchan = (bConstraintChannel *)ale->data;
528                                         
529                                         indent = 2;
530                                         
531                                         group= (ale->grp) ? 1 : 0;
532                                         grp= ale->grp;
533                                         
534                                         if (EDITABLE_CONCHAN(conchan))
535                                                 protect = ICON_UNLOCKED;
536                                         else
537                                                 protect = ICON_LOCKED;
538                                                 
539                                         if (conchan->ipo) {
540                                                 if (conchan->ipo->muteipo)
541                                                         mute = ICON_MUTE_IPO_ON;
542                                                 else
543                                                         mute = ICON_MUTE_IPO_OFF;
544                                         }
545                                         
546                                         sel = SEL_CONCHAN(conchan);
547                                         sprintf(name, conchan->name);
548                                 }
549                                         break;
550                                 case ACTTYPE_ICU: /* ipo-curve channel */
551                                 {
552                                         IpoCurve *icu = (IpoCurve *)ale->data;
553                                         
554                                         indent = 2;
555                                         protect = -1; // for now, until this can be supported by others
556                                         
557                                         group= (ale->grp) ? 1 : 0;
558                                         grp= ale->grp;
559                                         
560                                         if (icu->flag & IPO_MUTE)
561                                                 mute = ICON_MUTE_IPO_ON;
562                                         else    
563                                                 mute = ICON_MUTE_IPO_OFF;
564                                         
565                                         sel = SEL_ICU(icu);
566                                         if (G.saction->pin)
567                                                 sprintf(name, getname_ipocurve(icu, NULL));
568                                         else
569                                                 sprintf(name, getname_ipocurve(icu, OBACT));
570                                 }
571                                         break;
572                                 case ACTTYPE_SHAPEKEY: /* shapekey channel */
573                                 {
574                                         KeyBlock *kb = (KeyBlock *)ale->data;
575                                         
576                                         indent = 0;
577                                         special = -1;
578                                         
579                                         if (kb->name[0] == '\0')
580                                                 sprintf(name, "Key %d", ale->index);
581                                         else
582                                                 sprintf(name, kb->name);
583                                 }
584                                         break;
585                                 case ACTTYPE_FILLIPO: /* ipo expand widget */
586                                 {
587                                         bActionChannel *achan = (bActionChannel *)ale->data;
588                                         
589                                         indent = 1;
590                                         special = geticon_ipo_blocktype(achan->ipo->blocktype);
591                                         
592                                         group= (ale->grp) ? 1 : 0;
593                                         grp= ale->grp;
594                                         
595                                         if (FILTER_IPO_ACHAN(achan))    
596                                                 expand = ICON_TRIA_DOWN;
597                                         else
598                                                 expand = ICON_TRIA_RIGHT;
599                                         
600                                         sel = SEL_ACHAN(achan);
601                                         sprintf(name, "IPO Curves");
602                                 }
603                                         break;
604                                 case ACTTYPE_FILLCON: /* constraint expand widget */
605                                 {
606                                         bActionChannel *achan = (bActionChannel *)ale->data;
607                                         
608                                         indent = 1;
609                                         special = ICON_CONSTRAINT;
610                                         
611                                         group= (ale->grp) ? 1 : 0;
612                                         grp= ale->grp;
613                                         
614                                         if (FILTER_CON_ACHAN(achan))    
615                                                 expand = ICON_TRIA_DOWN;
616                                         else
617                                                 expand = ICON_TRIA_RIGHT;
618                                                 
619                                         sel = SEL_ACHAN(achan);
620                                         sprintf(name, "Constraint");
621                                 }
622                                         break;
623                         }       
624
625                         /* now, start drawing based on this information */
626                         /* draw backing strip behind channel name */
627                         if (group == 2) {
628                                 /* only for group-channels */
629                                 if (ale->flag & AGRP_ACTIVE)
630                                         BIF_ThemeColorShade(TH_GROUP_ACTIVE, 10);
631                                 else
632                                         BIF_ThemeColorShade(TH_GROUP, 20);
633                                 uiSetRoundBox((expand == ICON_TRIA_DOWN)? (1):(1|8));
634                                 gl_round_box(GL_POLYGON, x,  yminc, (float)NAMEWIDTH, ymaxc, 8);
635                                 
636                                 offset = 0;
637                         }
638                         else {
639                                 /* for normal channels 
640                                  *      - use 3 shades of color group/standard color for 3 indention level
641                                  *      - only use group colors if allowed to, and if actually feasible
642                                  */
643                                 if ( !(G.saction->flag & SACTION_NODRAWGCOLORS) && 
644                                          (grp) && (grp->customCol) ) 
645                                 {
646                                         char cp[3];
647                                         
648                                         if (indent == 2) {
649                                                 VECCOPY(cp, grp->cs.solid);
650                                         }
651                                         else if (indent == 1) {
652                                                 VECCOPY(cp, grp->cs.select);
653                                         }
654                                         else {
655                                                 VECCOPY(cp, grp->cs.active);
656                                         }
657                                         
658                                         glColor3ub(cp[0], cp[1], cp[2]);
659                                 }
660                                 else
661                                         BIF_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40));
662                                 
663                                 indent += group;
664                                 offset = 7 * indent;
665                                 glRectf(x+offset,  yminc, (float)NAMEWIDTH, ymaxc);
666                         }
667                         
668                         /* draw expand/collapse triangle */
669                         if (expand > 0) {
670                                 BIF_icon_draw(x+offset, yminc, expand);
671                                 offset += 17;
672                         }
673                         
674                         /* draw special icon indicating type of ipo-blocktype? 
675                          *      only for expand widgets for Ipo and Constraint Channels 
676                          */
677                         if (special > 0) {
678                                 offset = (group) ? 29 : 24;
679                                 BIF_icon_draw(x+offset, yminc, special);
680                                 offset += 17;
681                         }
682                                 
683                         /* draw name */
684                         if (sel)
685                                 BIF_ThemeColor(TH_TEXT_HI);
686                         else
687                                 BIF_ThemeColor(TH_TEXT);
688                         offset += 3;
689                         glRasterPos2f(x+offset, y-4);
690                         BMF_DrawString(G.font, name);
691                         
692                         /* reset offset - for RHS of panel */
693                         offset = 0;
694                         
695                         /* draw protect 'lock' */
696                         if (protect > 0) {
697                                 offset = 16;
698                                 BIF_icon_draw(NAMEWIDTH-offset, yminc, protect);
699                         }
700                         
701                         /* draw mute 'eye' */
702                         if (mute > 0) {
703                                 offset += 16;
704                                 BIF_icon_draw(NAMEWIDTH-offset, yminc, mute);
705                         }
706                 }
707                 
708                 /* adjust y-position for next one */
709                 y-=CHANNELHEIGHT+CHANNELSKIP;
710         }
711         
712         /* free tempolary channels */
713         BLI_freelistN(&act_data);
714         
715         /* re-adjust view matrices for correct scaling */
716     myortho2(0, NAMEWIDTH, 0, (ofsy+G.v2d->mask.ymax) - (ofsy+G.v2d->mask.ymin));       //      Scaling
717 }
718
719 /* sets or clears hidden flags */
720 void check_action_context(SpaceAction *saction)
721 {
722         bActionChannel *achan;
723         
724         if (saction->action==NULL) return;
725         
726         for (achan=saction->action->chanbase.first; achan; achan=achan->next)
727                 achan->flag &= ~ACHAN_HIDDEN;
728         
729         if ((saction->pin==0) && ((saction->flag & SACTION_NOHIDE)==0) && (OBACT)) {
730                 Object *ob= OBACT;
731                 bPoseChannel *pchan;
732                 bArmature *arm= ob->data;
733                 
734                 for (achan=saction->action->chanbase.first; achan; achan=achan->next) {
735                         pchan= get_pose_channel(ob->pose, achan->name);
736                         if (pchan && pchan->bone) {
737                                 if ((pchan->bone->layer & arm->layer)==0)
738                                         achan->flag |= ACHAN_HIDDEN;
739                                 else if (pchan->bone->flag & BONE_HIDDEN_P)
740                                         achan->flag |= ACHAN_HIDDEN;
741                         }
742                 }
743         }
744 }
745
746 static void draw_channel_strips(void)
747 {
748         ListBase act_data = {NULL, NULL};
749         bActListElem *ale;
750         int filter;
751         void *data;
752         short datatype;
753         
754         rcti scr_rct;
755         gla2DDrawInfo *di;
756         float y, sta, end;
757         int act_start, act_end, dummy;
758         char col1[3], col2[3];
759         char col1a[3], col2a[3];
760         
761         BIF_GetThemeColor3ubv(TH_SHADE2, col2);
762         BIF_GetThemeColor3ubv(TH_HILITE, col1);
763         BIF_GetThemeColor3ubv(TH_GROUP, col2a);
764         BIF_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
765
766         /* get editor data */
767         data= get_action_context(&datatype);
768         if (data == NULL) return;
769
770         scr_rct.xmin= G.saction->area->winrct.xmin + G.saction->v2d.mask.xmin;
771         scr_rct.ymin= G.saction->area->winrct.ymin + G.saction->v2d.mask.ymin;
772         scr_rct.xmax= G.saction->area->winrct.xmin + G.saction->v2d.hor.xmax;
773         scr_rct.ymax= G.saction->area->winrct.ymin + G.saction->v2d.mask.ymax; 
774         di= glaBegin2DDraw(&scr_rct, &G.v2d->cur);
775
776         /* if in NLA there's a strip active, map the view */
777         if (datatype == ACTCONT_ACTION) {
778                 if (NLA_ACTION_SCALED)
779                         map_active_strip(di, OBACT, 0);
780                 
781                 /* start and end of action itself */
782                 calc_action_range(data, &sta, &end, 0);
783                 gla2DDrawTranslatePt(di, sta, 0.0f, &act_start, &dummy);
784                 gla2DDrawTranslatePt(di, end, 0.0f, &act_end, &dummy);
785                 
786                 if (NLA_ACTION_SCALED)
787                         map_active_strip(di, OBACT, 1);
788         }
789         
790         /* build list of channels to draw */
791         filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS);
792         actdata_filter(&act_data, filter, data, datatype);
793         
794         /* first backdrop strips */
795         y = 0.0;
796         glEnable(GL_BLEND);
797         for (ale= act_data.first; ale; ale= ale->next) {
798                 int frame1_x, channel_y, sel=0;
799                 
800                 /* determine if any need to draw channel */
801                 if (ale->datatype != ALE_NONE) {
802                         /* determine if channel is selected */
803                         switch (ale->type) {
804                                 case ACTTYPE_GROUP:
805                                 {
806                                         bActionGroup *agrp = (bActionGroup *)ale->data;
807                                         sel = SEL_AGRP(agrp);
808                                 }
809                                         break;
810                                 case ACTTYPE_ACHAN:
811                                 {
812                                         bActionChannel *achan = (bActionChannel *)ale->data;
813                                         sel = SEL_ACHAN(achan);
814                                 }
815                                         break;
816                                 case ACTTYPE_CONCHAN:
817                                 {
818                                         bConstraintChannel *conchan = (bConstraintChannel *)ale->data;
819                                         sel = SEL_CONCHAN(conchan);
820                                 }
821                                         break;
822                                 case ACTTYPE_ICU:
823                                 {
824                                         IpoCurve *icu = (IpoCurve *)ale->data;
825                                         sel = SEL_ICU(icu);
826                                 }
827                                         break;
828                         }
829                         
830                         if (datatype == ACTCONT_ACTION) {
831                                 gla2DDrawTranslatePt(di, G.v2d->cur.xmin, y, &frame1_x, &channel_y);
832                                 
833                                 if (ale->datatype == ALE_GROUP) {
834                                         if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
835                                         else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
836                                 }
837                                 else {
838                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
839                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
840                                 }
841                                 glRectf(frame1_x,  channel_y-CHANNELHEIGHT/2,  G.v2d->hor.xmax,  channel_y+CHANNELHEIGHT/2);
842                                 
843                                 if (ale->datatype == ALE_GROUP) {
844                                         if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
845                                         else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
846                                 }
847                                 else {
848                                         if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
849                                         else glColor4ub(col2[0], col2[1], col2[2], 0x22);
850                                 }
851                                 glRectf(act_start,  channel_y-CHANNELHEIGHT/2,  act_end,  channel_y+CHANNELHEIGHT/2);
852                         }
853                         else if (datatype == ACTCONT_SHAPEKEY) {
854                                 gla2DDrawTranslatePt(di, 1, y, &frame1_x, &channel_y);
855                                 
856                                 /* all frames that have a frame number less than one
857                                  * get a desaturated orange background
858                                  */
859                                 glColor4ub(col2[0], col2[1], col2[2], 0x22);
860                                 glRectf(0, channel_y-CHANNELHEIGHT/2, frame1_x, channel_y+CHANNELHEIGHT/2);
861                                 
862                                 /* frames one and higher get a saturated orange background */
863                                 glColor4ub(col2[0], col2[1], col2[2], 0x44);
864                                 glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax,  channel_y+CHANNELHEIGHT/2);
865                         }
866                 }
867                 
868                 /*      Increment the step */
869                 y-=CHANNELHEIGHT+CHANNELSKIP;
870         }               
871         glDisable(GL_BLEND);
872         
873         if (NLA_ACTION_SCALED)
874                 map_active_strip(di, OBACT, 0);
875         
876         /* Draw keyframes 
877          *      1) Only channels that are visible in the Action Editor get drawn/evaluated.
878          *         This is to try to optimise this for heavier data sets
879          *      2) Keyframes which are out of view horizontally are disregarded 
880          */
881         y = 0.0;
882         for (ale= act_data.first; ale; ale= ale->next) {
883                 const float yminc= y-CHANNELHEIGHT/2;
884                 const float ymaxc= y+CHANNELHEIGHT/2;
885                 
886                 /* check if visible */
887                 if ( IN_RANGE(yminc, G.v2d->cur.ymin, G.v2d->cur.ymax) ||
888                          IN_RANGE(ymaxc, G.v2d->cur.ymin, G.v2d->cur.ymax) ) 
889                 {
890                         switch (ale->datatype) {
891                                 case ALE_GROUP:
892                                         draw_agroup_channel(di, ale->data, y);
893                                         break;
894                                 case ALE_IPO:
895                                         draw_ipo_channel(di, ale->key_data, y);
896                                         break;
897                                 case ALE_ICU:
898                                         draw_icu_channel(di, ale->key_data, y);
899                                         break;
900                         }
901                 }
902                 
903                 y-=CHANNELHEIGHT+CHANNELSKIP;
904         }
905         
906         /* free tempolary channels used for drawing */
907         BLI_freelistN(&act_data);
908
909         /* black line marking 'current frame' for Time-Slide transform mode */
910         if (G.saction->flag & SACTION_MOVING) {
911                 int frame1_x, channel_y;
912                 
913                 gla2DDrawTranslatePt(di, G.saction->timeslide, 0, &frame1_x, &channel_y);
914                 cpack(0x0);
915                 
916                 glBegin(GL_LINES);
917                 glVertex2f(frame1_x, G.v2d->mask.ymin - 100);
918                 glVertex2f(frame1_x, G.v2d->mask.ymax);
919                 glEnd();
920         }
921         
922         glaEnd2DDraw(di);
923 }
924
925 /* ********* action panel *********** */
926
927
928 void do_actionbuts(unsigned short event)
929 {
930         switch(event) {
931         case REDRAWVIEW3D:
932                 allqueue(REDRAWVIEW3D, 0);
933                 break;
934         case B_REDR:
935                 allqueue(REDRAWACTION, 0);
936                 break;
937         }
938 }
939
940 // currently not used...
941 static void action_panel_properties(short cntrl)        // ACTION_HANDLER_PROPERTIES
942 {
943         uiBlock *block;
944
945         block= uiNewBlock(&curarea->uiblocks, "action_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
946         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
947         uiSetPanelHandler(ACTION_HANDLER_PROPERTIES);  // for close and esc
948         if (uiNewPanel(curarea, block, "Transform Properties", "Action", 10, 230, 318, 204)==0) 
949                 return;
950
951         uiDefBut(block, LABEL, 0, "test text",          10,180,300,19, 0, 0, 0, 0, 0, "");
952 }
953
954 static void action_blockhandlers(ScrArea *sa)
955 {
956         SpaceAction *sact= sa->spacedata.first;
957         short a;
958         
959         for (a=0; a<SPACE_MAXHANDLER; a+=2) {
960                 switch(sact->blockhandler[a]) {
961                         case ACTION_HANDLER_PROPERTIES:
962                                 action_panel_properties(sact->blockhandler[a+1]);
963                                 break;
964                 }
965                 
966                 /* clear action value for event */
967                 sact->blockhandler[a+1]= 0;
968         }
969         
970         uiDrawBlocksPanels(sa, 0);
971 }
972
973 /* ************************* Action Editor Space ***************************** */
974
975 void drawactionspace(ScrArea *sa, void *spacedata)
976 {
977         bAction *act = NULL;
978         Key *key = NULL;
979         void *data;
980         short datatype;
981         
982         short ofsx = 0, ofsy = 0;
983         float col[3];
984
985         /* this is unlikely to occur, but it may */
986         if (G.saction == NULL)
987                 return;
988
989         /* warning: blocks need to be freed each time, handlers dont remove  */
990         uiFreeBlocksWin(&sa->uiblocks, sa->win);
991
992         /* only try to refresh action that's displayed if not pinned */
993         if (G.saction->pin==0) {
994                 if (OBACT)
995                         G.saction->action = OBACT->action;
996                 else
997                         G.saction->action= NULL;
998         }
999         
1000         /* get data */
1001         data = get_action_context(&datatype);
1002         if (datatype == ACTCONT_ACTION)
1003                 act = data;
1004         else if (datatype == ACTCONT_SHAPEKEY)
1005                 key = data;
1006         
1007         /* Lets make sure the width of the left hand of the screen
1008          * is set to an appropriate value based on whether sliders
1009          * are showing of not
1010          */
1011         if ((data) && (G.saction->flag & SACTION_SLIDERS)) 
1012                 ACTWIDTH = NAMEWIDTH + SLIDERWIDTH;
1013         else 
1014                 ACTWIDTH = NAMEWIDTH;
1015
1016         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1017
1018         calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
1019
1020         /* background color for entire window (used in lefthand part though) */
1021         BIF_GetThemeColor3fv(TH_HEADER, col);
1022         glClearColor(col[0], col[1], col[2], 0.0); 
1023         glClear(GL_COLOR_BUFFER_BIT);
1024         
1025         if (curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
1026                 if(G.v2d->scroll) {     
1027                         ofsx= curarea->winrct.xmin;     
1028                         ofsy= curarea->winrct.ymin;
1029                         glViewport(ofsx+G.v2d->mask.xmin,  ofsy+G.v2d->mask.ymin, 
1030                                            ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, 
1031                                            ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1); 
1032                         glScissor(ofsx+G.v2d->mask.xmin,  ofsy+G.v2d->mask.ymin, 
1033                                           ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, 
1034                                           ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
1035                 }
1036         }
1037
1038         BIF_GetThemeColor3fv(TH_BACK, col);
1039         glClearColor(col[0], col[1], col[2], 0.0);
1040         glClear(GL_COLOR_BUFFER_BIT);
1041
1042         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
1043         bwin_clear_viewmat(sa->win);    /* clear buttons view */
1044         glLoadIdentity();
1045
1046         /*      Draw backdrop */
1047         calc_ipogrid(); 
1048         draw_ipogrid();
1049
1050         check_action_context(G.saction);
1051         
1052         /* Draw channel strips */
1053         draw_channel_strips();
1054         
1055         /* reset matrices for stuff to be drawn on top of keys*/
1056         glViewport(ofsx+G.v2d->mask.xmin,  
1057              ofsy+G.v2d->mask.ymin, 
1058              ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, 
1059              ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1); 
1060         glScissor(ofsx+G.v2d->mask.xmin,  
1061             ofsy+G.v2d->mask.ymin, 
1062             ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, 
1063             ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
1064         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax,  G.v2d->cur.ymin, G.v2d->cur.ymax);
1065         
1066         /* Draw current frame */
1067         draw_cfra_action();
1068         
1069         /* Draw markers (local behind scene ones, as local obscure scene markers) */
1070         if (act) 
1071                 draw_markers_timespace(&act->markers, DRAW_MARKERS_LOCAL);
1072         draw_markers_timespace(SCE_MARKERS, 0);
1073         
1074         /* Draw 'curtains' for preview */
1075         draw_anim_preview_timespace();
1076
1077         /* Draw scroll */
1078         mywinset(curarea->win); // reset scissor too
1079         if (curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
1080                 myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
1081                 if (G.v2d->scroll) drawscroll(0);
1082         }
1083
1084         /* Draw Left-Hand Panel if enough space in window */
1085         if (G.v2d->mask.xmin!=0) {
1086                 /* Draw channel names */
1087                 draw_channel_names();
1088                 
1089                 if(sa->winx > 50 + NAMEWIDTH + SLIDERWIDTH) {
1090                         if (act) {
1091                                 /* if there is an action, draw sliders for its
1092                                  * ipo-curve channels in the action window
1093                                  */
1094                                 action_icu_buts(G.saction);
1095                         }
1096                         else if (key) {
1097                                 /* if there is a mesh with rvk's selected,
1098                                  * then draw the key frames in the action window
1099                                  */
1100                                 meshactionbuts(G.saction, OBACT, key);
1101                         }
1102                 }
1103         }
1104         
1105         mywinset(curarea->win); // reset scissor too
1106         myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
1107         draw_area_emboss(sa);
1108
1109         /* it is important to end a view in a transform compatible with buttons */
1110         bwin_scalematrix(sa->win, G.saction->blockscale, G.saction->blockscale, G.saction->blockscale);
1111         action_blockhandlers(sa);
1112
1113         curarea->win_swap= WIN_BACK_OK;
1114 }
1115
1116 /* *************************** Keyframe Drawing *************************** */
1117
1118 static void add_bezt_to_keycolumnslist(ListBase *keys, BezTriple *bezt)
1119 {
1120         /* The equivilant of add_to_cfra_elem except this version 
1121          * makes ActKeyColumns - one of the two datatypes required
1122          * for action editor drawing.
1123          */
1124         ActKeyColumn *ak, *akn;
1125         
1126         if (ELEM(NULL, keys, bezt)) return;
1127         
1128         /* try to any existing key to replace, or where to insert after */
1129         for (ak= keys->last; ak; ak= ak->prev) {
1130                 /* do because of double keys */
1131                 if (ak->cfra == bezt->vec[1][0]) {                      
1132                         /* set selection status and 'touched' status */
1133                         if (BEZSELECTED(bezt)) ak->sel = SELECT;
1134                         ak->modified += 1;
1135                         
1136                         return;
1137                 }
1138                 else if (ak->cfra < bezt->vec[1][0]) break;
1139         }
1140         
1141         /* add new block */
1142         akn= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
1143         if (ak) BLI_insertlinkafter(keys, ak, akn);
1144         else BLI_addtail(keys, akn);
1145         
1146         akn->cfra= bezt->vec[1][0];
1147         akn->modified += 1;
1148         
1149         // TODO: handle type = bezt->h1 or bezt->h2
1150         akn->handle_type= 0; 
1151         
1152         if (BEZSELECTED(bezt))
1153                 akn->sel = SELECT;
1154         else
1155                 akn->sel = 0;
1156 }
1157
1158 static void add_bezt_to_keyblockslist(ListBase *blocks, IpoCurve *icu, int index)
1159 {
1160         /* The equivilant of add_to_cfra_elem except this version 
1161          * makes ActKeyBlocks - one of the two datatypes required
1162          * for action editor drawing.
1163          */
1164         ActKeyBlock *ab, *abn;
1165         BezTriple *beztn=NULL, *prev=NULL;
1166         BezTriple *bezt;
1167         int v;
1168         
1169         /* get beztriples */
1170         beztn= (icu->bezt + index);
1171         
1172         /* we need to go through all beztriples, as they may not be in order (i.e. during transform) */
1173         for (v=0, bezt=icu->bezt; v<icu->totvert; v++, bezt++) {
1174                 /* skip if beztriple is current */
1175                 if (v != index) {
1176                         /* check if beztriple is immediately before */
1177                         if (beztn->vec[1][0] > bezt->vec[1][0]) {
1178                                 /* check if closer than previous was */
1179                                 if (prev) {
1180                                         if (prev->vec[1][0] < bezt->vec[1][0])
1181                                                 prev= bezt;
1182                                 }
1183                                 else {
1184                                         prev= bezt;
1185                                 }
1186                         }
1187                 }
1188         }
1189         
1190         /* check if block needed - same value(s)?
1191          *      -> firstly, handles must have same central value as each other
1192          *      -> secondly, handles which control that section of the curve must be constant
1193          */
1194         if ((!prev) || (!beztn)) return;
1195         if (IS_EQ(beztn->vec[1][1], prev->vec[1][1])==0) return;
1196         if (IS_EQ(beztn->vec[1][1], beztn->vec[0][1])==0) return;
1197         if (IS_EQ(prev->vec[1][1], prev->vec[2][1])==0) return;
1198         
1199         /* try to find a keyblock that starts on the previous beztriple */
1200         for (ab= blocks->last; ab; ab= ab->prev) {
1201                 /* check if alter existing block or add new block */
1202                 if (ab->start == prev->vec[1][0]) {                     
1203                         /* set selection status and 'touched' status */
1204                         if (BEZSELECTED(beztn)) ab->sel = SELECT;
1205                         ab->modified += 1;
1206                         
1207                         return;
1208                 }
1209                 else if (ab->start < prev->vec[1][0]) break;
1210         }
1211         
1212         /* add new block */
1213         abn= MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");
1214         if (ab) BLI_insertlinkafter(blocks, ab, abn);
1215         else BLI_addtail(blocks, abn);
1216         
1217         abn->start= prev->vec[1][0];
1218         abn->end= beztn->vec[1][0];
1219         abn->val= beztn->vec[1][1];
1220         
1221         if (BEZSELECTED(prev) || BEZSELECTED(beztn))
1222                 abn->sel = SELECT;
1223         else
1224                 abn->sel = 0;
1225         abn->modified = 1;
1226 }
1227
1228 /* helper function - find actkeycolumn that occurs on cframe */
1229 static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe)
1230 {
1231         ActKeyColumn *ak, *ak2;
1232         
1233         if (keys==NULL) 
1234                 return NULL;
1235          
1236         /* search from both ends at the same time, and stop if we find match or if both ends meet */ 
1237         for (ak=keys->first, ak2=keys->last; ak && ak2; ak=ak->next, ak2=ak2->prev) {
1238                 /* return whichever end encounters the frame */
1239                 if (ak->cfra == cframe)
1240                         return ak;
1241                 if (ak2->cfra == cframe)
1242                         return ak2;
1243                 
1244                 /* no matches on either end, so return NULL */
1245                 if (ak == ak2)
1246                         return NULL;
1247         }
1248         
1249         return NULL;
1250 }
1251
1252 #if 0  // disabled, as some intel cards have problems with this
1253 /* Draw a simple diamond shape with a filled in center (in screen space) */
1254 static void draw_key_but(int x, int y, short w, short h, int sel)
1255 {
1256         int xmin= x, ymin= y;
1257         int xmax= x+w-1, ymax= y+h-1;
1258         int xc= (xmin+xmax)/2, yc= (ymin+ymax)/2;
1259         
1260         /* interior - hardcoded colors (for selected and unselected only) */
1261         if (sel) glColor3ub(0xF1, 0xCA, 0x13);
1262         else glColor3ub(0xE9, 0xE9, 0xE9);
1263         
1264         glBegin(GL_QUADS);
1265         glVertex2i(xc, ymin);
1266         glVertex2i(xmax, yc);
1267         glVertex2i(xc, ymax);
1268         glVertex2i(xmin, yc);
1269         glEnd();
1270         
1271         
1272         /* outline */
1273         glColor3ub(0, 0, 0);
1274         
1275         glBegin(GL_LINE_LOOP);
1276         glVertex2i(xc, ymin);
1277         glVertex2i(xmax, yc);
1278         glVertex2i(xc, ymax);
1279         glVertex2i(xmin, yc);
1280         glEnd();
1281 }
1282 #endif
1283
1284 static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos)
1285 {
1286         ActKeyColumn *ak;
1287         ActKeyBlock *ab;
1288         
1289         glEnable(GL_BLEND);
1290         
1291         /* draw keyblocks */
1292         if (blocks) {
1293                 for (ab= blocks->first; ab; ab= ab->next) {
1294                         short startCurves, endCurves, totCurves;
1295                         
1296                         /* find out how many curves occur at each keyframe */
1297                         ak= cfra_find_actkeycolumn(keys, ab->start);
1298                         startCurves = (ak)? ak->totcurve: 0;
1299                         
1300                         ak= cfra_find_actkeycolumn(keys, ab->end);
1301                         endCurves = (ak)? ak->totcurve: 0;
1302                         
1303                         /* only draw keyblock if it appears in at all of the keyframes at lowest end */
1304                         if (!startCurves && !endCurves) 
1305                                 continue;
1306                         else
1307                                 totCurves = (startCurves>endCurves)? endCurves: startCurves;
1308                                 
1309                         if (ab->totcurve >= totCurves) {
1310                                 int sc_xa, sc_ya;
1311                                 int sc_xb, sc_yb;
1312                                 
1313                                 /* get co-ordinates of block */
1314                                 gla2DDrawTranslatePt(di, ab->start, ypos, &sc_xa, &sc_ya);
1315                                 gla2DDrawTranslatePt(di, ab->end, ypos, &sc_xb, &sc_yb);
1316                                 
1317                                 /* draw block */
1318                                 if (ab->sel)
1319                                         BIF_ThemeColor4(TH_STRIP_SELECT);
1320                                 else
1321                                         BIF_ThemeColor4(TH_STRIP);
1322                                 glRectf(sc_xa,  sc_ya-3,  sc_xb,  sc_yb+5);
1323                         }
1324                 }
1325         }
1326         
1327         /* draw keys */
1328         if (keys) {
1329                 for (ak= keys->first; ak; ak= ak->next) {
1330                         int sc_x, sc_y;
1331                         
1332                         /* get co-ordinate to draw at */
1333                         gla2DDrawTranslatePt(di, ak->cfra, ypos, &sc_x, &sc_y);
1334                         
1335                         /* draw using icons - old way which is slower but more proven */
1336                         if(ak->sel & SELECT) BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE2, 1.0f);
1337                         else BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE3, 1.0f);
1338                         
1339                         /* draw using OpenGL - slightly uglier but faster */
1340                         //      NOTE: disabled for now, as some intel cards seem to have problems with this
1341                         //draw_key_but(sc_x-5, sc_y-4, 11, 11, (ak->sel & SELECT));
1342                 }       
1343         }
1344         
1345         glDisable(GL_BLEND);
1346 }
1347
1348
1349 static ActKeysInc *init_aki_data()
1350 {
1351         static ActKeysInc aki;
1352         
1353         /* init data of static struct here */
1354         if ((curarea->spacetype == SPACE_ACTION) && NLA_ACTION_SCALED)
1355                 aki.ob= OBACT;
1356         else if (curarea->spacetype == SPACE_NLA)
1357                 aki.ob= NULL; // FIXME
1358         else
1359                 aki.ob= NULL;
1360                 
1361         aki.start= G.v2d->cur.xmin - 10;
1362         aki.end= G.v2d->cur.xmax + 10;
1363         
1364         /* only pass pointer for Action Editor if enabled (for now) */
1365         if ((curarea->spacetype == SPACE_ACTION) && (G.saction->flag & SACTION_HORIZOPTIMISEON))
1366                 return &aki;
1367         else    
1368                 return NULL;
1369 }
1370
1371 void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos)
1372 {
1373         ListBase keys = {0, 0};
1374         ListBase blocks = {0, 0};
1375         ActKeysInc *aki = init_aki_data();
1376
1377         ob_to_keylist(ob, &keys, &blocks, aki);
1378         draw_keylist(di, &keys, &blocks, ypos);
1379         
1380         BLI_freelistN(&keys);
1381         BLI_freelistN(&blocks);
1382 }
1383
1384 void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos)
1385 {
1386         ListBase keys = {0, 0};
1387         ListBase blocks = {0, 0};
1388         ActKeysInc *aki = init_aki_data();
1389
1390         ipo_to_keylist(ipo, &keys, &blocks, aki);
1391         draw_keylist(di, &keys, &blocks, ypos);
1392         
1393         BLI_freelistN(&keys);
1394         BLI_freelistN(&blocks);
1395 }
1396
1397 void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos)
1398 {
1399         ListBase keys = {0, 0};
1400         ListBase blocks = {0, 0};
1401         ActKeysInc *aki = init_aki_data();
1402
1403         icu_to_keylist(icu, &keys, &blocks, aki);
1404         draw_keylist(di, &keys, &blocks, ypos);
1405         
1406         BLI_freelistN(&keys);
1407         BLI_freelistN(&blocks);
1408 }
1409
1410 void draw_agroup_channel(gla2DDrawInfo *di, bActionGroup *agrp, float ypos)
1411 {
1412         ListBase keys = {0, 0};
1413         ListBase blocks = {0, 0};
1414         ActKeysInc *aki = init_aki_data();
1415
1416         agroup_to_keylist(agrp, &keys, &blocks, aki);
1417         draw_keylist(di, &keys, &blocks, ypos);
1418         BLI_freelistN(&keys);
1419         BLI_freelistN(&blocks);
1420 }
1421
1422 void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos)
1423 {
1424         ListBase keys = {0, 0};
1425         ActKeysInc *aki = init_aki_data();
1426
1427         action_to_keylist(act, &keys, NULL, aki);
1428         draw_keylist(di, &keys, NULL, ypos);
1429         BLI_freelistN(&keys);
1430 }
1431
1432 /* --------------- Conversion: data -> keyframe list ------------------ */
1433
1434 void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
1435 {
1436         bConstraintChannel *conchan;
1437
1438         if (ob) {
1439                 /* Add object keyframes */
1440                 if (ob->ipo)
1441                         ipo_to_keylist(ob->ipo, keys, blocks, aki);
1442                 
1443                 /* Add constraint keyframes */
1444                 for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) {
1445                         if (conchan->ipo)
1446                                 ipo_to_keylist(conchan->ipo, keys, blocks, aki);                
1447                 }
1448                         
1449                 /* Add object data keyframes */
1450                 //              TODO??
1451         }
1452 }
1453
1454 static short bezt_in_aki_range (ActKeysInc *aki, BezTriple *bezt)
1455 {
1456         /* when aki == NULL, we don't care about range */
1457         if (aki == NULL) 
1458                 return 1;
1459                 
1460         /* if nla-scaling is in effect, apply appropriate scaling adjustments */
1461         if (aki->ob) {
1462                 float frame= get_action_frame_inv(aki->ob, bezt->vec[1][0]);
1463                 return IN_RANGE(frame, aki->start, aki->end);
1464         }
1465         else {
1466                 /* check if in range */
1467                 return IN_RANGE(bezt->vec[1][0], aki->start, aki->end);
1468         }
1469 }
1470
1471 void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
1472 {
1473         BezTriple *bezt;
1474         ActKeyColumn *ak, *ak2;
1475         ActKeyBlock *ab, *ab2;
1476         int v;
1477         
1478         if (icu && icu->totvert) {
1479                 /* loop through beztriples, making ActKeys and ActKeyBlocks */
1480                 bezt= icu->bezt;
1481                 
1482                 for (v=0; v<icu->totvert; v++, bezt++) {
1483                         /* only if keyframe is in range (optimisation) */
1484                         if (bezt_in_aki_range(aki, bezt)) {
1485                                 add_bezt_to_keycolumnslist(keys, bezt);
1486                                 if (blocks) add_bezt_to_keyblockslist(blocks, icu, v);
1487                         }
1488                 }
1489                 
1490                 /* update the number of curves that elements have appeared in  */
1491                 if (keys) {
1492                         for (ak=keys->first, ak2=keys->last; ak && ak2; ak=ak->next, ak2=ak2->prev) {
1493                                 if (ak->modified) {
1494                                         ak->modified = 0;
1495                                         ak->totcurve += 1;
1496                                 }
1497                                 if (ak2->modified) {
1498                                         ak2->modified = 0;
1499                                         ak2->totcurve += 1;
1500                                 }
1501                                 
1502                                 if (ak == ak2)
1503                                         break;
1504                         }
1505                 }
1506                 if (blocks) {
1507                         for (ab=blocks->first, ab2=blocks->last; ab && ab2; ab=ab->next, ab2=ab2->prev) {
1508                                 if (ab->modified) {
1509                                         ab->modified = 0;
1510                                         ab->totcurve += 1;
1511                                 }
1512                                 if (ab2->modified) {
1513                                         ab2->modified = 0;
1514                                         ab2->totcurve += 1;
1515                                 }
1516                                 
1517                                 if (ab == ab2)
1518                                         break;
1519                         }
1520                 }
1521         }
1522 }
1523
1524 void ipo_to_keylist(Ipo *ipo, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
1525 {
1526         IpoCurve *icu;
1527         
1528         if (ipo) {
1529                 for (icu= ipo->curve.first; icu; icu= icu->next)
1530                         icu_to_keylist(icu, keys, blocks, aki);
1531         }
1532 }
1533
1534 void agroup_to_keylist(bActionGroup *agrp, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
1535 {
1536         bActionChannel *achan;
1537         bConstraintChannel *conchan;
1538
1539         if (agrp) {
1540                 /* loop through action channels */
1541                 for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
1542                         if (VISIBLE_ACHAN(achan)) {
1543                                 /* firstly, add keys from action channel's ipo block */
1544                                 if (achan->ipo)
1545                                         ipo_to_keylist(achan->ipo, keys, blocks, aki);
1546                                 
1547                                 /* then, add keys from constraint channels */
1548                                 for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) {
1549                                         if (conchan->ipo)
1550                                                 ipo_to_keylist(conchan->ipo, keys, blocks, aki);
1551                                 }
1552                         }
1553                 }
1554         }
1555 }
1556
1557 void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
1558 {
1559         bActionChannel *achan;
1560         bConstraintChannel *conchan;
1561
1562         if (act) {
1563                 /* loop through action channels */
1564                 for (achan= act->chanbase.first; achan; achan= achan->next) {
1565                         /* firstly, add keys from action channel's ipo block */
1566                         if (achan->ipo)
1567                                 ipo_to_keylist(achan->ipo, keys, blocks, aki);
1568                         
1569                         /* then, add keys from constraint channels */
1570                         for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) {
1571                                 if (conchan->ipo)
1572                                         ipo_to_keylist(conchan->ipo, keys, blocks, aki);
1573                         }
1574                 }
1575         }
1576 }
1577