Orange:
[blender.git] / source / blender / src / edittime.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): 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
67 #include "BSE_drawipo.h"
68 #include "BSE_headerbuttons.h"
69 #include "BSE_time.h"
70
71 #include "BDR_editobject.h"
72
73 #include "blendef.h"
74
75 #include "mydevice.h"
76
77 #include "PIL_time.h"
78
79 /* declarations */
80 void winqreadtimespace(ScrArea *, void *, BWinEvent *);
81
82 /* ************* Timeline marker code **************** */
83
84 /* add TimeMarker at curent frame */
85 void add_timeline_marker(int frame)
86 {
87         TimeMarker *marker;
88         
89         /* two markers can't be at the same place */
90         for(marker= G.scene->markers.first; marker; marker= marker->next)
91                 if(marker->frame == frame) return;
92         /* deselect all */
93         for(marker= G.scene->markers.first; marker; marker= marker->next)
94                 marker->flag &= ~SELECT;
95                 
96         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
97         marker->flag= SELECT;
98         marker->frame= frame;
99         BLI_addtail(&(G.scene->markers), marker);
100         
101         BIF_undo_push("Add Timeline Marker");
102 }
103
104 /* remove TimeMarker */
105 void remove_timeline_marker(void)
106 {
107         TimeMarker *marker;
108         
109         for(marker= G.scene->markers.first; marker; marker= marker->next) {
110                 if(marker->flag & SELECT){
111                         BLI_freelinkN(&G.scene->markers, marker);
112                 }
113         }
114         
115         BIF_undo_push("Remove Timeline Marker");
116 }
117
118 /* rename first selected TimeMarker */
119 void rename_timeline_marker(void)
120 {
121         TimeMarker *marker;
122         char name[64];
123         
124         for(marker= G.scene->markers.first; marker; marker= marker->next) {
125                 if(marker->flag & SELECT) {
126                         sprintf(name, marker->name);
127                         if (sbutton(name, 0, sizeof(name)-1, "Name: "))
128                                 BLI_strncpy(marker->name, name, sizeof(marker->name));
129                         break;
130                 }
131         }
132         
133         BIF_undo_push("Rename Timeline Marker");
134 }
135
136 /* duplicate selected TimeMarkers */
137 void duplicate_timeline_marker(void)
138 {
139         TimeMarker *marker, *newmarker;
140
141         /* go through the list of markers, duplicate selected markers and add duplicated copies
142          * to the begining of the list (unselect original markers) */
143         for(marker= G.scene->markers.first; marker; marker= marker->next) {
144                 if(marker->flag & SELECT){
145                         /* unselect selected marker */
146                         marker->flag &= ~SELECT;
147                         /* create and set up new marker */
148                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
149                         newmarker->flag= SELECT;
150                         newmarker->frame= marker->frame;
151                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
152                         /* new marker is added to the begining of list */
153                         BLI_addhead(&(G.scene->markers), newmarker);
154                 }
155         }
156         
157         timeline_grab('g', 0);
158 }
159
160
161
162 static int find_nearest_marker(float dx)
163 {
164         TimeMarker *marker, *nearest= NULL;
165         float dist, min_dist= 1000000;
166         
167         for(marker= G.scene->markers.first; marker; marker= marker->next) {
168                 dist = ABS((float)marker->frame - dx);
169                 if(dist < min_dist){
170                         min_dist= dist;
171                         nearest= marker;
172                 }
173         }
174         
175         if(nearest) return nearest->frame;
176         else return (int)floor(dx);
177 }
178
179 /* select/deselect TimeMarker at current frame */
180 static void select_timeline_marker_frame(int frame, unsigned char shift)
181 {
182         TimeMarker *marker;
183         int select=0;
184         
185         for(marker= G.scene->markers.first; marker; marker= marker->next) {
186                 /* if Shift is not set, then deselect Markers */
187                 if(!shift) marker->flag &= ~SELECT;
188                 /* this way a not-shift select will allways give 1 selected marker */
189                 if((marker->frame == frame) && (!select)) {
190                         if(marker->flag & SELECT) 
191                                 marker->flag &= ~SELECT;
192                         else
193                                 marker->flag |= SELECT;
194                         select = 1;
195                 }
196         }
197 }
198
199 /* select/deselect all TimeMarkers */
200 void select_timeline_markers(void)
201 {
202         TimeMarker *marker;
203         char any_selected= 0;
204         
205         for(marker= G.scene->markers.first; marker; marker= marker->next) {
206                 if(marker->flag & SELECT) any_selected= 1;
207                 marker->flag &= ~SELECT;
208         }
209         
210         /* no TimeMarker selected, then select all TimeMarkers */
211         if(!any_selected){
212                 for(marker= G.scene->markers.first; marker; marker= marker->next) {
213                         marker->flag |= SELECT;
214                 }
215         }
216 }
217
218 void nextprev_timeline_marker(short dir)
219 {
220         TimeMarker *marker, *cur=NULL, *first, *last;
221         int mindist= MAXFRAME, dist;
222         
223         first= last= G.scene->markers.first; 
224         for(marker= G.scene->markers.first; marker; marker= marker->next) {
225                 /* find closest to current frame first */
226                 dist= (marker->frame/G.scene->r.framelen) - CFRA;
227                 if(dir==1 && dist>0 && dist<mindist) {
228                         mindist= dist;
229                         cur= marker;
230                 }
231                 else if(dir==-1 && dist<0 && -dist<mindist) {
232                         mindist= -dist;
233                         cur= marker;
234                 }
235                 /* find first/last */
236                 if(marker->frame > last->frame) last= marker;
237                 if(marker->frame < first->frame) first= marker;
238         }
239         
240         if(cur==NULL) {
241                 if(dir==1) cur= first;
242                 else cur= last;
243         }
244         if(cur) {
245                 CFRA= cur->frame/G.scene->r.framelen;
246                 update_for_newframe();
247                 allqueue(REDRAWALL, 0);
248         }
249 }
250
251 /* *********** end Markers *************** */
252
253 static int float_to_frame(float frame) 
254 {
255         int to= (int) floor(0.5 + frame/G.scene->r.framelen );
256         
257         return to;      
258 }
259
260 static float find_closest_cfra_elem(ListBase elems, int dir, float closest)
261 {
262         CfraElem *ce;
263         
264         for(ce= elems.first; ce; ce= ce->next) {
265                 if (dir==-1) {
266                         if( float_to_frame(ce->cfra)<CFRA) {
267                                 if ((ce->cfra > closest) || (closest == CFRA)) {
268                                         closest= ce->cfra;
269                                 }
270                         }
271                 } 
272                 else {
273                         if(float_to_frame(ce->cfra)>CFRA) {
274                                 if ((ce->cfra < closest) || (closest == CFRA)) {
275                                         closest= ce->cfra;
276                                 }
277                         }
278                 }
279         }
280         return closest;
281 }
282
283 void nextprev_timeline_key(short dir)
284 {
285         /*mostly copied from drawobject.c, draw_object() AND editipo.c, movekey_obipo() */
286         Object *ob;
287         bActionChannel *achan;
288         bAction *act;
289         ListBase elems;
290         float closest= CFRA;
291         int a;
292         
293         if (OBACT) {
294                 ob = OBACT;
295                 
296                 if(ob) {
297                         if(ob!=G.obedit) {
298                                 if(ob->ipo) {
299                                         /* convert the ipo to a list of 'current frame elements' */
300                                         
301                                         elems.first= elems.last= NULL;
302                                         make_cfra_list(ob->ipo, &elems);
303                                         
304                                         closest= find_closest_cfra_elem(elems, dir, closest);
305                                         
306                                         BLI_freelistN(&elems);
307                                 }
308                                 
309                                 if(ob->action) {
310                                         act = ob->action;
311                                         /* go through each channel in the action */
312                                         for (achan=act->chanbase.first; achan; achan=achan->next){
313                                                 /* convert the ipo to a list of 'current frame elements' */
314                                                 
315                                                 elems.first= elems.last= NULL;
316                                                 make_cfra_list(achan->ipo, &elems);
317                                                 
318                                                 closest= find_closest_cfra_elem(elems, dir, closest);
319                                                 
320                                                 BLI_freelistN(&elems);
321                                         }
322                                 }
323                                 
324                                 for(a=0; a<ob->totcol; a++) {
325                                         Material *ma= give_current_material(ob, a+1);
326                                         if(ma && ma->ipo) {
327                                                 elems.first= elems.last= NULL;
328                                                 make_cfra_list(ma->ipo, &elems);
329                                                 
330                                                 closest= find_closest_cfra_elem(elems, dir, closest);
331                                                 
332                                                 BLI_freelistN(&elems);
333                                         }
334                                 }
335                         }
336                 }
337                 
338                 a= float_to_frame(closest);
339                 
340                 if (a!=CFRA) {
341                         CFRA= a;
342                         update_for_newframe();
343                 }       
344                 
345                 BIF_undo_push("Next/Prev Key");
346                 allqueue(REDRAWALL, 0);
347         }
348 }
349
350 void timeline_frame_to_center(void)
351 {
352         float dtime;
353         
354         dtime= CFRA*(G.scene->r.framelen) - (G.v2d->cur.xmin + G.v2d->cur.xmax)/2.0; 
355         G.v2d->cur.xmin += dtime;
356         G.v2d->cur.xmax += dtime;
357         scrarea_queue_winredraw(curarea);
358 }
359
360 void timeline_grab(int mode, int smode) // mode and smode unused here, for callback
361 {
362         SpaceTime *stime= curarea->spacedata.first;
363         TimeMarker *marker, *selmarker=NULL;
364         float dx, fac;
365         int a, ret_val= 0, totmark=0, *oldframe, offs, firsttime=1;
366         unsigned short event;
367         short val, pmval[2], mval[2], mvalo[2];
368         char str[32];
369         
370         for(marker= G.scene->markers.first; marker; marker= marker->next) {
371                 if(marker->flag & SELECT) totmark++;
372         }
373         if(totmark==0) return;
374         
375         oldframe= MEM_mallocN(totmark*sizeof(int), "marker array");
376         for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
377                 if(marker->flag & SELECT) {
378                         oldframe[a]= marker->frame;
379                         selmarker= marker;      // used for hederprint
380                         a++;
381                 }
382         }
383         
384         dx= G.v2d->mask.xmax-G.v2d->mask.xmin;
385         dx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/dx;
386         
387         getmouseco_areawin(pmval);
388         mvalo[0]= pmval[0];
389         
390         while(ret_val == 0) {
391                 
392                 getmouseco_areawin(mval);
393                 
394                 if (mval[0] != mvalo[0] || firsttime) {
395                         mvalo[0]= mval[0];
396                         firsttime= 0;
397                         
398                         fac= (((float)(mval[0] - pmval[0]))*dx);
399                         
400                         apply_keyb_grid(&fac, 0.0, (float)G.scene->r.frs_sec, 0.1*(float)G.scene->r.frs_sec, 0);
401                         offs= (int)fac;
402                         
403                         for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
404                                 if(marker->flag & SELECT) {
405                                         marker->frame= oldframe[a] + offs;
406                                         a++;
407                                 }
408                         }
409                         
410                         if(totmark==1) {        // we print current marker value
411                                 if(stime->flag & TIME_DRAWFRAMES) 
412                                         sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
413                                 else 
414                                         sprintf(str, "Marker %.2f offset %.2f", (selmarker->frame/(float)G.scene->r.frs_sec), (offs/(float)G.scene->r.frs_sec));
415                         }
416                         else {
417                                 if(stime->flag & TIME_DRAWFRAMES) 
418                                         sprintf(str, "Marker offset %d ", offs);
419                                 else 
420                                         sprintf(str, "Marker offset %.2f ", (offs/(float)G.scene->r.frs_sec));
421                         }
422                         headerprint(str);
423                         
424                         force_draw(0);  // areas identical to this, 0 = no header
425                 }
426                 else PIL_sleep_ms(10);  // idle
427                 
428                 /* emptying queue and reading events */
429                 while( qtest() ) {
430                         event= extern_qread(&val);
431                         
432                         if(val) {
433                                 if(event==ESCKEY || event==RIGHTMOUSE) ret_val= 2;
434                                 else if(event==LEFTMOUSE || event==RETKEY || event==SPACEKEY) ret_val= 1;
435                         }
436                 }
437         }
438         
439         /* restore? */
440         if(ret_val==2) {
441                 for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
442                         if(marker->flag & SELECT) {
443                                 marker->frame= oldframe[a];
444                                 a++;
445                         }
446                 }
447         }
448         else {
449                 BIF_undo_push("Move Markers");
450         }
451         MEM_freeN(oldframe);
452         allqueue(REDRAWTIME, 0);
453 }
454
455 /* copy of this is actually in editscreen.c, but event based */
456 static void timeline_force_draw(short val)
457 {
458         ScrArea *sa, *tempsa, *samin= NULL;
459         int dodraw;
460         
461         if(val & TIME_LEFTMOST_3D_WIN) {
462                 ScrArea *sa= G.curscreen->areabase.first;
463                 int min= 10000;
464                 for(; sa; sa= sa->next) {
465                         if(sa->spacetype==SPACE_VIEW3D) {
466                                 if(sa->winrct.xmin - sa->winrct.ymin < min) {
467                                         samin= sa;
468                                         min= sa->winrct.xmin - sa->winrct.ymin;
469                                 }
470                         }
471                 }
472         }
473         
474         tempsa= curarea;
475         sa= G.curscreen->areabase.first;
476         while(sa) {
477                 dodraw= 0;
478                 if(sa->spacetype==SPACE_VIEW3D) {
479                         if(sa==samin || (val & TIME_ALL_3D_WIN)) dodraw= 1;
480                 }
481                 else if(ELEM6(sa->spacetype, SPACE_NLA, SPACE_IPO, SPACE_SEQ, SPACE_BUTS, SPACE_ACTION, SPACE_SOUND)) {
482                         if(val & TIME_ALL_ANIM_WIN) dodraw= 1;
483                 }
484                 else if(sa->spacetype==SPACE_BUTS) {
485                         if(val & TIME_ALL_BUTS_WIN) dodraw= 1;
486                 }
487                 else if(sa->spacetype==SPACE_TIME) dodraw= 2;
488                 
489                 if(dodraw) {
490                         areawinset(sa->win);
491                         scrarea_do_windraw(sa);
492                         if(dodraw==2) scrarea_do_headdraw(sa);
493                 }
494                 sa= sa->next;
495         }
496         areawinset(tempsa->win);
497         
498         screen_swapbuffers();
499
500 }
501
502 /* ***************************** */
503
504 /* Right. Now for some implementation: */
505 void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
506 {
507         SpaceTime *stime= spacedata;
508         unsigned short event= evt->event;
509         short val= evt->val;
510         float dx, dy;
511         int doredraw= 0, cfra, first = 0;
512         short mval[2], nr;
513         short mousebut = L_MOUSE;
514         
515         if(sa->win==0) return;
516
517         if(val) {
518                 
519                 if( uiDoBlocks(&sa->uiblocks, event)!=UI_NOTHING ) event= 0;
520
521                 /* swap mouse buttons based on user preference */
522                 if (U.flag & USER_LMOUSESELECT) {
523                         if (event == LEFTMOUSE) {
524                                 event = RIGHTMOUSE;
525                                 mousebut = L_MOUSE;
526                         } else if (event == RIGHTMOUSE) {
527                                 event = LEFTMOUSE;
528                                 mousebut = R_MOUSE;
529                         }
530                 }
531
532                 switch(event) {
533                 case LEFTMOUSE:
534                         stime->flag |= TIME_CFRA_NUM;
535                         do {
536                                 getmouseco_areawin(mval);
537                                 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
538                                 
539                                 cfra = (int)dx;
540                                 if(cfra< MINFRAME) cfra= MINFRAME;
541                                 
542                                 if( cfra!=CFRA || first )
543                                 {
544                                         first= 0;
545                                         CFRA= cfra;
546                                         update_for_newframe_nodraw(1);  // 1= nosound
547                                         timeline_force_draw(stime->redraws);
548                                 }
549                                 else PIL_sleep_ms(30);
550                         
551                         } while(get_mbut() & mousebut);
552                         
553                         stime->flag &= ~TIME_CFRA_NUM;
554                         allqueue(REDRAWALL, 0);
555                         break;
556                         
557                 case RIGHTMOUSE: /* select/deselect marker */
558                         getmouseco_areawin(mval);
559                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
560
561                         cfra= find_nearest_marker(dx);
562
563                         if (G.qual && LR_SHIFTKEY)
564                                 select_timeline_marker_frame(cfra, 1);
565                         else
566                                 select_timeline_marker_frame(cfra, 0);
567                         
568                         force_draw(0);
569                         std_rmouse_transform(timeline_grab);
570
571                         break;
572                 case MIDDLEMOUSE:
573                 case WHEELUPMOUSE:
574                 case WHEELDOWNMOUSE:
575                         view2dmove(event);      /* in drawipo.c */
576                         break;
577                 case PADPLUSKEY:
578                         dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
579                         G.v2d->cur.xmin+= dx;
580                         G.v2d->cur.xmax-= dx;
581                         test_view2d(G.v2d, sa->winx, sa->winy);
582                         view2d_do_locks(curarea, V2D_LOCK_COPY);
583                         doredraw= 1;
584                         break;
585                 case PADMINUS:
586                         dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
587                         G.v2d->cur.xmin-= dx;
588                         G.v2d->cur.xmax+= dx;
589                         test_view2d(G.v2d, sa->winx, sa->winy);
590                         view2d_do_locks(curarea, V2D_LOCK_COPY);
591                         doredraw= 1;
592                         break;
593                 case HOMEKEY:
594                         first= G.scene->r.sfra;
595                         if(first >= G.scene->r.efra) first= G.scene->r.efra;
596                         G.v2d->cur.xmin=G.v2d->tot.xmin= (float)first-2;
597                         G.v2d->cur.xmax=G.v2d->tot.xmax= (float)G.scene->r.efra+2;
598                         doredraw= 1;
599                         break;
600                         
601                 case PAGEUPKEY: /* next keyframe */
602                         if(G.qual==LR_CTRLKEY)
603                                 nextprev_timeline_key(1);
604                         else
605                                 nextprev_timeline_marker(1);
606                         break;
607                 case PAGEDOWNKEY: /* prev keyframe */
608                         if(G.qual==LR_CTRLKEY)
609                                 nextprev_timeline_key(-1);
610                         else
611                                 nextprev_timeline_marker(-1);
612                         break;
613                         
614                 case AKEY:
615                         /* deselect all TimeMarkers */
616                         select_timeline_markers();
617                         doredraw= 1;
618                         break;
619                 case DKEY:
620                         if(G.qual==LR_SHIFTKEY)
621                                 duplicate_timeline_marker();
622                         break;
623                 case CKEY:
624                         timeline_frame_to_center();
625                         break;
626                 case GKEY: /* move marker */
627                         timeline_grab('g', 0);
628                         break;
629                 case EKEY: /* set end frame */
630                         G.scene->r.efra = CFRA;
631                         allqueue(REDRAWBUTSALL, 0);
632                         allqueue(REDRAWTIME, 1);
633                         break;
634                 case MKEY: /* add, rename marker */
635                         if (G.qual & LR_CTRLKEY)
636                                 rename_timeline_marker();
637                         else
638                                 add_timeline_marker(CFRA);
639                         allqueue(REDRAWTIME, 0);
640                         break;
641                 case SKEY: /* set start frame */
642                         G.scene->r.sfra = CFRA;
643                         allqueue(REDRAWBUTSALL, 0);
644                         allqueue(REDRAWTIME, 1);
645                         break;
646                 case TKEY: /* popup menu */
647                         nr= pupmenu("Time value%t|Frames %x1|Seconds%x2");
648                         if (nr>0) {
649                                 if(nr==1) stime->flag |= TIME_DRAWFRAMES;
650                                 else stime->flag &= ~TIME_DRAWFRAMES;
651                                 doredraw= 1;
652                         }
653                         break;
654                 case DELKEY:
655                 case XKEY:
656                         if( okee("Erase selected")==0 ) break;
657
658                         remove_timeline_marker();
659                         allqueue(REDRAWTIME, 0);
660                         break;
661                 }
662         }
663
664         if(doredraw)
665                 scrarea_queue_winredraw(sa);
666 }
667
668