Fix a few warning in editors/ module.
[blender-staging.git] / source / blender / editors / animation / anim_markers.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_scene_types.h"
34 #include "DNA_object_types.h"
35
36 #include "RNA_access.h"
37 #include "RNA_define.h"
38 #include "RNA_enum_types.h"
39
40 #include "BLI_blenlib.h"
41
42 #include "BKE_context.h"
43 #include "BKE_fcurve.h"
44 #include "BKE_main.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "BIF_gl.h"
52 #include "BIF_glutil.h"
53
54 #include "UI_interface.h"
55 #include "UI_interface_icons.h"
56 #include "UI_view2d.h"
57 #include "UI_resources.h"
58
59 #include "ED_markers.h"
60 #include "ED_screen.h"
61 #include "ED_util.h"
62 #include "ED_numinput.h"
63 #include "ED_object.h"
64 #include "ED_types.h"
65
66 /* ************* Marker API **************** */
67
68 static ListBase *context_get_markers(const bContext *C)
69 {
70         
71 #if 0
72         /* XXX get them from pose */
73         if ((slink->spacetype == SPACE_ACTION) && (saction->flag & SACTION_POSEMARKERS_MOVE)) {
74                 if (saction->action)
75                         markers= &saction->action->markers;
76                 else
77                         markers= NULL;
78         }
79         else
80 #endif
81         
82         return &CTX_data_scene(C)->markers;
83 }
84
85 /* Get the marker that is closest to this point */
86 /* XXX for select, the min_dist should be small */
87 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x) 
88 {
89         TimeMarker *marker, *nearest=NULL;
90         float dist, min_dist= 1000000;
91         
92         if (markers) {
93                 for (marker= markers->first; marker; marker= marker->next) {
94                         dist = ABS((float)marker->frame - x);
95                         
96                         if (dist < min_dist) {
97                                 min_dist= dist;
98                                 nearest= marker;
99                         }
100                 }
101         }
102         
103         return nearest;
104 }
105
106 /* Return the time of the marker that occurs on a frame closest to the given time */
107 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
108 {
109         TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
110         return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
111 }
112
113
114 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
115 {
116         TimeMarker *marker;
117         float min, max;
118         int selcount = 0;
119         
120         /* sanity check */
121         //printf("markers = %p -  %p, %p \n", markers, markers->first, markers->last);
122         if (markers == NULL) {
123                 *first = 0.0f;
124                 *last = 0.0f;
125                 return;
126         }
127         
128         if (markers->first && markers->last) {
129                 TimeMarker *fm= markers->first;
130                 TimeMarker *lm= markers->last;
131                 
132                 min= (float)fm->frame;
133                 max= (float)lm->frame;
134         }
135         else {
136                 *first = 0.0f;
137                 *last = 0.0f;
138                 return;
139         }
140         
141         /* count how many markers are usable - see later */
142         if (sel) {
143                 for (marker= markers->first; marker; marker= marker->next) {
144                         if (marker->flag & SELECT)
145                                 selcount++;
146                 }
147         }
148         else
149                 selcount= BLI_countlist(markers);
150         
151         /* if only selected are to be considered, only consider the selected ones
152          * (optimisation for not searching list) 
153          */
154         if (selcount > 1) {
155                 for (marker= markers->first; marker; marker= marker->next) {
156                         if (sel) {
157                                 if (marker->flag & SELECT) {
158                                         if (marker->frame < min)
159                                                 min= (float)marker->frame;
160                                         if (marker->frame > max)
161                                                 max= (float)marker->frame;
162                                 }
163                         }
164                         else {
165                                 if (marker->frame < min)
166                                         min= (float)marker->frame;
167                                 if (marker->frame > max)
168                                         max= (float)marker->frame;
169                         }       
170                 }
171         }
172         
173         /* set the min/max values */
174         *first= min;
175         *last= max;
176 }
177
178 /* Adds a marker to list of cfra elems */
179 void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
180 {
181         CfraElem *ce, *cen;
182         
183         /* should this one only be considered if it is selected? */
184         if ((only_sel) && ((marker->flag & SELECT)==0))
185                 return;
186         
187         /* insertion sort - try to find a previous cfra elem */
188         for (ce= lb->first; ce; ce= ce->next) {
189                 if (ce->cfra == marker->frame) {
190                         /* do because of double keys */
191                         if (marker->flag & SELECT) 
192                                 ce->sel= marker->flag;
193                         return;
194                 }
195                 else if (ce->cfra > marker->frame) break;
196         }       
197         
198         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
199         if (ce) BLI_insertlinkbefore(lb, ce, cen);
200         else BLI_addtail(lb, cen);
201
202         cen->cfra= marker->frame;
203         cen->sel= marker->flag;
204 }
205
206 /* This function makes a list of all the markers. The only_sel
207  * argument is used to specify whether only the selected markers
208  * are added.
209  */
210 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
211 {
212         TimeMarker *marker;
213         
214         if (markers == NULL)
215                 return;
216         
217         for (marker= markers->first; marker; marker= marker->next)
218                 add_marker_to_cfra_elem(lb, marker, only_sel);
219 }
220
221 /* ************* Marker Drawing ************ */
222
223 /* function to draw markers */
224 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
225 {
226         float xpos, ypixels, xscale, yscale;
227         int icon_id= 0;
228         
229         xpos = marker->frame;
230         
231         /* no time correction for framelen! space is drawn with old values */
232         ypixels= v2d->mask.ymax-v2d->mask.ymin;
233         UI_view2d_getscale(v2d, &xscale, &yscale);
234         
235         glScalef(1.0f/xscale, 1.0f, 1.0f);
236         
237         glEnable(GL_BLEND);
238         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                      
239         
240         /* vertical line - dotted */
241 #ifdef DURIAN_CAMERA_SWITCH
242         if ((marker->camera) || (flag & DRAW_MARKERS_LINES)) {
243 #else
244         if (flag & DRAW_MARKERS_LINES) {
245 #endif
246                 setlinestyle(3);
247                 
248                 if (marker->flag & SELECT)
249                         glColor4ub(255, 255, 255, 96);
250                 else
251                         glColor4ub(0, 0, 0, 96);
252                 
253                 glBegin(GL_LINES);
254                         glVertex2f((xpos*xscale)+0.5f, 12.0f);
255                         glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
256                 glEnd();
257                 
258                 setlinestyle(0);
259         }
260         
261         /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
262         if (flag & DRAW_MARKERS_LOCAL) {
263                 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : 
264                 (marker->flag & SELECT) ? ICON_PMARKER_SEL : 
265                 ICON_PMARKER;
266         }
267         else {
268                 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT : 
269                 ICON_MARKER;
270         }
271         
272         UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
273         
274         glBlendFunc(GL_ONE, GL_ZERO);
275         glDisable(GL_BLEND);
276         
277         /* and the marker name too, shifted slightly to the top-right */
278         if (marker->name && marker->name[0]) {
279                 float x, y;
280                 
281                 if (marker->flag & SELECT) {
282                         UI_ThemeColor(TH_TEXT_HI);
283                         x= xpos*xscale + 4.0f;
284                         y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
285                 }
286                 else {
287                         UI_ThemeColor(TH_TEXT);
288                         if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
289                                 x= xpos*xscale + 4.0f;
290                                 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
291                         }
292                         else {
293                                 x= xpos*xscale + 4.0f;
294                                 y= 17.0f;
295                         }
296                 }
297
298 #ifdef DURIAN_CAMERA_SWITCH
299                 if(marker->camera && marker->camera->restrictflag & OB_RESTRICT_RENDER) {
300                         float col[4];
301                         glGetFloatv(GL_CURRENT_COLOR, col);
302                         col[3]= 0.4;
303                         glColor4fv(col);
304                 }
305 #endif
306
307                 UI_DrawString(x, y, marker->name);
308         }
309         
310         glScalef(xscale, 1.0f, 1.0f);
311 }
312
313 /* Draw Scene-Markers in time window */
314 void draw_markers_time(const bContext *C, int flag)
315 {
316         ListBase *markers= context_get_markers(C);
317         View2D *v2d= UI_view2d_fromcontext(C);
318         TimeMarker *marker;
319         
320         if (markers == NULL)
321                 return;
322         
323         /* unselected markers are drawn at the first time */
324         for (marker= markers->first; marker; marker= marker->next) {
325                 if ((marker->flag & SELECT) == 0) 
326                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
327         }
328         
329         /* selected markers are drawn later */
330         for (marker= markers->first; marker; marker= marker->next) {
331                 if (marker->flag & SELECT) 
332                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
333         }
334 }
335
336 /* ************************** add markers *************************** */
337
338 /* add TimeMarker at curent frame */
339 static int ed_marker_add(bContext *C, wmOperator *op)
340 {
341         ListBase *markers= context_get_markers(C);
342         TimeMarker *marker;
343         int frame= CTX_data_scene(C)->r.cfra;
344         
345         if (markers == NULL)
346                 return OPERATOR_CANCELLED;
347         
348         /* two markers can't be at the same place */
349         for (marker= markers->first; marker; marker= marker->next) {
350                 if (marker->frame == frame) 
351                         return OPERATOR_CANCELLED;
352         }
353         
354         /* deselect all */
355         for(marker= markers->first; marker; marker= marker->next)
356                 marker->flag &= ~SELECT;
357         
358         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
359         marker->flag= SELECT;
360         marker->frame= frame;
361         sprintf(marker->name, "F_%02d", frame); // XXX - temp code only
362         BLI_addtail(markers, marker);
363         
364         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
365         
366         return OPERATOR_FINISHED;
367 }
368
369 static void MARKER_OT_add(wmOperatorType *ot)
370 {
371         /* identifiers */
372         ot->name= "Add Time Marker";
373         ot->description= "Add a new time marker";
374         ot->idname= "MARKER_OT_add";
375         
376         /* api callbacks */
377         ot->exec= ed_marker_add;
378         ot->poll= ED_operator_areaactive;
379         
380         /* flags */
381         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
382 }
383
384 /* ************************** transform markers *************************** */
385
386
387 /* operator state vars used:  
388         frs: delta movement
389
390 functions:
391
392         init()   check selection, add customdata with old values and some lookups
393
394         apply()  do the actual movement
395
396         exit()  cleanup, send notifier
397
398         cancel() to escpae from modal
399
400 callbacks:
401
402         exec()  calls init, apply, exit 
403
404         invoke() calls init, adds modal handler
405
406         modal() accept modal events while doing it, ends with apply and exit, or cancel
407
408 */
409
410 typedef struct MarkerMove {
411         SpaceLink *slink;
412         ListBase *markers;
413         int event_type;         /* store invoke-event, to verify */
414         int *oldframe, evtx, firstx;
415         NumInput num;
416 } MarkerMove;
417
418 /* copy selection to temp buffer */
419 /* return 0 if not OK */
420 static int ed_marker_move_init(bContext *C, wmOperator *op)
421 {
422         ListBase *markers= context_get_markers(C);
423         MarkerMove *mm;
424         TimeMarker *marker;
425         int totmark=0;
426         int a;
427
428         if(markers == NULL) return 0;
429         
430         for (marker= markers->first; marker; marker= marker->next)
431                 if (marker->flag & SELECT) totmark++;
432         
433         if (totmark==0) return 0;
434         
435         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
436         mm->slink= CTX_wm_space_data(C);
437         mm->markers= markers;
438         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
439
440         initNumInput(&mm->num);
441         mm->num.idx_max = 0; /* one axis */
442         mm->num.flag |= NUM_NO_FRACTION;
443         mm->num.increment = 1.0f;
444         
445         for (a=0, marker= markers->first; marker; marker= marker->next) {
446                 if (marker->flag & SELECT) {
447                         mm->oldframe[a]= marker->frame;
448                         a++;
449                 }
450         }
451         
452         return 1;
453 }
454
455 /* free stuff */
456 static void ed_marker_move_exit(bContext *C, wmOperator *op)
457 {
458         MarkerMove *mm= op->customdata;
459         
460         /* free data */
461         MEM_freeN(mm->oldframe);
462         MEM_freeN(op->customdata);
463         op->customdata= NULL;
464         
465         /* clear custom header prints */
466         ED_area_headerprint(CTX_wm_area(C), NULL);
467 }
468
469 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
470 {
471         if(ed_marker_move_init(C, op)) {
472                 MarkerMove *mm= op->customdata;
473                 
474                 mm->evtx= evt->x;
475                 mm->firstx= evt->x;
476                 mm->event_type= evt->type;
477                 
478                 /* add temp handler */
479                 WM_event_add_modal_handler(C, op);
480                 
481                 /* reset frs delta */
482                 RNA_int_set(op->ptr, "frames", 0);
483                 
484                 return OPERATOR_RUNNING_MODAL;
485         }
486         
487         return OPERATOR_CANCELLED;
488 }
489
490 /* note, init has to be called succesfully */
491 static void ed_marker_move_apply(bContext *C, wmOperator *op)
492 {
493         MarkerMove *mm= op->customdata;
494         TimeMarker *marker;
495         int a, offs;
496         
497         offs= RNA_int_get(op->ptr, "frames");
498         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
499                 if (marker->flag & SELECT) {
500                         marker->frame= mm->oldframe[a] + offs;
501                         a++;
502                 }
503         }
504 }
505
506 /* only for modal */
507 static void ed_marker_move_cancel(bContext *C, wmOperator *op)
508 {
509         RNA_int_set(op->ptr, "frames", 0);
510         ed_marker_move_apply(C, op);
511         ed_marker_move_exit(C, op);     
512         
513         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
514 }
515
516
517
518 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
519 {
520         Scene *scene= CTX_data_scene(C);
521         MarkerMove *mm= op->customdata;
522         View2D *v2d= UI_view2d_fromcontext(C);
523         TimeMarker *marker, *selmarker=NULL;
524         float dx, fac;
525         char str[256];
526                 
527         switch(evt->type) {
528                 case ESCKEY:
529                         ed_marker_move_cancel(C, op);
530                         return OPERATOR_CANCELLED;
531                 
532                 case RETKEY:
533                 case PADENTER:
534                 case LEFTMOUSE:
535                 case MIDDLEMOUSE:
536                 case RIGHTMOUSE:
537                         if(WM_modal_tweak_exit(evt, mm->event_type)) {
538                                 ed_marker_move_exit(C, op);
539                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
540                                 return OPERATOR_FINISHED;
541                         }
542                         
543                         break;
544                 case MOUSEMOVE:
545                         if(hasNumInput(&mm->num))
546                                 break;
547
548                         dx= v2d->mask.xmax-v2d->mask.xmin;
549                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
550                         
551                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
552                                 int a, offs, totmark=0;
553                                 
554                                 mm->evtx= evt->x;
555                                 
556                                 fac= ((float)(evt->x - mm->firstx)*dx);
557                                 
558                                 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) 
559                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
560                                 else
561                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
562                                 
563                                 offs= (int)fac;
564                                 RNA_int_set(op->ptr, "frames", offs);
565                                 ed_marker_move_apply(C, op);
566                                 
567                                 /* cruft below is for header print */
568                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
569                                         if (marker->flag & SELECT) {
570                                                 selmarker= marker;
571                                                 a++; totmark++;
572                                         }
573                                 }
574                                 
575                                 if (totmark==1) {       
576                                         /* we print current marker value */
577                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
578                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
579                                                 if (stime->flag & TIME_DRAWFRAMES) 
580                                                         sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
581                                                 else 
582                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
583                                         }
584                                         else if (mm->slink->spacetype == SPACE_ACTION) {
585                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
586                                                 if (saction->flag & SACTION_DRAWTIME)
587                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
588                                                 else
589                                                         sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
590                                         }
591                                         else {
592                                                 sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
593                                         }
594                                 }
595                                 else {
596                                         /* we only print the offset */
597                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { 
598                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
599                                                 if (stime->flag & TIME_DRAWFRAMES) 
600                                                         sprintf(str, "Marker offset %d ", offs);
601                                                 else 
602                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
603                                         }
604                                         else if (mm->slink->spacetype == SPACE_ACTION) {
605                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
606                                                 if (saction->flag & SACTION_DRAWTIME)
607                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
608                                                 else
609                                                         sprintf(str, "Marker offset %.2f ", (double)(offs));
610                                         }
611                                         else {
612                                                 sprintf(str, "Marker offset %.2f ", (double)(offs));
613                                         }
614                                 }
615                                 
616                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
617                                 ED_area_headerprint(CTX_wm_area(C), str);
618                         }
619         }
620
621         if(evt->val==KM_PRESS) {
622                 float vec[3];
623                 char str_tx[256];
624
625                 if (handleNumInput(&mm->num, evt))
626                 {
627                         applyNumInput(&mm->num, vec);
628                         outputNumInput(&mm->num, str_tx);
629
630                         RNA_int_set(op->ptr, "frames", vec[0]);
631                         ed_marker_move_apply(C, op);
632                         // ed_marker_header_update(C, op, str, (int)vec[0]);
633                         // strcat(str, str_tx);
634                         sprintf(str, "Marker offset %s", str_tx);
635                         ED_area_headerprint(CTX_wm_area(C), str);
636
637                         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
638                 }
639         }
640
641         return OPERATOR_RUNNING_MODAL;
642 }
643
644 static int ed_marker_move_exec(bContext *C, wmOperator *op)
645 {
646         if(ed_marker_move_init(C, op)) {
647                 ed_marker_move_apply(C, op);
648                 ed_marker_move_exit(C, op);
649                 return OPERATOR_FINISHED;
650         }
651         return OPERATOR_PASS_THROUGH;
652 }
653
654 static void MARKER_OT_move(wmOperatorType *ot)
655 {
656         /* identifiers */
657         ot->name= "Move Time Marker";
658         ot->description= "Move selected time marker(s)";
659         ot->idname= "MARKER_OT_move";
660         
661         /* api callbacks */
662         ot->exec= ed_marker_move_exec;
663         ot->invoke= ed_marker_move_invoke;
664         ot->modal= ed_marker_move_modal;
665         ot->poll= ED_operator_areaactive;
666         
667         /* flags */
668         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
669         
670         /* rna storage */
671         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
672 }
673
674 /* ************************** duplicate markers *************************** */
675
676 /* operator state vars used:  
677         frs: delta movement
678
679 functions:
680
681         apply()  do the actual duplicate
682
683 callbacks:
684
685         exec()  calls apply, move_exec
686
687         invoke() calls apply, move_invoke
688
689         modal() uses move_modal
690
691 */
692
693
694 /* duplicate selected TimeMarkers */
695 static void ed_marker_duplicate_apply(bContext *C, wmOperator *op)
696 {
697         ListBase *markers= context_get_markers(C);
698         TimeMarker *marker, *newmarker;
699         
700         if (markers == NULL) 
701                 return;
702
703         /* go through the list of markers, duplicate selected markers and add duplicated copies
704          * to the begining of the list (unselect original markers) 
705          */
706         for (marker= markers->first; marker; marker= marker->next) {
707                 if (marker->flag & SELECT) {
708                         /* unselect selected marker */
709                         marker->flag &= ~SELECT;
710                         
711                         /* create and set up new marker */
712                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
713                         newmarker->flag= SELECT;
714                         newmarker->frame= marker->frame;
715                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
716                         
717 #ifdef DURIAN_CAMERA_SWITCH
718                         newmarker->camera= marker->camera;
719 #endif
720
721                         /* new marker is added to the begining of list */
722                         BLI_addhead(markers, newmarker);
723                 }
724         }
725 }
726
727 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
728 {
729         ed_marker_duplicate_apply(C, op);
730         ed_marker_move_exec(C, op);     /* assumes frs delta set */
731         
732         return OPERATOR_FINISHED;
733         
734 }
735
736 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
737 {
738         ed_marker_duplicate_apply(C, op);
739         return ed_marker_move_invoke(C, op, evt);
740 }
741
742 static void MARKER_OT_duplicate(wmOperatorType *ot)
743 {
744         /* identifiers */
745         ot->name= "Duplicate Time Marker";
746         ot->description= "Duplicate selected time marker(s)";
747         ot->idname= "MARKER_OT_duplicate";
748         
749         /* api callbacks */
750         ot->exec= ed_marker_duplicate_exec;
751         ot->invoke= ed_marker_duplicate_invoke;
752         ot->modal= ed_marker_move_modal;
753         ot->poll= ED_operator_areaactive;
754         
755         /* flags */
756         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
757         
758         /* rna storage */
759         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
760 }
761
762 /* ************************** selection ************************************/
763
764 /* select/deselect TimeMarker at current frame */
765 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
766 {
767         TimeMarker *marker;
768         int select=0;
769         
770         for (marker= markers->first; marker; marker= marker->next) {
771                 /* if Shift is not set, then deselect Markers */
772                 if (!shift) marker->flag &= ~SELECT;
773                 
774                 /* this way a not-shift select will allways give 1 selected marker */
775                 if ((marker->frame == frame) && (!select)) {
776                         if (marker->flag & SELECT) 
777                                 marker->flag &= ~SELECT;
778                         else
779                                 marker->flag |= SELECT;
780                         select = 1;
781                 }
782         }
783 }
784
785 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
786 {
787         ListBase *markers= context_get_markers(C);
788         View2D *v2d= UI_view2d_fromcontext(C);
789         float viewx;
790         int x, y, cfra;
791         
792         if(markers == NULL)
793                 return OPERATOR_PASS_THROUGH;
794
795         x= evt->x - CTX_wm_region(C)->winrct.xmin;
796         y= evt->y - CTX_wm_region(C)->winrct.ymin;
797         
798         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
799         
800         cfra= ED_markers_find_nearest_marker_time(markers, viewx);
801         
802         if (extend)
803                 select_timeline_marker_frame(markers, cfra, 1);
804         else
805                 select_timeline_marker_frame(markers, cfra, 0);
806         
807 #ifdef DURIAN_CAMERA_SWITCH
808
809         if(camera) {
810                 Scene *scene= CTX_data_scene(C);
811                 Base *base;
812                 TimeMarker *marker;
813                 int sel= 0;
814
815                 if (!extend)
816                         scene_deselect_all(scene);
817
818                 for (marker= markers->first; marker; marker= marker->next) {
819                         if(marker->frame==cfra) {
820                                 sel= (marker->flag & SELECT);
821                                 break;
822                         }
823                 }
824
825                 for (marker= markers->first; marker; marker= marker->next) {
826                         if(marker->camera) {
827                                 if(marker->frame==cfra) {
828                                         base= object_in_scene(marker->camera, scene);
829                                         if(base) {
830                                                 ED_base_object_select(base, sel);
831                                                 if(sel)
832                                                         ED_base_object_activate(C, base);
833                                         }
834                                 }
835                         }
836                 }
837
838                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
839         }
840 #endif
841
842         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
843
844         /* allowing tweaks */
845         return OPERATOR_PASS_THROUGH;
846 }
847
848 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
849 {
850         short extend= RNA_boolean_get(op->ptr, "extend");
851         short camera= 0;
852 #ifdef DURIAN_CAMERA_SWITCH
853         camera= RNA_boolean_get(op->ptr, "camera");
854 #endif
855         return ed_marker_select(C, evt, extend, camera);
856 }
857
858 static void MARKER_OT_select(wmOperatorType *ot)
859 {
860         /* identifiers */
861         ot->name= "Select Time Marker";
862         ot->description= "Select time marker(s)";
863         ot->idname= "MARKER_OT_select";
864         
865         /* api callbacks */
866         ot->invoke= ed_marker_select_invoke;
867         ot->poll= ED_operator_areaactive;
868         
869         /* flags */
870         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
871
872         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
873 #ifdef DURIAN_CAMERA_SWITCH
874         RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
875 #endif
876 }
877
878 /* *************************** border select markers **************** */
879
880 /* operator state vars used: (added by default WM callbacks)   
881         xmin, ymin     
882         xmax, ymax     
883
884 customdata: the wmGesture pointer, with subwindow
885
886 callbacks:
887
888         exec()  has to be filled in by user
889
890         invoke() default WM function
891                         adds modal handler
892
893         modal() default WM function 
894                         accept modal events while doing it, calls exec(), handles ESC and border drawing
895
896         poll()  has to be filled in by user for context
897 */
898
899 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
900 {
901         View2D *v2d= UI_view2d_fromcontext(C);
902         ListBase *markers= context_get_markers(C);
903         TimeMarker *marker;
904         float xminf, xmaxf, yminf, ymaxf;
905         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
906         int xmin= RNA_int_get(op->ptr, "xmin");
907         int xmax= RNA_int_get(op->ptr, "xmax");
908         int ymin= RNA_int_get(op->ptr, "ymin");
909         int ymax= RNA_int_get(op->ptr, "ymax");
910         
911         UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);      
912         UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);      
913         
914         /* XXX disputable */
915         if(yminf > 30.0f || ymaxf < 0.0f)
916                 return 0;
917         
918         if(markers == NULL)
919                 return 0;
920         
921         /* XXX marker context */
922         for(marker= markers->first; marker; marker= marker->next) {
923                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
924                         switch (gesture_mode) {
925                                 case GESTURE_MODAL_SELECT:
926                                         if ((marker->flag & SELECT) == 0) 
927                                                 marker->flag |= SELECT;
928                                         break;
929                                 case GESTURE_MODAL_DESELECT:
930                                         if (marker->flag & SELECT) 
931                                                 marker->flag &= ~SELECT;
932                                         break;
933                         }
934                 }
935         }
936         
937         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
938
939         return 1;
940 }
941
942 static void MARKER_OT_select_border(wmOperatorType *ot)
943 {
944         /* identifiers */
945         ot->name= "Marker Border select";
946         ot->description= "Select all time markers using border selection";
947         ot->idname= "MARKER_OT_select_border";
948         
949         /* api callbacks */
950         ot->exec= ed_marker_border_select_exec;
951         ot->invoke= WM_border_select_invoke;
952         ot->modal= WM_border_select_modal;
953         
954         ot->poll= ED_operator_areaactive;
955         
956         /* flags */
957         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
958         
959         /* rna */
960         WM_operator_properties_gesture_border(ot, FALSE);
961 }
962
963 /* *********************** (de)select all ***************** */
964
965 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
966 {
967         ListBase *markers= context_get_markers(C);
968         TimeMarker *marker;
969         int action = RNA_enum_get(op->ptr, "action");
970
971         if(markers == NULL)
972                 return OPERATOR_CANCELLED;
973
974         if (action == SEL_TOGGLE) {
975                 action = SEL_SELECT;
976                 for(marker= markers->first; marker; marker= marker->next) {
977                         if(marker->flag & SELECT) {
978                                 action = SEL_DESELECT;
979                                 break;
980                         }
981                 }
982         }
983         
984         for(marker= markers->first; marker; marker= marker->next) {
985                 switch (action) {
986                 case SEL_SELECT:
987                         marker->flag |= SELECT;
988                         break;
989                 case SEL_DESELECT:
990                         marker->flag &= ~SELECT;
991                         break;
992                 case SEL_INVERT:
993                         if (marker->flag & SELECT) {
994                                 marker->flag &= ~SELECT;
995                         } else {
996                                 marker->flag |= SELECT;
997                         }
998                         break;
999                 }
1000         }
1001         
1002         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1003
1004         return OPERATOR_FINISHED;
1005 }
1006
1007 static void MARKER_OT_select_all(wmOperatorType *ot)
1008 {
1009         /* identifiers */
1010         ot->name= "(De)select all markers";
1011         ot->description= "Change selection of all time markers";
1012         ot->idname= "MARKER_OT_select_all";
1013         
1014         /* api callbacks */
1015         ot->exec= ed_marker_select_all_exec;
1016         ot->poll= ED_operator_areaactive;
1017         
1018         /* flags */
1019         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1020         
1021         /* rna */
1022         WM_operator_properties_select_all(ot);
1023 }
1024
1025 /* ******************************* remove marker ***************** */
1026
1027 /* remove selected TimeMarkers */
1028 static int ed_marker_delete_exec(bContext *C, wmOperator *op)
1029 {
1030         ListBase *markers= context_get_markers(C);
1031         TimeMarker *marker, *nmarker;
1032         short changed= 0;
1033         
1034         if(markers == NULL)
1035                 return OPERATOR_CANCELLED;
1036         
1037         for(marker= markers->first; marker; marker= nmarker) {
1038                 nmarker= marker->next;
1039                 if(marker->flag & SELECT) {
1040                         BLI_freelinkN(markers, marker);
1041                         changed= 1;
1042                 }
1043         }
1044         
1045         if (changed)
1046                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1047         
1048         return OPERATOR_FINISHED;
1049 }
1050
1051
1052 static void MARKER_OT_delete(wmOperatorType *ot)
1053 {
1054         /* identifiers */
1055         ot->name= "Delete Markers";
1056         ot->description= "Delete selected time marker(s)";
1057         ot->idname= "MARKER_OT_delete";
1058         
1059         /* api callbacks */
1060         ot->invoke= WM_operator_confirm;
1061         ot->exec= ed_marker_delete_exec;
1062         ot->poll= ED_operator_areaactive;
1063         
1064         /* flags */
1065         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1066         
1067 }
1068
1069 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1070 {
1071         ListBase *markers= context_get_markers(C);
1072         Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "type"));
1073         TimeMarker *marker, *marker_new;
1074
1075         if(scene_to==NULL) {
1076                 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1077                 return OPERATOR_CANCELLED;
1078         }
1079
1080         if(scene_to == CTX_data_scene(C)) {
1081                 BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
1082                 return OPERATOR_CANCELLED;
1083         }
1084
1085         /* copy markers */
1086         for (marker= markers->first; marker; marker= marker->next) {
1087                 if(marker->flag & SELECT) {
1088                         marker_new= MEM_dupallocN(marker);
1089                         BLI_addtail(&scene_to->markers, marker_new);
1090                 }
1091         }
1092
1093         return OPERATOR_FINISHED;
1094 }
1095
1096 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1097 {
1098         PropertyRNA *prop;
1099
1100         /* identifiers */
1101         ot->name= "Make Links to Scene";
1102         ot->description= "Link markers to another scene";
1103         ot->idname= "MARKER_OT_make_links_scene";
1104
1105         /* api callbacks */
1106         ot->exec= ed_marker_make_links_scene_exec;
1107         ot->poll= ED_operator_areaactive;
1108
1109         /* flags */
1110         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1111
1112         /* properties */
1113         prop= RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", "");
1114         RNA_def_enum_funcs(prop, RNA_scene_itemf);
1115
1116 }
1117
1118 #ifdef DURIAN_CAMERA_SWITCH
1119 /* ******************************* camera bind marker ***************** */
1120
1121 /* remove selected TimeMarkers */
1122 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
1123 {
1124         Scene *scene= CTX_data_scene(C);
1125         ListBase *markers= context_get_markers(C);
1126         TimeMarker *marker;
1127         short changed= 0;
1128
1129         if(markers == NULL)
1130                 return OPERATOR_CANCELLED;
1131
1132         for(marker= markers->first; marker; marker= marker->next) {
1133                 if(marker->flag & SELECT) {
1134                         marker->camera= scene->camera;
1135                 }
1136         }
1137
1138         if (changed)
1139                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1140
1141         return OPERATOR_FINISHED;
1142 }
1143
1144 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1145 {
1146         /* identifiers */
1147         ot->name= "Bind Camera to Markers";
1148         ot->description= "Bind the active camera to selected markers(s)";
1149         ot->idname= "MARKER_OT_camera_bind";
1150
1151         /* api callbacks */
1152         ot->exec= ed_marker_camera_bind_exec;
1153         ot->poll= ED_operator_areaactive;
1154
1155         /* flags */
1156         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1157 }
1158 #endif
1159
1160 /* ************************** registration **********************************/
1161
1162 /* called in screen_ops.c:ED_operatortypes_screen() */
1163 void ED_operatortypes_marker(void)
1164 {
1165         WM_operatortype_append(MARKER_OT_add);
1166         WM_operatortype_append(MARKER_OT_move);
1167         WM_operatortype_append(MARKER_OT_duplicate);
1168         WM_operatortype_append(MARKER_OT_select);
1169         WM_operatortype_append(MARKER_OT_select_border);
1170         WM_operatortype_append(MARKER_OT_select_all);
1171         WM_operatortype_append(MARKER_OT_delete);
1172         WM_operatortype_append(MARKER_OT_make_links_scene);
1173 #ifdef DURIAN_CAMERA_SWITCH
1174         WM_operatortype_append(MARKER_OT_camera_bind);
1175 #endif
1176 }
1177
1178 /* called in screen_ops.c:ED_keymap_screen() */
1179 void ED_marker_keymap(wmKeyConfig *keyconf)
1180 {
1181         wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
1182         wmKeyMapItem *kmi;
1183         
1184         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1185         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1186         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1187         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1188         RNA_boolean_set(WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1189
1190 #ifdef DURIAN_CAMERA_SWITCH
1191         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1192         RNA_boolean_set(kmi->ptr, "camera", 1);
1193
1194         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1195         RNA_boolean_set(kmi->ptr, "extend", 1);
1196         RNA_boolean_set(kmi->ptr, "camera", 1);
1197 #endif
1198         
1199         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1200         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1201         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1202         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1203         
1204         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1205 #ifdef DURIAN_CAMERA_SWITCH
1206         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1207 #endif
1208 }