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