== PoseLib - Overhauled Implementation ==
[blender.git] / source / blender / src / edittime.c
1 /**
2  * $Id: BIF_edittime.c
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): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <string.h>
34 #include <math.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_arithb.h"
44
45 #include "DNA_action_types.h"
46 #include "DNA_ipo_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_space_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_userdef_types.h"
53
54 #include "BKE_ipo.h"
55 #include "BKE_utildefines.h"
56 #include "BKE_global.h"
57 #include "BKE_main.h"
58 #include "BKE_material.h"
59 #include "BKE_library.h"
60
61 #include "BIF_space.h"
62 #include "BIF_screen.h"
63 #include "BIF_interface.h"
64 #include "BIF_toolbox.h"
65 #include "BIF_mywindow.h"
66 #include "BIF_editaction.h"
67
68 #include "BSE_drawipo.h"
69 #include "BSE_edit.h"
70 #include "BSE_headerbuttons.h"
71 #include "BSE_time.h"
72
73 #include "BDR_editobject.h"
74
75 #include "blendef.h"
76
77 #include "mydevice.h"
78
79 #include "PIL_time.h"
80
81 /* declarations */
82 void winqreadtimespace(ScrArea *, void *, BWinEvent *);
83
84 /* ************* Marker API **************** */
85
86 /* add TimeMarker at curent frame */
87 void add_marker(int frame)
88 {
89         TimeMarker *marker;
90         
91         /* two markers can't be at the same place */
92         for(marker= G.scene->markers.first; marker; marker= marker->next)
93                 if(marker->frame == frame) return;
94         /* deselect all */
95         for(marker= G.scene->markers.first; marker; marker= marker->next)
96                 marker->flag &= ~SELECT;
97                 
98         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
99         marker->flag= SELECT;
100         marker->frame= frame;
101         BLI_addtail(&(G.scene->markers), marker);
102         
103         BIF_undo_push("Add Marker");
104 }
105
106
107
108 /* remove selected TimeMarkers */
109 void remove_marker(void)
110 {
111         TimeMarker *marker, *nmarker;
112         short changed= 0;
113                 
114         for(marker= G.scene->markers.first; marker; marker= nmarker) {
115                 nmarker= marker->next;
116                 if(marker->flag & SELECT) {
117                         BLI_freelinkN(&(G.scene->markers), marker);
118                         changed= 1;
119                 }
120         }
121         
122         if (changed)
123                 BIF_undo_push("Remove Marker");
124 }
125
126 /* rename first selected TimeMarker */
127 void rename_marker(void)
128 {
129         TimeMarker *marker;
130         char name[64];
131                         
132         for(marker= G.scene->markers.first; marker; marker= marker->next) {
133                 if(marker->flag & SELECT) {
134                         strcpy(name, marker->name);
135                         if (sbutton(name, 0, sizeof(name)-1, "Name: "))
136                                 BLI_strncpy(marker->name, name, sizeof(marker->name));
137                         break;
138                 }
139         }
140         
141 //      BIF_undo_push("Rename Marker");
142 }
143
144 /* duplicate selected TimeMarkers */
145 void duplicate_marker(void)
146 {
147         TimeMarker *marker, *newmarker;
148         
149         /* go through the list of markers, duplicate selected markers and add duplicated copies
150          * to the begining of the list (unselect original markers) */
151         for(marker= G.scene->markers.first; marker; marker= marker->next) {
152                 if(marker->flag & SELECT){
153                         /* unselect selected marker */
154                         marker->flag &= ~SELECT;
155                         /* create and set up new marker */
156                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
157                         newmarker->flag= SELECT;
158                         newmarker->frame= marker->frame;
159                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
160                         /* new marker is added to the begining of list */
161                         BLI_addhead(&(G.scene->markers), newmarker);
162                 }
163         }
164         
165         transform_markers('g', 0);
166 }
167
168 void transform_markers(int mode, int smode)     // mode and smode unused here, for callback
169 {
170         SpaceLink *slink= curarea->spacedata.first;
171         SpaceTime *stime= curarea->spacedata.first;
172         SpaceAction *saction = curarea->spacedata.first;
173         TimeMarker *marker, *selmarker=NULL;
174         float dx, fac;
175         int a, ret_val= 0, totmark=0, *oldframe, offs, firsttime=1;
176         unsigned short event;
177         short val, pmval[2], mval[2], mvalo[2];
178         char str[32];
179         
180         for(marker= G.scene->markers.first; marker; marker= marker->next) {
181                 if(marker->flag & SELECT) totmark++;
182         }
183         if(totmark==0) return;
184         
185         oldframe= MEM_mallocN(totmark*sizeof(int), "marker array");
186         for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
187                 if(marker->flag & SELECT) {
188                         oldframe[a]= marker->frame;
189                         selmarker= marker;      // used for hederprint
190                         a++;
191                 }
192         }
193         
194         dx= G.v2d->mask.xmax-G.v2d->mask.xmin;
195         dx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/dx;
196         
197         getmouseco_areawin(pmval);
198         mvalo[0]= pmval[0];
199         
200         while(ret_val == 0) {
201                 
202                 getmouseco_areawin(mval);
203                 
204                 if (mval[0] != mvalo[0] || firsttime) {
205                         mvalo[0]= mval[0];
206                         firsttime= 0;
207                         
208                         fac= (((float)(mval[0] - pmval[0]))*dx);
209                         
210                         if (ELEM(slink->spacetype, SPACE_TIME, SPACE_SOUND)) 
211                                 apply_keyb_grid(&fac, 0.0, FPS, 0.1*FPS, 0);
212                         else
213                                 apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
214                         offs= (int)fac;
215                         
216                         for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
217                                 if(marker->flag & SELECT) {
218                                         marker->frame= oldframe[a] + offs;
219                                         a++;
220                                 }
221                         }
222                         
223                         if(totmark==1) {        // we print current marker value
224                                 if (ELEM(slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
225                                         if (stime->flag & TIME_DRAWFRAMES) 
226                                                 sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
227                                         else 
228                                                 sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
229                                 }
230                                 else if (slink->spacetype == SPACE_ACTION) {
231                                         if (saction->flag & SACTION_DRAWTIME)
232                                                 sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
233                                         else
234                                                 sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
235                                 }
236                                 else {
237                                         sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
238                                 }
239                         }
240                         else {
241                                 if (ELEM(slink->spacetype, SPACE_TIME, SPACE_SOUND)) { 
242                                         if (stime->flag & TIME_DRAWFRAMES) 
243                                                 sprintf(str, "Marker offset %d ", offs);
244                                         else 
245                                                 sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
246                                 }
247                                 else if (slink->spacetype == SPACE_ACTION) {
248                                         if (saction->flag & SACTION_DRAWTIME)
249                                                 sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
250                                         else
251                                                 sprintf(str, "Marker offset %.2f ", (double)(offs));
252                                 }
253                                 else {
254                                         sprintf(str, "Marker offset %.2f ", (double)(offs));
255                                 }
256                         }
257                         headerprint(str);
258                         
259                         force_draw(0);  // areas identical to this, 0 = no header
260                 }
261                 else PIL_sleep_ms(10);  // idle
262                 
263                 /* emptying queue and reading events */
264                 while( qtest() ) {
265                         event= extern_qread(&val);
266                         
267                         if(val) {
268                                 if(event==ESCKEY || event==RIGHTMOUSE) ret_val= 2;
269                                 else if(event==LEFTMOUSE || event==RETKEY || event==SPACEKEY) ret_val= 1;
270                         }
271                 }
272         }
273         
274         /* restore? */
275         if(ret_val==2) {
276                 for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
277                         if(marker->flag & SELECT) {
278                                 marker->frame= oldframe[a];
279                                 a++;
280                         }
281                 }
282         }
283         else {
284                 BIF_undo_push("Move Markers");
285         }
286         MEM_freeN(oldframe);
287         allqueue(REDRAWMARKER, 0);
288 }
289
290 /* select/deselect all TimeMarkers
291  *      test - based on current selections?
292  *      sel - selection status to set all markers to if blanket apply status
293  */
294 void deselect_markers(short test, short sel)
295 {
296         TimeMarker *marker;
297                 
298         /* check if need to find out whether to how to select markers */
299         if (test) {
300                 /* dependant on existing selection */
301                 /* determine if select all or deselect all */
302                 sel = 1;
303                 for (marker= G.scene->markers.first; marker; marker= marker->next) {
304                         if (marker->flag & SELECT) {
305                                 sel = 0;
306                                 break;
307                         }
308                 }
309                 
310                 /* do selection */
311                 for (marker= G.scene->markers.first; marker; marker= marker->next) {
312                         if (sel == 2) {
313                                 marker->flag ^= SELECT;
314                         }
315                         else if (sel == 1) {
316                                 if ((marker->flag & SELECT)==0) 
317                                         marker->flag |= SELECT;
318                         }
319                         else {
320                                 if (marker->flag & SELECT)
321                                         marker->flag &= ~SELECT;
322                         }
323                 }
324         }
325         else {
326                 /* not dependant on existing selection */
327                 for (marker= G.scene->markers.first; marker; marker= marker->next) {
328                                 if (sel==2) {
329                                         marker->flag ^= SELECT;
330                                 }
331                                 else if (sel==1) {
332                                         if ((marker->flag & SELECT)==0)
333                                                 marker->flag |= SELECT;
334                                 }
335                                 else {
336                                         if (marker->flag & SELECT)
337                                                 marker->flag &= ~SELECT;
338                                 }
339                 }
340         }
341 }
342
343 static void borderselect_markers_func(float xmin, float xmax, int selectmode)
344 {
345         TimeMarker *marker;
346                 
347         for(marker= G.scene->markers.first; marker; marker= marker->next) {
348                 if ((marker->frame > xmin) && (marker->frame <= xmax)) {
349                         switch (selectmode) {
350                                 case SELECT_ADD:
351                                         if ((marker->flag & SELECT) == 0) 
352                                                 marker->flag |= SELECT;
353                                         break;
354                                 case SELECT_SUBTRACT:
355                                         if (marker->flag & SELECT) 
356                                                 marker->flag &= ~SELECT;
357                                         break;
358                         }
359                 }
360         }
361 }
362
363 /* border-select markers */
364 void borderselect_markers(void) 
365 {
366         rcti rect;
367         rctf rectf;
368         int val, selectmode;            
369         short   mval[2];
370
371         if ( (val = get_border(&rect, 3)) ){
372                 if (val == LEFTMOUSE)
373                         selectmode = SELECT_ADD;
374                 else
375                         selectmode = SELECT_SUBTRACT;
376
377                 mval[0]= rect.xmin;
378                 mval[1]= rect.ymin+2;
379                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
380                 mval[0]= rect.xmax;
381                 mval[1]= rect.ymax-2;
382                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
383                         
384                 /* do markers */
385                 borderselect_markers_func(rectf.xmin, rectf.xmax, selectmode);
386                 
387                 BIF_undo_push("Border Select Markers");
388                 allqueue(REDRAWMARKER, 0);
389         }
390 }
391
392 void nextprev_marker(short dir)
393 {
394         TimeMarker *marker, *cur=NULL, *first, *last;
395         int mindist= MAXFRAME, dist;
396                 
397         first= last= G.scene->markers.first; 
398         for(marker= G.scene->markers.first; marker; marker= marker->next) {
399                 /* find closest to current frame first */
400                 dist= (marker->frame/G.scene->r.framelen) - CFRA;
401                 if(dir==1 && dist>0 && dist<mindist) {
402                         mindist= dist;
403                         cur= marker;
404                 }
405                 else if(dir==-1 && dist<0 && -dist<mindist) {
406                         mindist= -dist;
407                         cur= marker;
408                 }
409                 /* find first/last */
410                 if(marker->frame > last->frame) last= marker;
411                 if(marker->frame < first->frame) first= marker;
412         }
413         
414         if(cur==NULL) {
415                 if(dir==1) cur= first;
416                 else cur= last;
417         }
418         if(cur) {
419                 CFRA= cur->frame/G.scene->r.framelen;
420                 update_for_newframe();
421                 allqueue(REDRAWALL, 0);
422         }
423 }
424
425 void get_minmax_markers(short sel, float *first, float *last)
426 {
427         TimeMarker *marker;
428         ListBase *markers;
429         float min, max;
430         int selcount = 0;
431         
432         markers= &(G.scene->markers);
433         
434         if (sel)
435                 for (marker= markers->first; marker; marker= marker->next) {
436                         if (marker->flag & SELECT)
437                                 selcount++;
438                 }
439         else {
440                 selcount= BLI_countlist(markers);
441         }
442         
443         if (markers->first && markers->last) {
444                 min= ((TimeMarker *)markers->first)->frame;
445                 max= ((TimeMarker *)markers->last)->frame;
446         }
447         else {
448                 *first = 0.0f;
449                 *last = 0.0f;
450                 return;
451         }
452         
453         if (selcount > 1) {
454                 for (marker= markers->first; marker; marker= marker->next) {
455                         if (sel) {
456                                 if (marker->flag & SELECT) {
457                                         if (marker->frame < min)
458                                                 min= marker->frame;
459                                         else if (marker->frame > max)
460                                                 max= marker->frame;
461                                 }
462                         }
463                         else {
464                                 if (marker->frame < min)
465                                         min= marker->frame;
466                                 else if (marker->frame > max)
467                                         max= marker->frame;
468                         }       
469                 }
470         }
471         
472         *first= min;
473         *last= max;
474 }
475
476 TimeMarker *find_nearest_marker(ListBase *markers, int clip_y)
477 {
478         TimeMarker *marker;
479         float xmin, xmax;
480         rctf    rectf;
481         short mval[2];
482         
483         getmouseco_areawin (mval);
484         
485         /* first clip selection in Y */
486         if ((clip_y) && (mval[1] > 30))
487                 return NULL;
488         
489         mval[0]-=7;
490         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
491         mval[0]+=14;
492         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
493         
494         xmin= rectf.xmin;
495         xmax= rectf.xmax;
496         
497         for (marker= markers->first; marker; marker= marker->next) {
498                 if ((marker->frame > xmin) && (marker->frame <= xmax)) {
499                         return marker;
500                 }
501         }
502         
503         return NULL;
504 }
505
506 /* Adds a marker to list of cfra elems */
507 void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
508 {
509         CfraElem *ce, *cen;
510         
511         /* should this one only be considered if it is selected? */
512         if ((only_sel) && ((marker->flag & SELECT)==0))
513                 return;
514         
515         /* try to find a previous cfra elem */
516         ce= lb->first;
517         while(ce) {
518                 
519                 if( ce->cfra==marker->frame ) {
520                         /* do because of double keys */
521                         if(marker->flag & SELECT) ce->sel= marker->flag;
522                         return;
523                 }
524                 else if(ce->cfra > marker->frame) break;
525                 
526                 ce= ce->next;
527         }       
528         
529         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
530         if(ce) BLI_insertlinkbefore(lb, ce, cen);
531         else BLI_addtail(lb, cen);
532
533         cen->cfra= marker->frame;
534         cen->sel= marker->flag;
535 }
536
537 /* This function makes a list of all the markers. The only_sel
538  * argument is used to specify whether only the selected markers
539  * are added.
540  */
541 void make_marker_cfra_list(ListBase *lb, short only_sel)
542 {
543         TimeMarker *marker;
544         
545         for (marker= G.scene->markers.first; marker; marker= marker->next) {
546                 add_marker_to_cfra_elem(lb, marker, only_sel);
547         }
548 }
549
550 int find_nearest_marker_time(float dx)
551 {
552         TimeMarker *marker, *nearest= NULL;
553         float dist, min_dist= 1000000;
554         
555         for(marker= G.scene->markers.first; marker; marker= marker->next) {
556                 dist = ABS((float)marker->frame - dx);
557                 if(dist < min_dist){
558                         min_dist= dist;
559                         nearest= marker;
560                 }
561         }
562         
563         if(nearest) return nearest->frame;
564         else return (int)floor(dx);
565 }
566
567 /* *********** End Markers - Markers API *************** */
568 /* select/deselect TimeMarker at current frame */
569 static void select_timeline_marker_frame(int frame, unsigned char shift)
570 {
571         TimeMarker *marker;
572         int select=0;
573         
574         for(marker= G.scene->markers.first; marker; marker= marker->next) {
575                 /* if Shift is not set, then deselect Markers */
576                 if(!shift) marker->flag &= ~SELECT;
577                 /* this way a not-shift select will allways give 1 selected marker */
578                 if((marker->frame == frame) && (!select)) {
579                         if(marker->flag & SELECT) 
580                                 marker->flag &= ~SELECT;
581                         else
582                                 marker->flag |= SELECT;
583                         select = 1;
584                 }
585         }
586 }
587
588 /* *********** end Markers - TimeLine *************** */
589
590 /* set the animation preview range of scene */
591 void anim_previewrange_set()
592 {
593         extern float get_action_frame(Object *ob, float cframe);
594         rcti rect;
595         rctf rectf;
596         short val, mval[2];
597         
598         /* set range by drawing border-select rectangle */
599         if ( (val = get_border(&rect, 5)) ) {   
600                 /* get frame numbers */
601                 mval[0]= rect.xmin;
602                 mval[1]= rect.ymin+2;
603                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
604                 mval[0]= rect.xmax;
605                 mval[1]= rect.ymax-2;
606                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
607                         
608                 /* set preview-range */
609                 if (rectf.xmin < 1) rectf.xmin = 1.0f;
610                 if (rectf.xmax < 1) rectf.xmax = 1.0f;
611                 G.scene->r.psfra= rectf.xmin;
612                 G.scene->r.pefra= rectf.xmax;
613                 
614                 BIF_undo_push("Set anim-preview range");
615                 allqueue(REDRAWTIME, 0);
616                 allqueue(REDRAWACTION, 0);
617                 allqueue(REDRAWNLA, 0);
618                 allqueue(REDRAWIPO, 0);
619                 allqueue(REDRAWBUTSALL, 0);
620         }
621 }
622
623 /* clear the animation preview range for scene */
624 void anim_previewrange_clear()
625 {
626         G.scene->r.psfra = 0;
627         G.scene->r.pefra = 0;
628         
629         BIF_undo_push("Clear anim-preview range");
630         allqueue(REDRAWTIME, 0);
631         allqueue(REDRAWACTION, 0);
632         allqueue(REDRAWNLA, 0);
633         allqueue(REDRAWBUTSALL, 0);
634 }
635
636 /* ************ end Animation Preview Range ********** */
637
638
639 static int float_to_frame(float frame) 
640 {
641         int to= (int) floor(0.5 + frame/G.scene->r.framelen );
642         
643         return to;      
644 }
645
646 static float find_closest_cfra_elem(ListBase elems, int dir, float closest)
647 {
648         CfraElem *ce;
649         
650         for(ce= elems.first; ce; ce= ce->next) {
651                 if (dir==-1) {
652                         if( float_to_frame(ce->cfra)<CFRA) {
653                                 if ((ce->cfra > closest) || (closest == CFRA)) {
654                                         closest= ce->cfra;
655                                 }
656                         }
657                 } 
658                 else {
659                         if(float_to_frame(ce->cfra)>CFRA) {
660                                 if ((ce->cfra < closest) || (closest == CFRA)) {
661                                         closest= ce->cfra;
662                                 }
663                         }
664                 }
665         }
666         return closest;
667 }
668
669 void nextprev_timeline_key(short dir)
670 {
671         /*mostly copied from drawobject.c, draw_object() AND editipo.c, movekey_obipo() */
672         Object *ob;
673         bActionChannel *achan;
674         bAction *act;
675         ListBase elems;
676         float closest= CFRA;
677         int a;
678         
679         if (OBACT) {
680                 ob = OBACT;
681                 
682                 if(ob) {
683                         if(ob!=G.obedit) {
684                                 if(ob->ipo) {
685                                         /* convert the ipo to a list of 'current frame elements' */
686                                         
687                                         elems.first= elems.last= NULL;
688                                         make_cfra_list(ob->ipo, &elems);
689                                         
690                                         closest= find_closest_cfra_elem(elems, dir, closest);
691                                         
692                                         BLI_freelistN(&elems);
693                                 }
694                                 
695                                 if(ob->action) {
696                                         act = ob->action;
697                                         /* go through each channel in the action */
698                                         for (achan=act->chanbase.first; achan; achan=achan->next){
699                                                 /* convert the ipo to a list of 'current frame elements' */
700                                                 
701                                                 if(achan->ipo) {
702                                                         elems.first= elems.last= NULL;
703                                                         make_cfra_list(achan->ipo, &elems);
704                                                         
705                                                         closest= find_closest_cfra_elem(elems, dir, closest);
706                                                         
707                                                         BLI_freelistN(&elems);
708                                                 }
709                                         }
710                                 }
711                                 
712                                 for(a=0; a<ob->totcol; a++) {
713                                         Material *ma= give_current_material(ob, a+1);
714                                         if(ma && ma->ipo) {
715                                                 elems.first= elems.last= NULL;
716                                                 make_cfra_list(ma->ipo, &elems);
717                                                 
718                                                 closest= find_closest_cfra_elem(elems, dir, closest);
719                                                 
720                                                 BLI_freelistN(&elems);
721                                         }
722                                 }
723                         }
724                 }
725                 
726                 a= float_to_frame(closest);
727                 
728                 if (a!=CFRA) {
729                         CFRA= a;
730                         update_for_newframe();
731                 }       
732                 
733                 BIF_undo_push("Next/Prev Key");
734                 allqueue(REDRAWALL, 0);
735         }
736 }
737
738 /* return the current marker for this frame,
739 we can have more then 1 marker per frame, this just returns the first :/ */
740 TimeMarker *get_frame_marker(int frame)
741 {
742         TimeMarker *marker, *best_marker = NULL;
743         int best_frame = -MAXFRAME*2; 
744         for (marker= G.scene->markers.first; marker; marker= marker->next) {
745                 if (marker->frame==frame) {
746                         return marker;
747                 }
748                 
749                 if ( marker->frame > best_frame && marker->frame < frame) {
750                         best_marker = marker;
751                         best_frame = marker->frame;
752                 }
753         }
754         
755         return best_marker;
756 }
757
758
759 void timeline_frame_to_center(void)
760 {
761         float dtime;
762         
763         dtime= CFRA*(G.scene->r.framelen) - (G.v2d->cur.xmin + G.v2d->cur.xmax)/2.0; 
764         G.v2d->cur.xmin += dtime;
765         G.v2d->cur.xmax += dtime;
766         scrarea_queue_winredraw(curarea);
767 }
768
769 /* copy of this is actually in editscreen.c, but event based */
770 static void timeline_force_draw(short val)
771 {
772         ScrArea *sa, *tempsa, *samin= NULL;
773         int dodraw;
774         
775         if(val & TIME_LEFTMOST_3D_WIN) {
776                 ScrArea *sa= G.curscreen->areabase.first;
777                 int min= 10000;
778                 for(; sa; sa= sa->next) {
779                         if(sa->spacetype==SPACE_VIEW3D) {
780                                 if(sa->winrct.xmin - sa->winrct.ymin < min) {
781                                         samin= sa;
782                                         min= sa->winrct.xmin - sa->winrct.ymin;
783                                 }
784                         }
785                 }
786         }
787         
788         tempsa= curarea;
789         sa= G.curscreen->areabase.first;
790         while(sa) {
791                 dodraw= 0;
792                 if(sa->spacetype==SPACE_VIEW3D) {
793                         if(sa==samin || (val & TIME_ALL_3D_WIN)) dodraw= 1;
794                 }
795                 else if(ELEM6(sa->spacetype, SPACE_NLA, SPACE_IPO, SPACE_SEQ, SPACE_BUTS, SPACE_ACTION, SPACE_SOUND)) {
796                         if(val & TIME_ALL_ANIM_WIN) dodraw= 1;
797                 }
798                 else if(sa->spacetype==SPACE_BUTS) {
799                         if(val & TIME_ALL_BUTS_WIN) dodraw= 1;
800                 }
801                 else if(sa->spacetype==SPACE_IMAGE) {
802                         if (val & TIME_ALL_IMAGE_WIN) dodraw = 1;
803                 }
804                 else if(sa->spacetype==SPACE_SEQ) {
805                         if (val & TIME_SEQ) dodraw = 1;
806                 }
807                 else if(sa->spacetype==SPACE_TIME) dodraw= 2;
808                 
809                 if(dodraw) {
810                         areawinset(sa->win);
811                         scrarea_do_windraw(sa);
812                         if(dodraw==2) scrarea_do_headdraw(sa);
813                 }
814                 sa= sa->next;
815         }
816         areawinset(tempsa->win);
817         
818         screen_swapbuffers();
819
820 }
821
822 /* ***************************** */
823
824 /* Right. Now for some implementation: */
825 void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
826 {
827         SpaceTime *stime= spacedata;
828         unsigned short event= evt->event;
829         short val= evt->val;
830         float dx, dy;
831         int doredraw= 0, cfra, first = 0;
832         short mval[2], nr;
833         short mousebut = L_MOUSE;
834         
835         if(sa->win==0) return;
836
837         if(val) {
838                 
839                 if( uiDoBlocks(&sa->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
840
841                 /* swap mouse buttons based on user preference */
842                 if (U.flag & USER_LMOUSESELECT) {
843                         if (event == LEFTMOUSE) {
844                                 event = RIGHTMOUSE;
845                                 mousebut = L_MOUSE;
846                         } else if (event == RIGHTMOUSE) {
847                                 event = LEFTMOUSE;
848                                 mousebut = R_MOUSE;
849                         }
850                 }
851
852                 switch(event) {
853                 case LEFTMOUSE:
854                         stime->flag |= TIME_CFRA_NUM;
855                         do {
856                                 getmouseco_areawin(mval);
857                                 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
858                                 
859                                 cfra = (int)dx;
860                                 if(cfra< MINFRAME) cfra= MINFRAME;
861                                 
862                                 if( cfra!=CFRA || first )
863                                 {
864                                         first= 0;
865                                         CFRA= cfra;
866                                         update_for_newframe_nodraw(0);  // 1= nosound
867                                         timeline_force_draw(stime->redraws);
868                                 }
869                                 else PIL_sleep_ms(30);
870                         
871                         } while(get_mbut() & mousebut);
872                         
873                         stime->flag &= ~TIME_CFRA_NUM;
874                         allqueue(REDRAWALL, 0);
875                         break;
876                         
877                 case RIGHTMOUSE: /* select/deselect marker */
878                         getmouseco_areawin(mval);
879                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
880                         
881                         cfra= find_nearest_marker_time(dx);
882                         
883                         if (G.qual && LR_SHIFTKEY)
884                                 select_timeline_marker_frame(cfra, 1);
885                         else
886                                 select_timeline_marker_frame(cfra, 0);
887                         
888                         force_draw(0);
889                         std_rmouse_transform(transform_markers);
890
891                         break;
892                 case MIDDLEMOUSE:
893                 case WHEELUPMOUSE:
894                 case WHEELDOWNMOUSE:
895                         view2dmove(event);      /* in drawipo.c */
896                         break;
897                 case PADPLUSKEY:
898                         dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
899                         G.v2d->cur.xmin+= dx;
900                         G.v2d->cur.xmax-= dx;
901                         test_view2d(G.v2d, sa->winx, sa->winy);
902                         view2d_do_locks(curarea, V2D_LOCK_COPY);
903                         doredraw= 1;
904                         break;
905                 case PADMINUS:
906                         dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
907                         G.v2d->cur.xmin-= dx;
908                         G.v2d->cur.xmax+= dx;
909                         test_view2d(G.v2d, sa->winx, sa->winy);
910                         view2d_do_locks(curarea, V2D_LOCK_COPY);
911                         doredraw= 1;
912                         break;
913                 case HOMEKEY:
914                         first= G.scene->r.sfra;
915                         if(first >= G.scene->r.efra) first= G.scene->r.efra;
916                         G.v2d->cur.xmin=G.v2d->tot.xmin= (float)first-2;
917                         G.v2d->cur.xmax=G.v2d->tot.xmax= (float)G.scene->r.efra+2;
918                         doredraw= 1;
919                         break;
920                         
921                 case PAGEUPKEY: /* next keyframe */
922                         if(G.qual==LR_CTRLKEY)
923                                 nextprev_timeline_key(1);
924                         else
925                                 nextprev_marker(1);
926                         break;
927                 case PAGEDOWNKEY: /* prev keyframe */
928                         if(G.qual==LR_CTRLKEY)
929                                 nextprev_timeline_key(-1);
930                         else
931                                 nextprev_marker(-1);
932                         break;
933                         
934                 case AKEY:
935                         /* deselect all TimeMarkers */
936                         deselect_markers(1, 0);
937                         allqueue(REDRAWMARKER, 0);
938                         break;
939                 case BKEY:
940                         /* borderselect markers */
941                         borderselect_markers();
942                         break;
943                 case DKEY:
944                         if(G.qual==LR_SHIFTKEY)
945                                 duplicate_marker();
946                         break;
947                 case CKEY:
948                         timeline_frame_to_center();
949                         break;
950                 case GKEY: /* move marker */
951                         transform_markers('g', 0);
952                         break;
953                 case EKEY: /* set end frame */
954                         if (G.scene->r.psfra) {
955                                 if (CFRA < G.scene->r.psfra)
956                                         G.scene->r.psfra= CFRA;
957                                 G.scene->r.pefra= CFRA;
958                         }                               
959                         else
960                                 G.scene->r.efra = CFRA;
961                         allqueue(REDRAWALL, 1);
962                         break;
963                 case MKEY: /* add, rename marker */
964                         if (G.qual & LR_CTRLKEY)
965                                 rename_marker();
966                         else
967                                 add_marker(CFRA);
968                         allqueue(REDRAWMARKER, 0);
969                         break;
970                 case PKEY:      /* preview-range stuff */
971                         if (G.qual & LR_CTRLKEY) /* set preview range */
972                                 anim_previewrange_set();
973                         else if (G.qual & LR_ALTKEY) /* clear preview range */
974                                 anim_previewrange_clear();
975                         break;
976                 case SKEY: /* set start frame */
977                         if (G.scene->r.psfra) {
978                                 if (G.scene->r.pefra < CFRA)
979                                         G.scene->r.pefra= CFRA;
980                                 G.scene->r.psfra= CFRA;
981                         }                               
982                         else
983                                 G.scene->r.sfra = CFRA;
984                         allqueue(REDRAWALL, 1);
985                         break;
986                 case TKEY: /* popup menu */
987                         nr= pupmenu("Time value%t|Frames %x1|Seconds%x2");
988                         if (nr>0) {
989                                 if(nr==1) stime->flag |= TIME_DRAWFRAMES;
990                                 else stime->flag &= ~TIME_DRAWFRAMES;
991                                 doredraw= 1;
992                         }
993                         break;
994                 case DELKEY:
995                 case XKEY:
996                         if( okee("Erase selected")==0 ) break;
997
998                         remove_marker();
999                         allqueue(REDRAWMARKER, 0);
1000                         break;
1001                 }
1002         }
1003
1004         if(doredraw)
1005                 scrarea_queue_winredraw(sa);
1006 }
1007
1008