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