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