e19771d0fdb25a2182aad5d0b663c7da41eca10e
[blender.git] / source / blender / src / edittime.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <string.h>
37 #include <math.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_arithb.h"
47
48 #include "DNA_action_types.h"
49 #include "DNA_ipo_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_material_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_scene_types.h"
55 #include "DNA_userdef_types.h"
56
57 #include "BKE_ipo.h"
58 #include "BKE_utildefines.h"
59 #include "BKE_global.h"
60 #include "BKE_main.h"
61 #include "BKE_material.h"
62 #include "BKE_library.h"
63
64 #include "BIF_space.h"
65 #include "BIF_screen.h"
66 #include "BIF_interface.h"
67 #include "BIF_toolbox.h"
68 #include "BIF_mywindow.h"
69
70 #include "BSE_drawipo.h"
71 #include "BSE_headerbuttons.h"
72 #include "BSE_time.h"
73
74 #include "BDR_editobject.h"
75
76 #include "blendef.h"
77
78 #include "mydevice.h"
79
80 #include "PIL_time.h"
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
102 /* remove TimeMarker */
103 void remove_timeline_marker(void)
104 {
105         TimeMarker *marker;
106         
107         for(marker= G.scene->markers.first; marker; marker= marker->next) {
108                 if(marker->flag & SELECT){
109                         BLI_freelinkN(&G.scene->markers, marker);
110                 }
111         }
112 }
113
114 /* rename first selected TimeMarker */
115 void rename_timeline_marker(void)
116 {
117         TimeMarker *marker;
118         char name[64];
119         
120         for(marker= G.scene->markers.first; marker; marker= marker->next) {
121                 if(marker->flag & SELECT) {
122                         sprintf(name, marker->name);
123                         if (sbutton(name, 0, sizeof(name)-1, "Name: "))
124                                 BLI_strncpy(marker->name, name, sizeof(marker->name));
125                         break;
126                 }
127         }
128 }
129
130 static int find_nearest_marker(float dx)
131 {
132         TimeMarker *marker, *nearest= NULL;
133         float dist, min_dist= 1000000;
134         
135         for(marker= G.scene->markers.first; marker; marker= marker->next) {
136                 dist = ABS((float)marker->frame - dx);
137                 if(dist < min_dist){
138                         min_dist= dist;
139                         nearest= marker;
140                 }
141         }
142         
143         if(nearest) return nearest->frame;
144         else return (int)floor(dx);
145 }
146
147 /* select/deselect TimeMarker at current frame */
148 static void select_timeline_marker_frame(int frame, unsigned char shift)
149 {
150         TimeMarker *marker;
151         int select=0;
152         
153         for(marker= G.scene->markers.first; marker; marker= marker->next) {
154                 /* if Shift is not set, then deselect Markers */
155                 if(!shift) marker->flag &= ~SELECT;
156                 /* this way a not-shift select will allways give 1 selected marker */
157                 if((marker->frame == frame) && (!select)) {
158                         if(marker->flag & SELECT) 
159                                 marker->flag &= ~SELECT;
160                         else
161                                 marker->flag |= SELECT;
162                         select = 1;
163                 }
164         }
165 }
166
167 /* select/deselect all TimeMarkers */
168 void select_timeline_markers(void)
169 {
170         TimeMarker *marker;
171         char any_selected= 0;
172         
173         for(marker= G.scene->markers.first; marker; marker= marker->next) {
174                 if(marker->flag & SELECT) any_selected= 1;
175                 marker->flag &= ~SELECT;
176         }
177         
178         /* no TimeMarker selected, then select all TimeMarkers */
179         if(!any_selected){
180                 for(marker= G.scene->markers.first; marker; marker= marker->next) {
181                         marker->flag |= SELECT;
182                 }
183         }
184 }
185
186 void nextprev_timeline_marker(short dir)
187 {
188         TimeMarker *marker, *cur=NULL, *first, *last;
189         int mindist= MAXFRAME, dist;
190         
191         first= last= G.scene->markers.first; 
192         for(marker= G.scene->markers.first; marker; marker= marker->next) {
193                 /* find closest to current frame first */
194                 dist= (marker->frame/G.scene->r.framelen) - CFRA;
195                 if(dir==1 && dist>0 && dist<mindist) {
196                         mindist= dist;
197                         cur= marker;
198                 }
199                 else if(dir==-1 && dist<0 && -dist<mindist) {
200                         mindist= -dist;
201                         cur= marker;
202                 }
203                 /* find first/last */
204                 if(marker->frame > last->frame) last= marker;
205                 if(marker->frame < first->frame) first= marker;
206         }
207         
208         if(cur==NULL) {
209                 if(dir==1) cur= first;
210                 else cur= last;
211         }
212         if(cur) {
213                 CFRA= cur->frame/G.scene->r.framelen;
214                 update_for_newframe();
215                 allqueue(REDRAWALL, 0);
216         }
217 }
218
219 /* *********** end Markers *************** */
220
221 static int float_to_frame(float frame) 
222 {
223         int to= (int) floor(0.5 + frame/G.scene->r.framelen );
224         
225         return to;      
226 }
227
228 static float find_closest_cfra_elem(ListBase elems, int dir, float closest)
229 {
230         CfraElem *ce;
231         
232         for(ce= elems.first; ce; ce= ce->next) {
233                 if (dir==-1) {
234                         if( float_to_frame(ce->cfra)<CFRA) {
235                                 if ((ce->cfra > closest) || (closest == CFRA)) {
236                                         closest= ce->cfra;
237                                 }
238                         }
239                 } 
240                 else {
241                         if(float_to_frame(ce->cfra)>CFRA) {
242                                 if ((ce->cfra < closest) || (closest == CFRA)) {
243                                         closest= ce->cfra;
244                                 }
245                         }
246                 }
247         }
248         return closest;
249 }
250
251 void nextprev_timeline_key(short dir)
252 {
253         /*mostly copied from drawobject.c, draw_object() AND editipo.c, movekey_obipo() */
254         Object *ob;
255         bActionChannel *achan;
256         bAction *act;
257         ListBase elems;
258         float closest= CFRA;
259         int a;
260         
261         if (OBACT) {
262                 ob = OBACT;
263                 
264                 if(ob) {
265                         if(ob!=G.obedit) {
266                                 if(ob->ipo) {
267                                         /* convert the ipo to a list of 'current frame elements' */
268                                         
269                                         elems.first= elems.last= NULL;
270                                         make_cfra_list(ob->ipo, &elems);
271                                         
272                                         closest= find_closest_cfra_elem(elems, dir, closest);
273                                         
274                                         BLI_freelistN(&elems);
275                                 }
276                                 
277                                 if(ob->action) {
278                                         act = ob->action;
279                                         /* go through each channel in the action */
280                                         for (achan=act->chanbase.first; achan; achan=achan->next){
281                                                 /* convert the ipo to a list of 'current frame elements' */
282                                                 
283                                                 elems.first= elems.last= NULL;
284                                                 make_cfra_list(achan->ipo, &elems);
285                                                 
286                                                 closest= find_closest_cfra_elem(elems, dir, closest);
287                                                 
288                                                 BLI_freelistN(&elems);
289                                         }
290                                 }
291                                 
292                                 for(a=0; a<ob->totcol; a++) {
293                                         Material *ma= give_current_material(ob, a+1);
294                                         if(ma && ma->ipo) {
295                                                 elems.first= elems.last= NULL;
296                                                 make_cfra_list(ma->ipo, &elems);
297                                                 
298                                                 closest= find_closest_cfra_elem(elems, dir, closest);
299                                                 
300                                                 BLI_freelistN(&elems);
301                                         }
302                                 }
303                         }
304                 }
305                 
306                 a= float_to_frame(closest);
307                 
308                 if (a!=CFRA) {
309                         CFRA= a;
310                         update_for_newframe();
311                 }       
312                 
313                 BIF_undo_push("Next/Prev Key");
314                 allqueue(REDRAWALL, 0);
315         }
316 }
317
318 void timeline_frame_to_center(void)
319 {
320         float dtime;
321         
322         dtime= CFRA*(G.scene->r.framelen) - (G.v2d->cur.xmin + G.v2d->cur.xmax)/2.0; 
323         G.v2d->cur.xmin += dtime;
324         G.v2d->cur.xmax += dtime;
325         scrarea_queue_winredraw(curarea);
326 }
327
328 void timeline_grab(int mode, int smode) // mode and smode unused here, for callback
329 {
330         SpaceTime *stime= curarea->spacedata.first;
331         TimeMarker *marker, *selmarker=NULL;
332         float dx, fac;
333         int a, ret_val= 0, totmark=0, *oldframe, offs, firsttime=1;
334         unsigned short event;
335         short val, pmval[2], mval[2], mvalo[2];
336         char str[32];
337         
338         for(marker= G.scene->markers.first; marker; marker= marker->next) {
339                 if(marker->flag & SELECT) totmark++;
340         }
341         if(totmark==0) return;
342         
343         oldframe= MEM_mallocN(totmark*sizeof(int), "marker array");
344         for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
345                 if(marker->flag & SELECT) {
346                         oldframe[a]= marker->frame;
347                         selmarker= marker;      // used for hederprint
348                         a++;
349                 }
350         }
351         
352         dx= G.v2d->mask.xmax-G.v2d->mask.xmin;
353         dx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/dx;
354         
355         getmouseco_areawin(pmval);
356         mvalo[0]= pmval[0];
357         
358         while(ret_val == 0) {
359                 
360                 getmouseco_areawin(mval);
361                 
362                 if (mval[0] != mvalo[0] || firsttime) {
363                         mvalo[0]= mval[0];
364                         firsttime= 0;
365                         
366                         fac= (((float)(mval[0] - pmval[0]))*dx);
367                         
368                         apply_keyb_grid(&fac, 0.0, (float)G.scene->r.frs_sec, 0.1*(float)G.scene->r.frs_sec, 0);
369                         offs= (int)fac;
370                         
371                         for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
372                                 if(marker->flag & SELECT) {
373                                         marker->frame= oldframe[a] + offs;
374                                         a++;
375                                 }
376                         }
377                         
378                         if(totmark==1) {        // we print current marker value
379                                 if(stime->flag & TIME_DRAWFRAMES) 
380                                         sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
381                                 else 
382                                         sprintf(str, "Marker %.2f offset %.2f", (selmarker->frame/(float)G.scene->r.frs_sec), (offs/(float)G.scene->r.frs_sec));
383                         }
384                         else {
385                                 if(stime->flag & TIME_DRAWFRAMES) 
386                                         sprintf(str, "Marker offset %d ", offs);
387                                 else 
388                                         sprintf(str, "Marker offset %.2f ", (offs/(float)G.scene->r.frs_sec));
389                         }
390                         headerprint(str);
391                         
392                         force_draw(0);  // areas identical to this, 0 = no header
393                 }
394                 else PIL_sleep_ms(10);  // idle
395                 
396                 /* emptying queue and reading events */
397                 while( qtest() ) {
398                         event= extern_qread(&val);
399                         
400                         if(val) {
401                                 if(event==ESCKEY || event==RIGHTMOUSE) ret_val= 2;
402                                 else if(event==LEFTMOUSE || event==RETKEY || event==SPACEKEY) ret_val= 1;
403                         }
404                 }
405         }
406         
407         /* restore? */
408         if(ret_val==2) {
409                 for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
410                         if(marker->flag & SELECT) {
411                                 marker->frame= oldframe[a];
412                                 a++;
413                         }
414                 }
415         }
416         else {
417                 BIF_undo_push("Move Markers");
418         }
419         MEM_freeN(oldframe);
420         allqueue(REDRAWTIME, 0);
421 }
422
423 /* copy of this is actually in editscreen.c, but event based */
424 static void timeline_force_draw(short val)
425 {
426         ScrArea *sa, *tempsa, *samin= NULL;
427         int dodraw;
428         
429         if(val & TIME_LEFTMOST_3D_WIN) {
430                 ScrArea *sa= G.curscreen->areabase.first;
431                 int min= 10000;
432                 for(; sa; sa= sa->next) {
433                         if(sa->spacetype==SPACE_VIEW3D) {
434                                 if(sa->winrct.xmin - sa->winrct.ymin < min) {
435                                         samin= sa;
436                                         min= sa->winrct.xmin - sa->winrct.ymin;
437                                 }
438                         }
439                 }
440         }
441         
442         tempsa= curarea;
443         sa= G.curscreen->areabase.first;
444         while(sa) {
445                 dodraw= 0;
446                 if(sa->spacetype==SPACE_VIEW3D) {
447                         if(sa==samin || (val & TIME_ALL_3D_WIN)) dodraw= 1;
448                 }
449                 else if(ELEM6(sa->spacetype, SPACE_NLA, SPACE_IPO, SPACE_SEQ, SPACE_BUTS, SPACE_ACTION, SPACE_SOUND)) {
450                         if(val & TIME_ALL_ANIM_WIN) dodraw= 1;
451                 }
452                 else if(sa->spacetype==SPACE_BUTS) {
453                         if(val & TIME_ALL_BUTS_WIN) dodraw= 1;
454                 }
455                 else if(sa->spacetype==SPACE_TIME) dodraw= 2;
456                 
457                 if(dodraw) {
458                         areawinset(sa->win);
459                         scrarea_do_windraw(sa);
460                         if(dodraw==2) scrarea_do_headdraw(sa);
461                 }
462                 sa= sa->next;
463         }
464         areawinset(tempsa->win);
465         
466         screen_swapbuffers();
467
468 }
469
470 /* ***************************** */
471
472 /* Right. Now for some implementation: */
473 void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
474 {
475         SpaceTime *stime= spacedata;
476         unsigned short event= evt->event;
477         short val= evt->val;
478         float dx, dy;
479         int doredraw= 0, cfra, first = 0;
480         short mval[2], nr;
481         short mousebut = L_MOUSE;
482         
483         if(sa->win==0) return;
484
485         if(val) {
486                 
487                 if( uiDoBlocks(&sa->uiblocks, event)!=UI_NOTHING ) event= 0;
488
489                 /* swap mouse buttons based on user preference */
490                 if (U.flag & USER_LMOUSESELECT) {
491                         if (event == LEFTMOUSE) {
492                                 event = RIGHTMOUSE;
493                                 mousebut = L_MOUSE;
494                         } else if (event == RIGHTMOUSE) {
495                                 event = LEFTMOUSE;
496                                 mousebut = R_MOUSE;
497                         }
498                 }
499
500                 switch(event) {
501                 case LEFTMOUSE:
502                         stime->flag |= TIME_CFRA_NUM;
503                         do {
504                                 getmouseco_areawin(mval);
505                                 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
506                                 
507                                 cfra = (int)dx;
508                                 if(cfra< MINFRAME) cfra= MINFRAME;
509                                 
510                                 if( cfra!=CFRA || first )
511                                 {
512                                         first= 0;
513                                         CFRA= cfra;
514                                         update_for_newframe_nodraw(1);  // 1= nosound
515                                         timeline_force_draw(stime->redraws);
516                                 }
517                                 else PIL_sleep_ms(30);
518                         
519                         } while(get_mbut() & mousebut);
520                         
521                         stime->flag &= ~TIME_CFRA_NUM;
522                         allqueue(REDRAWALL, 0);
523                         break;
524                         
525                 case RIGHTMOUSE: /* select/deselect marker */
526                         getmouseco_areawin(mval);
527                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
528
529                         cfra= find_nearest_marker(dx);
530
531                         if(cfra < MINFRAME) cfra= MINFRAME;
532
533                         if (G.qual && LR_SHIFTKEY)
534                                 select_timeline_marker_frame(cfra, 1);
535                         else
536                                 select_timeline_marker_frame(cfra, 0);
537                         
538                         force_draw(0);
539                         std_rmouse_transform(timeline_grab);
540
541                         break;
542                 case MIDDLEMOUSE:
543                 case WHEELUPMOUSE:
544                 case WHEELDOWNMOUSE:
545                         view2dmove(event);      /* in drawipo.c */
546                         break;
547                 case PADPLUSKEY:
548                         dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
549                         G.v2d->cur.xmin+= dx;
550                         G.v2d->cur.xmax-= dx;
551                         test_view2d(G.v2d, sa->winx, sa->winy);
552
553                         doredraw= 1;
554                         break;
555                 case PADMINUS:
556                         dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
557                         G.v2d->cur.xmin-= dx;
558                         G.v2d->cur.xmax+= dx;
559                         test_view2d(G.v2d, sa->winx, sa->winy);
560
561                         doredraw= 1;
562                         break;
563                 case HOMEKEY:
564                         first= G.scene->r.sfra;
565                         if(first >= G.scene->r.efra) first= G.scene->r.efra;
566                         G.v2d->cur.xmin=G.v2d->tot.xmin= (float)first-2;
567                         G.v2d->cur.xmax=G.v2d->tot.xmax= (float)G.scene->r.efra+2;
568                         doredraw= 1;
569                         break;
570                         
571                 case PAGEUPKEY: /* next keyframe */
572                         if(G.qual==LR_CTRLKEY)
573                                 nextprev_timeline_key(1);
574                         else
575                                 nextprev_timeline_marker(1);
576                         break;
577                 case PAGEDOWNKEY: /* prev keyframe */
578                         if(G.qual==LR_CTRLKEY)
579                                 nextprev_timeline_key(-1);
580                         else
581                                 nextprev_timeline_marker(-1);
582                         break;
583                         
584                 case AKEY:
585                         /* deselect all TimeMarkers */
586                         select_timeline_markers();
587                         doredraw= 1;
588                         break;
589                 case CKEY:
590                         timeline_frame_to_center();
591                         break;
592                 case GKEY: /* move marker */
593                         timeline_grab('g', 0);
594                         break;
595                 case EKEY: /* set end frame */
596                         G.scene->r.efra = CFRA;
597                         allqueue(REDRAWBUTSALL, 0);
598                         allqueue(REDRAWTIME, 1);
599                         break;
600                 case MKEY: /* add, rename marker */
601                         if (G.qual & LR_CTRLKEY)
602                                 rename_timeline_marker();
603                         else
604                                 add_timeline_marker(CFRA);
605                         allqueue(REDRAWTIME, 0);
606                         break;
607                 case SKEY: /* set start frame */
608                         G.scene->r.sfra = CFRA;
609                         allqueue(REDRAWBUTSALL, 0);
610                         allqueue(REDRAWTIME, 1);
611                         break;
612                 case TKEY: /* popup menu */
613                         nr= pupmenu("Time value%t|Frames %x1|Seconds%x2");
614                         if (nr>0) {
615                                 if(nr==1) stime->flag |= TIME_DRAWFRAMES;
616                                 else stime->flag &= ~TIME_DRAWFRAMES;
617                                 doredraw= 1;
618                         }
619                         break;
620                 case DELKEY:
621                 case XKEY:
622                         if( okee("Erase selected")==0 ) break;
623
624                         remove_timeline_marker();
625                         allqueue(REDRAWTIME, 0);
626                         break;
627                 }
628         }
629
630         if(doredraw)
631                 scrarea_queue_winredraw(sa);
632 }
633
634