fix for incorrect array use when freeing fcurve modifier envelope points, array also...
[blender.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 /** \file blender/editors/animation/anim_markers.c
30  *  \ingroup edanimation
31  */
32
33
34 #include <math.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_scene_types.h"
39 #include "DNA_object_types.h"
40
41 #include "RNA_access.h"
42 #include "RNA_define.h"
43 #include "RNA_enum_types.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_context.h"
49 #include "BKE_fcurve.h"
50 #include "BKE_main.h"
51 #include "BKE_report.h"
52 #include "BKE_scene.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59
60 #include "UI_interface.h"
61 #include "UI_interface_icons.h"
62 #include "UI_view2d.h"
63 #include "UI_resources.h"
64
65 #include "ED_anim_api.h"
66 #include "ED_markers.h"
67 #include "ED_screen.h"
68 #include "ED_util.h"
69 #include "ED_numinput.h"
70 #include "ED_object.h"
71 #include "ED_transform.h"
72 #include "ED_types.h"
73
74 /* ************* Marker API **************** */
75
76 /* helper function for getting the list of markers to work on */
77 static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
78 {
79         /* local marker sets... */
80         if (sa) {
81                 if (sa->spacetype == SPACE_ACTION) {
82                         SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
83                         
84                         /* local markers can only be shown when there's only a single active action to grab them from 
85                          *      - flag only takes effect when there's an action, otherwise it can get too confusing?
86                          */
87                         if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action)) 
88                         {
89                                 if (saction->flag & SACTION_POSEMARKERS_SHOW)
90                                         return &saction->action->markers;
91                         }
92                 }
93         }
94         
95         /* default to using the scene's markers */
96         return &scene->markers;
97 }
98
99 /* ............. */
100
101 /* public API for getting markers from context */
102 ListBase *ED_context_get_markers(const bContext *C)
103 {
104         return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
105 }
106
107 /* public API for getting markers from "animation" context */
108 ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
109 {
110         if (ac)
111                 return context_get_markers(ac->scene, ac->sa);
112         else
113                 return NULL;
114 }
115
116 /* --------------------------------- */
117
118 /* Apply some transformation to markers after the fact 
119  * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything
120  * < scene: current scene (for getting current frame)
121  * < mode: (TfmMode) transform mode that this transform is for
122  * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale)
123  * < side: (B/L/R) for 'extend' functionality, which side of current frame to use
124  */
125 int ED_markers_post_apply_transform (ListBase *markers, Scene *scene, int mode, float value, char side)
126 {
127         TimeMarker *marker;
128         float cfra = (float)CFRA;
129         int changed = 0;
130         
131         /* sanity check */
132         if (markers == NULL)
133                 return changed;
134         
135         /* affect selected markers - it's unlikely that we will want to affect all in this way? */
136         for (marker = markers->first; marker; marker = marker->next) {
137                 if (marker->flag & SELECT) {
138                         switch (mode) {
139                                 case TFM_TIME_TRANSLATE:
140                                 case TFM_TIME_EXTEND:
141                                 {
142                                         /* apply delta if marker is on the right side of the current frame */
143                                         if ((side=='B') ||
144                                                 (side=='L' && marker->frame < cfra) || 
145                                             (side=='R' && marker->frame >= cfra))
146                                         {
147                                                 marker->frame += (int)floorf(value + 0.5f);
148                                                 changed++;
149                                         }
150                                 }
151                                         break;
152                                         
153                                 case TFM_TIME_SCALE:
154                                 {       
155                                         /* rescale the distance between the marker and the current frame */
156                                         marker->frame= cfra + (int)floorf(((float)(marker->frame - cfra) * value) + 0.5f);
157                                         changed++;
158                                 }
159                                         break;
160                         }
161                 }
162         }
163         
164         return changed;
165 }
166
167 /* --------------------------------- */
168
169 /* Get the marker that is closest to this point */
170 /* XXX for select, the min_dist should be small */
171 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x) 
172 {
173         TimeMarker *marker, *nearest=NULL;
174         float dist, min_dist= 1000000;
175         
176         if (markers) {
177                 for (marker= markers->first; marker; marker= marker->next) {
178                         dist = ABS((float)marker->frame - x);
179                         
180                         if (dist < min_dist) {
181                                 min_dist= dist;
182                                 nearest= marker;
183                         }
184                 }
185         }
186         
187         return nearest;
188 }
189
190 /* Return the time of the marker that occurs on a frame closest to the given time */
191 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
192 {
193         TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
194         return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
195 }
196
197
198 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
199 {
200         TimeMarker *marker;
201         float min, max;
202         int selcount = 0;
203         
204         /* sanity check */
205         //printf("markers = %p -  %p, %p \n", markers, markers->first, markers->last);
206         if (markers == NULL) {
207                 *first = 0.0f;
208                 *last = 0.0f;
209                 return;
210         }
211         
212         if (markers->first && markers->last) {
213                 TimeMarker *fm= markers->first;
214                 TimeMarker *lm= markers->last;
215                 
216                 min= (float)fm->frame;
217                 max= (float)lm->frame;
218         }
219         else {
220                 *first = 0.0f;
221                 *last = 0.0f;
222                 return;
223         }
224         
225         /* count how many markers are usable - see later */
226         if (sel) {
227                 for (marker= markers->first; marker; marker= marker->next) {
228                         if (marker->flag & SELECT)
229                                 selcount++;
230                 }
231         }
232         else
233                 selcount= BLI_countlist(markers);
234         
235         /* if only selected are to be considered, only consider the selected ones
236          * (optimisation for not searching list) 
237          */
238         if (selcount > 1) {
239                 for (marker= markers->first; marker; marker= marker->next) {
240                         if (sel) {
241                                 if (marker->flag & SELECT) {
242                                         if (marker->frame < min)
243                                                 min= (float)marker->frame;
244                                         if (marker->frame > max)
245                                                 max= (float)marker->frame;
246                                 }
247                         }
248                         else {
249                                 if (marker->frame < min)
250                                         min= (float)marker->frame;
251                                 if (marker->frame > max)
252                                         max= (float)marker->frame;
253                         }       
254                 }
255         }
256         
257         /* set the min/max values */
258         *first= min;
259         *last= max;
260 }
261
262 /* --------------------------------- */
263
264 /* Adds a marker to list of cfra elems */
265 static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
266 {
267         CfraElem *ce, *cen;
268         
269         /* should this one only be considered if it is selected? */
270         if ((only_sel) && ((marker->flag & SELECT)==0))
271                 return;
272         
273         /* insertion sort - try to find a previous cfra elem */
274         for (ce= lb->first; ce; ce= ce->next) {
275                 if (ce->cfra == marker->frame) {
276                         /* do because of double keys */
277                         if (marker->flag & SELECT) 
278                                 ce->sel= marker->flag;
279                         return;
280                 }
281                 else if (ce->cfra > marker->frame) break;
282         }       
283         
284         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
285         if (ce) BLI_insertlinkbefore(lb, ce, cen);
286         else BLI_addtail(lb, cen);
287
288         cen->cfra= marker->frame;
289         cen->sel= marker->flag;
290 }
291
292 /* This function makes a list of all the markers. The only_sel
293  * argument is used to specify whether only the selected markers
294  * are added.
295  */
296 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
297 {
298         TimeMarker *marker;
299         
300         if (markers == NULL)
301                 return;
302         
303         for (marker= markers->first; marker; marker= marker->next)
304                 add_marker_to_cfra_elem(lb, marker, only_sel);
305 }
306
307 /* --------------------------------- */
308
309 /* Get the first selected marker */
310 TimeMarker *ED_markers_get_first_selected(ListBase *markers)
311 {
312         TimeMarker *marker;
313         
314         if (markers) {
315                 for (marker = markers->first; marker; marker = marker->next) {
316                         if (marker->flag & SELECT)
317                                 return marker;
318                 }
319         }
320         
321         return NULL;
322 }
323
324 /* --------------------------------- */
325
326 /* Print debugging prints of list of markers 
327  * BSI's: do NOT make static or put in if-defs as "unused code". That's too much trouble when we need to use for quick debuggging!
328  */
329 void debug_markers_print_list(ListBase *markers)
330 {
331         TimeMarker *marker;
332         
333         if (markers == NULL) {
334                 printf("No markers list to print debug for\n");
335                 return;
336         }
337         
338         printf("List of markers follows: -----\n");
339         
340         for (marker = markers->first; marker; marker = marker->next) {
341                 printf("\t'%s' on %d at %p with %d\n", marker->name, marker->frame, (void *)marker, marker->flag);
342         }
343         
344         printf("End of list ------------------\n");
345 }
346
347 /* ************* Marker Drawing ************ */
348
349 /* function to draw markers */
350 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
351 {
352         float xpos, ypixels, xscale, yscale;
353         int icon_id= 0;
354         
355         xpos = marker->frame;
356         
357         /* no time correction for framelen! space is drawn with old values */
358         ypixels= v2d->mask.ymax-v2d->mask.ymin;
359         UI_view2d_getscale(v2d, &xscale, &yscale);
360         
361         glScalef(1.0f/xscale, 1.0f, 1.0f);
362         
363         glEnable(GL_BLEND);
364         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                      
365         
366         /* vertical line - dotted */
367 #ifdef DURIAN_CAMERA_SWITCH
368         if ((marker->camera) || (flag & DRAW_MARKERS_LINES))
369 #else
370         if (flag & DRAW_MARKERS_LINES)
371 #endif
372         {
373                 setlinestyle(3);
374                 
375                 if (marker->flag & SELECT)
376                         glColor4ub(255, 255, 255, 96);
377                 else
378                         glColor4ub(0, 0, 0, 96);
379                 
380                 glBegin(GL_LINES);
381                         glVertex2f((xpos*xscale)+0.5f, 12.0f);
382                         glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
383                 glEnd();
384                 
385                 setlinestyle(0);
386         }
387         
388         /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
389         if (flag & DRAW_MARKERS_LOCAL) {
390                 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : 
391                 (marker->flag & SELECT) ? ICON_PMARKER_SEL : 
392                 ICON_PMARKER;
393         }
394         else {
395                 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT : 
396                 ICON_MARKER;
397         }
398         
399         UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
400         
401         glDisable(GL_BLEND);
402         
403         /* and the marker name too, shifted slightly to the top-right */
404         if (marker->name && marker->name[0]) {
405                 float x, y;
406                 
407                 if (marker->flag & SELECT) {
408                         UI_ThemeColor(TH_TEXT_HI);
409                         x= xpos*xscale + 4.0f;
410                         y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
411                 }
412                 else {
413                         UI_ThemeColor(TH_TEXT);
414                         if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
415                                 x= xpos*xscale + 4.0f;
416                                 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
417                         }
418                         else {
419                                 x= xpos*xscale + 4.0f;
420                                 y= 17.0f;
421                         }
422                 }
423
424 #ifdef DURIAN_CAMERA_SWITCH
425                 if(marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
426                         float col[4];
427                         glGetFloatv(GL_CURRENT_COLOR, col);
428                         col[3]= 0.4;
429                         glColor4fv(col);
430                 }
431 #endif
432
433                 UI_DrawString(x, y, marker->name);
434         }
435         
436         glScalef(xscale, 1.0f, 1.0f);
437 }
438
439 /* Draw Scene-Markers in time window */
440 void draw_markers_time(const bContext *C, int flag)
441 {
442         ListBase *markers= ED_context_get_markers(C);
443         View2D *v2d= UI_view2d_fromcontext(C);
444         TimeMarker *marker;
445         
446         if (markers == NULL)
447                 return;
448         
449         /* unselected markers are drawn at the first time */
450         for (marker= markers->first; marker; marker= marker->next) {
451                 if ((marker->flag & SELECT) == 0) 
452                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
453         }
454         
455         /* selected markers are drawn later */
456         for (marker= markers->first; marker; marker= marker->next) {
457                 if (marker->flag & SELECT) 
458                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
459         }
460 }
461
462 /* ************************ Marker Wrappers API ********************* */
463 /* These wrappers allow marker operators to function within the confines 
464  * of standard animation editors, such that they can coexist with the 
465  * primary operations of those editors.
466  */
467
468 /* ------------------------ */
469
470 /* special poll() which checks if there are selected markers first */
471 static int ed_markers_poll_selected_markers(bContext *C)
472 {
473         ListBase *markers = ED_context_get_markers(C);
474         
475         /* first things first: markers can only exist in timeline views */
476         if (ED_operator_animview_active(C) == 0)
477                 return 0;
478                 
479         /* check if some marker is selected */
480         return ED_markers_get_first_selected(markers) != NULL;
481 }
482
483 /* special poll() which checks if there are any markers at all first */
484 static int ed_markers_poll_markers_exist(bContext *C)
485 {
486         ListBase *markers = ED_context_get_markers(C);
487         
488         /* first things first: markers can only exist in timeline views */
489         if (ED_operator_animview_active(C) == 0)
490                 return 0;
491                 
492         /* list of markers must exist, as well as some markers in it! */
493         return (markers && markers->first);
494 }
495  
496 /* ------------------------ */ 
497
498 /* Second-tier invoke() callback that performs context validation before running the  
499  * "custom"/third-tier invoke() callback supplied as the last arg (which would normally
500  * be the operator's invoke() callback elsewhere)
501  *
502  * < invoke_func: (fn(bContext*, wmOperator*, wmEvent*)=int) "standard" invoke function 
503  *                      that operator would otherwise have used. If NULL, the operator's standard
504  *                      exec() callback will be called instead in the appropriate places.
505  */
506 static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt, 
507                 int (*invoke_func)(bContext*,wmOperator*,wmEvent*))
508 {
509         ScrArea *sa = CTX_wm_area(C);
510         int retval = OPERATOR_PASS_THROUGH;
511         
512         /* removed check for Y coord of event, keymap has bounbox now */
513         
514         /* allow operator to run now */
515         if (invoke_func)
516                 retval = invoke_func(C, op, evt);
517         else if (op->type->exec)
518                 retval = op->type->exec(C, op);
519         else
520                 BKE_report(op->reports, RPT_ERROR, "Programming error: operator doesn't actually have code to do anything!");
521                 
522         /* return status modifications - for now, make this spacetype dependent as above */
523         if (sa->spacetype != SPACE_TIME) {
524                 /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
525                 if (retval != OPERATOR_FINISHED)
526                         retval |= OPERATOR_PASS_THROUGH;
527         }
528         
529         return retval;
530 }
531
532 /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata
533  * for operators which don't need any special invoke calls. Any operators with special invoke calls
534  * though will need to implement their own wrapper which calls the second-tier callback themselves
535  * (passing through the custom invoke function they use)
536  */
537 static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
538 {
539         return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
540 }
541
542 /* ************************** add markers *************************** */
543
544 /* add TimeMarker at curent frame */
545 static int ed_marker_add(bContext *C, wmOperator *UNUSED(op))
546 {
547         ListBase *markers= ED_context_get_markers(C);
548         TimeMarker *marker;
549         int frame= CTX_data_scene(C)->r.cfra;
550         
551         if (markers == NULL)
552                 return OPERATOR_CANCELLED;
553         
554         /* two markers can't be at the same place */
555         for (marker= markers->first; marker; marker= marker->next) {
556                 if (marker->frame == frame) 
557                         return OPERATOR_CANCELLED;
558         }
559         
560         /* deselect all */
561         for (marker= markers->first; marker; marker= marker->next)
562                 marker->flag &= ~SELECT;
563         
564         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
565         marker->flag= SELECT;
566         marker->frame= frame;
567         BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only
568         BLI_addtail(markers, marker);
569         
570         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
571         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
572         
573         return OPERATOR_FINISHED;
574 }
575
576 static void MARKER_OT_add(wmOperatorType *ot)
577 {
578         /* identifiers */
579         ot->name= "Add Time Marker";
580         ot->description= "Add a new time marker";
581         ot->idname= "MARKER_OT_add";
582         
583         /* api callbacks */
584         ot->exec= ed_marker_add;
585         ot->invoke = ed_markers_opwrap_invoke;
586         ot->poll= ED_operator_animview_active;
587         
588         /* flags */
589         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
590 }
591
592 /* ************************** transform markers *************************** */
593
594
595 /* operator state vars used:  
596         frs: delta movement
597
598 functions:
599
600         init()   check selection, add customdata with old values and some lookups
601
602         apply()  do the actual movement
603
604         exit()  cleanup, send notifier
605
606         cancel() to escape from modal
607
608 callbacks:
609
610         exec()  calls init, apply, exit 
611
612         invoke() calls init, adds modal handler
613
614         modal() accept modal events while doing it, ends with apply and exit, or cancel
615
616 */
617
618 typedef struct MarkerMove {
619         SpaceLink *slink;
620         ListBase *markers;
621         int event_type;         /* store invoke-event, to verify */
622         int *oldframe, evtx, firstx;
623         NumInput num;
624 } MarkerMove;
625
626 /* copy selection to temp buffer */
627 /* return 0 if not OK */
628 static int ed_marker_move_init(bContext *C, wmOperator *op)
629 {
630         ListBase *markers= ED_context_get_markers(C);
631         MarkerMove *mm;
632         TimeMarker *marker;
633         int totmark=0;
634         int a;
635
636         if(markers == NULL) return 0;
637         
638         for (marker= markers->first; marker; marker= marker->next)
639                 if (marker->flag & SELECT) totmark++;
640         
641         if (totmark==0) return 0;
642         
643         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
644         mm->slink= CTX_wm_space_data(C);
645         mm->markers= markers;
646         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
647
648         initNumInput(&mm->num);
649         mm->num.idx_max = 0; /* one axis */
650         mm->num.flag |= NUM_NO_FRACTION;
651         mm->num.increment = 1.0f;
652         
653         for (a=0, marker= markers->first; marker; marker= marker->next) {
654                 if (marker->flag & SELECT) {
655                         mm->oldframe[a]= marker->frame;
656                         a++;
657                 }
658         }
659         
660         return 1;
661 }
662
663 /* free stuff */
664 static void ed_marker_move_exit(bContext *C, wmOperator *op)
665 {
666         MarkerMove *mm= op->customdata;
667         
668         /* free data */
669         MEM_freeN(mm->oldframe);
670         MEM_freeN(op->customdata);
671         op->customdata= NULL;
672         
673         /* clear custom header prints */
674         ED_area_headerprint(CTX_wm_area(C), NULL);
675 }
676
677 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
678 {
679         if(ed_marker_move_init(C, op)) {
680                 MarkerMove *mm= op->customdata;
681                 
682                 mm->evtx= evt->x;
683                 mm->firstx= evt->x;
684                 mm->event_type= evt->type;
685                 
686                 /* add temp handler */
687                 WM_event_add_modal_handler(C, op);
688                 
689                 /* reset frs delta */
690                 RNA_int_set(op->ptr, "frames", 0);
691                 
692                 return OPERATOR_RUNNING_MODAL;
693         }
694         
695         return OPERATOR_CANCELLED;
696 }
697
698 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
699 {
700         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
701 }
702
703 /* note, init has to be called succesfully */
704 static void ed_marker_move_apply(wmOperator *op)
705 {
706         MarkerMove *mm= op->customdata;
707         TimeMarker *marker;
708         int a, offs;
709         
710         offs= RNA_int_get(op->ptr, "frames");
711         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
712                 if (marker->flag & SELECT) {
713                         marker->frame= mm->oldframe[a] + offs;
714                         a++;
715                 }
716         }
717 }
718
719 /* only for modal */
720 static void ed_marker_move_cancel(bContext *C, wmOperator *op)
721 {
722         RNA_int_set(op->ptr, "frames", 0);
723         ed_marker_move_apply(op);
724         ed_marker_move_exit(C, op);     
725         
726         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
727         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
728 }
729
730
731
732 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
733 {
734         Scene *scene= CTX_data_scene(C);
735         MarkerMove *mm= op->customdata;
736         View2D *v2d= UI_view2d_fromcontext(C);
737         TimeMarker *marker, *selmarker=NULL;
738         float dx, fac;
739         char str[256];
740                 
741         switch(evt->type) {
742                 case ESCKEY:
743                         ed_marker_move_cancel(C, op);
744                         return OPERATOR_CANCELLED;
745                 
746                 case RIGHTMOUSE:
747                         /* press = user manually demands transform to be cancelled */
748                         if (evt->val == KM_PRESS) {
749                                 ed_marker_move_cancel(C, op);
750                                 return OPERATOR_CANCELLED;
751                         }
752                         /* else continue; <--- see if release event should be caught for tweak-end */
753                 
754                 case RETKEY:
755                 case PADENTER:
756                 case LEFTMOUSE:
757                 case MIDDLEMOUSE:
758                         if (WM_modal_tweak_exit(evt, mm->event_type)) {
759                                 ed_marker_move_exit(C, op);
760                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
761                                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
762                                 return OPERATOR_FINISHED;
763                         }
764                         break;
765                 case MOUSEMOVE:
766                         if (hasNumInput(&mm->num))
767                                 break;
768                         
769                         dx= v2d->mask.xmax-v2d->mask.xmin;
770                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
771                         
772                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
773                                 int a, offs, totmark=0;
774                                 
775                                 mm->evtx= evt->x;
776                                 
777                                 fac= ((float)(evt->x - mm->firstx)*dx);
778                                 
779                                 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) 
780                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
781                                 else
782                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
783                                 
784                                 offs= (int)fac;
785                                 RNA_int_set(op->ptr, "frames", offs);
786                                 ed_marker_move_apply(op);
787                                 
788                                 /* cruft below is for header print */
789                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
790                                         if (marker->flag & SELECT) {
791                                                 selmarker= marker;
792                                                 a++; totmark++;
793                                         }
794                                 }
795                                 
796                                 if (totmark==1) {       
797                                         /* we print current marker value */
798                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
799                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
800                                                 if (stime->flag & TIME_DRAWFRAMES) 
801                                                         BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
802                                                 else 
803                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
804                                         }
805                                         else if (mm->slink->spacetype == SPACE_ACTION) {
806                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
807                                                 if (saction->flag & SACTION_DRAWTIME)
808                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
809                                                 else
810                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
811                                         }
812                                         else {
813                                                 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
814                                         }
815                                 }
816                                 else {
817                                         /* we only print the offset */
818                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { 
819                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
820                                                 if (stime->flag & TIME_DRAWFRAMES) 
821                                                         BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
822                                                 else 
823                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
824                                         }
825                                         else if (mm->slink->spacetype == SPACE_ACTION) {
826                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
827                                                 if (saction->flag & SACTION_DRAWTIME)
828                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
829                                                 else
830                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
831                                         }
832                                         else {
833                                                 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
834                                         }
835                                 }
836                                 
837                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
838                                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
839                                 ED_area_headerprint(CTX_wm_area(C), str);
840                         }
841         }
842
843         if (evt->val==KM_PRESS) {
844                 float vec[3];
845                 char str_tx[256];
846                 
847                 if (handleNumInput(&mm->num, evt))
848                 {
849                         applyNumInput(&mm->num, vec);
850                         outputNumInput(&mm->num, str_tx);
851                         
852                         RNA_int_set(op->ptr, "frames", vec[0]);
853                         ed_marker_move_apply(op);
854                         // ed_marker_header_update(C, op, str, (int)vec[0]);
855                         // strcat(str, str_tx);
856                         BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
857                         ED_area_headerprint(CTX_wm_area(C), str);
858                         
859                         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
860                         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
861                 }
862         }
863
864         return OPERATOR_RUNNING_MODAL;
865 }
866
867 static int ed_marker_move_exec(bContext *C, wmOperator *op)
868 {
869         if(ed_marker_move_init(C, op)) {
870                 ed_marker_move_apply(op);
871                 ed_marker_move_exit(C, op);
872                 return OPERATOR_FINISHED;
873         }
874         return OPERATOR_PASS_THROUGH;
875 }
876
877 static void MARKER_OT_move(wmOperatorType *ot)
878 {
879         /* identifiers */
880         ot->name= "Move Time Marker";
881         ot->description= "Move selected time marker(s)";
882         ot->idname= "MARKER_OT_move";
883         
884         /* api callbacks */
885         ot->exec= ed_marker_move_exec;
886         ot->invoke= ed_marker_move_invoke_wrapper;
887         ot->modal= ed_marker_move_modal;
888         ot->poll= ed_markers_poll_selected_markers;
889         
890         /* flags */
891         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
892         
893         /* rna storage */
894         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
895 }
896
897 /* ************************** duplicate markers *************************** */
898
899 /* operator state vars used:  
900         frs: delta movement
901
902 functions:
903
904         apply()  do the actual duplicate
905
906 callbacks:
907
908         exec()  calls apply, move_exec
909
910         invoke() calls apply, move_invoke
911
912         modal() uses move_modal
913
914 */
915
916
917 /* duplicate selected TimeMarkers */
918 static void ed_marker_duplicate_apply(bContext *C)
919 {
920         ListBase *markers= ED_context_get_markers(C);
921         TimeMarker *marker, *newmarker;
922         
923         if (markers == NULL) 
924                 return;
925
926         /* go through the list of markers, duplicate selected markers and add duplicated copies
927          * to the begining of the list (unselect original markers) 
928          */
929         for (marker= markers->first; marker; marker= marker->next) {
930                 if (marker->flag & SELECT) {
931                         /* unselect selected marker */
932                         marker->flag &= ~SELECT;
933                         
934                         /* create and set up new marker */
935                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
936                         newmarker->flag= SELECT;
937                         newmarker->frame= marker->frame;
938                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
939                         
940 #ifdef DURIAN_CAMERA_SWITCH
941                         newmarker->camera= marker->camera;
942 #endif
943
944                         /* new marker is added to the begining of list */
945                         // FIXME: bad ordering!
946                         BLI_addhead(markers, newmarker);
947                 }
948         }
949 }
950
951 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
952 {
953         ed_marker_duplicate_apply(C);
954         ed_marker_move_exec(C, op);     /* assumes frs delta set */
955         
956         return OPERATOR_FINISHED;
957         
958 }
959
960 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
961 {
962         ed_marker_duplicate_apply(C);
963         return ed_marker_move_invoke(C, op, evt);
964 }
965
966 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
967 {
968         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
969 }
970
971 static void MARKER_OT_duplicate(wmOperatorType *ot)
972 {
973         /* identifiers */
974         ot->name= "Duplicate Time Marker";
975         ot->description= "Duplicate selected time marker(s)";
976         ot->idname= "MARKER_OT_duplicate";
977         
978         /* api callbacks */
979         ot->exec= ed_marker_duplicate_exec;
980         ot->invoke= ed_marker_duplicate_invoke_wrapper;
981         ot->modal= ed_marker_move_modal;
982         ot->poll= ed_markers_poll_selected_markers;
983         
984         /* flags */
985         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
986         
987         /* rna storage */
988         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
989 }
990
991 /* ************************** selection ************************************/
992
993 /* select/deselect TimeMarker at current frame */
994 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
995 {
996         TimeMarker *marker;
997         int select=0;
998         
999         for (marker= markers->first; marker; marker= marker->next) {
1000                 /* if Shift is not set, then deselect Markers */
1001                 if (!shift) marker->flag &= ~SELECT;
1002                 
1003                 /* this way a not-shift select will allways give 1 selected marker */
1004                 if ((marker->frame == frame) && (!select)) {
1005                         if (marker->flag & SELECT) 
1006                                 marker->flag &= ~SELECT;
1007                         else
1008                                 marker->flag |= SELECT;
1009                         select = 1;
1010                 }
1011         }
1012 }
1013
1014 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1015 {
1016         ListBase *markers= ED_context_get_markers(C);
1017         View2D *v2d= UI_view2d_fromcontext(C);
1018         float viewx;
1019         int x, y, cfra;
1020         
1021         if (markers == NULL)
1022                 return OPERATOR_PASS_THROUGH;
1023
1024         x= evt->x - CTX_wm_region(C)->winrct.xmin;
1025         y= evt->y - CTX_wm_region(C)->winrct.ymin;
1026         
1027         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
1028         
1029         cfra= ED_markers_find_nearest_marker_time(markers, viewx);
1030         
1031         if (extend)
1032                 select_timeline_marker_frame(markers, cfra, 1);
1033         else
1034                 select_timeline_marker_frame(markers, cfra, 0);
1035         
1036 #ifdef DURIAN_CAMERA_SWITCH
1037
1038         if (camera) {
1039                 Scene *scene= CTX_data_scene(C);
1040                 Base *base;
1041                 TimeMarker *marker;
1042                 int sel= 0;
1043                 
1044                 if (!extend)
1045                         scene_deselect_all(scene);
1046                 
1047                 for (marker= markers->first; marker; marker= marker->next) {
1048                         if(marker->frame==cfra) {
1049                                 sel= (marker->flag & SELECT);
1050                                 break;
1051                         }
1052                 }
1053                 
1054                 for (marker= markers->first; marker; marker= marker->next) {
1055                         if (marker->camera) {
1056                                 if (marker->frame==cfra) {
1057                                         base= object_in_scene(marker->camera, scene);
1058                                         if (base) {
1059                                                 ED_base_object_select(base, sel);
1060                                                 if(sel)
1061                                                         ED_base_object_activate(C, base);
1062                                         }
1063                                 }
1064                         }
1065                 }
1066                 
1067                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1068         }
1069 #endif
1070
1071         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1072         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1073
1074         /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
1075         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1076 }
1077
1078 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1079 {
1080         short extend= RNA_boolean_get(op->ptr, "extend");
1081         short camera= 0;
1082 #ifdef DURIAN_CAMERA_SWITCH
1083         camera= RNA_boolean_get(op->ptr, "camera");
1084 #endif
1085         return ed_marker_select(C, evt, extend, camera);
1086 }
1087
1088 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1089 {
1090         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
1091 }
1092
1093 static void MARKER_OT_select(wmOperatorType *ot)
1094 {
1095         /* identifiers */
1096         ot->name= "Select Time Marker";
1097         ot->description= "Select time marker(s)";
1098         ot->idname= "MARKER_OT_select";
1099         
1100         /* api callbacks */
1101         ot->invoke= ed_marker_select_invoke_wrapper;
1102         ot->poll= ed_markers_poll_markers_exist;
1103         
1104         /* flags */
1105         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1106
1107         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
1108 #ifdef DURIAN_CAMERA_SWITCH
1109         RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
1110 #endif
1111 }
1112
1113 /* *************************** border select markers **************** */
1114
1115 /* operator state vars used: (added by default WM callbacks)   
1116         xmin, ymin     
1117         xmax, ymax     
1118
1119 customdata: the wmGesture pointer, with subwindow
1120
1121 callbacks:
1122
1123         exec()  has to be filled in by user
1124
1125         invoke() default WM function
1126                         adds modal handler
1127
1128         modal() default WM function 
1129                         accept modal events while doing it, calls exec(), handles ESC and border drawing
1130
1131         poll()  has to be filled in by user for context
1132 */
1133
1134 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
1135 {
1136         View2D *v2d= UI_view2d_fromcontext(C);
1137         ListBase *markers= ED_context_get_markers(C);
1138         TimeMarker *marker;
1139         float xminf, xmaxf, yminf, ymaxf;
1140         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1141         int xmin= RNA_int_get(op->ptr, "xmin");
1142         int xmax= RNA_int_get(op->ptr, "xmax");
1143         int ymin= RNA_int_get(op->ptr, "ymin");
1144         int ymax= RNA_int_get(op->ptr, "ymax");
1145         
1146         UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);      
1147         UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);      
1148         
1149         if (markers == NULL)
1150                 return 0;
1151         
1152         /* XXX marker context */
1153         for (marker= markers->first; marker; marker= marker->next) {
1154                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
1155                         switch (gesture_mode) {
1156                                 case GESTURE_MODAL_SELECT:
1157                                         marker->flag |= SELECT;
1158                                         break;
1159                                 case GESTURE_MODAL_DESELECT:
1160                                         marker->flag &= ~SELECT;
1161                                         break;
1162                         }
1163                 }
1164         }
1165         
1166         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1167         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1168
1169         return 1;
1170 }
1171
1172 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1173 {
1174         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
1175 }
1176
1177 static void MARKER_OT_select_border(wmOperatorType *ot)
1178 {
1179         /* identifiers */
1180         ot->name= "Marker Border select";
1181         ot->description= "Select all time markers using border selection";
1182         ot->idname= "MARKER_OT_select_border";
1183         
1184         /* api callbacks */
1185         ot->exec= ed_marker_border_select_exec;
1186         ot->invoke= ed_marker_select_border_invoke_wrapper;
1187         ot->modal= WM_border_select_modal;
1188         
1189         ot->poll= ed_markers_poll_markers_exist;
1190         
1191         /* flags */
1192         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1193         
1194         /* rna */
1195         WM_operator_properties_gesture_border(ot, FALSE);
1196 }
1197
1198 /* *********************** (de)select all ***************** */
1199
1200 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
1201 {
1202         ListBase *markers= ED_context_get_markers(C);
1203         TimeMarker *marker;
1204         int action = RNA_enum_get(op->ptr, "action");
1205
1206         if (markers == NULL)
1207                 return OPERATOR_CANCELLED;
1208
1209         if (action == SEL_TOGGLE) {
1210                 action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
1211         }
1212         
1213         for(marker= markers->first; marker; marker= marker->next) {
1214                 switch (action) {
1215                 case SEL_SELECT:
1216                         marker->flag |= SELECT;
1217                         break;
1218                 case SEL_DESELECT:
1219                         marker->flag &= ~SELECT;
1220                         break;
1221                 case SEL_INVERT:
1222                         marker->flag ^= SELECT;
1223                         break;
1224                 }
1225         }
1226         
1227         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1228         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1229
1230         return OPERATOR_FINISHED;
1231 }
1232
1233 static void MARKER_OT_select_all(wmOperatorType *ot)
1234 {
1235         /* identifiers */
1236         ot->name= "(De)select all markers";
1237         ot->description= "Change selection of all time markers";
1238         ot->idname= "MARKER_OT_select_all";
1239         
1240         /* api callbacks */
1241         ot->exec= ed_marker_select_all_exec;
1242         ot->invoke = ed_markers_opwrap_invoke;
1243         ot->poll= ed_markers_poll_markers_exist;
1244         
1245         /* flags */
1246         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1247         
1248         /* rna */
1249         WM_operator_properties_select_all(ot);
1250 }
1251
1252 /* ***************** remove marker *********************** */
1253
1254 /* remove selected TimeMarkers */
1255 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
1256 {
1257         ListBase *markers= ED_context_get_markers(C);
1258         TimeMarker *marker, *nmarker;
1259         short changed= 0;
1260         
1261         if (markers == NULL)
1262                 return OPERATOR_CANCELLED;
1263         
1264         for (marker= markers->first; marker; marker= nmarker) {
1265                 nmarker= marker->next;
1266                 if (marker->flag & SELECT) {
1267                         BLI_freelinkN(markers, marker);
1268                         changed= 1;
1269                 }
1270         }
1271         
1272         if (changed) {
1273                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1274                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1275         }
1276         
1277         return OPERATOR_FINISHED;
1278 }
1279
1280 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1281 {
1282         // XXX: must we keep these confirmations?
1283         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
1284 }
1285
1286 static void MARKER_OT_delete(wmOperatorType *ot)
1287 {
1288         /* identifiers */
1289         ot->name= "Delete Markers";
1290         ot->description= "Delete selected time marker(s)";
1291         ot->idname= "MARKER_OT_delete";
1292         
1293         /* api callbacks */
1294         ot->invoke= ed_marker_delete_invoke_wrapper;
1295         ot->exec= ed_marker_delete_exec;
1296         ot->poll= ed_markers_poll_selected_markers;
1297         
1298         /* flags */
1299         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
1300 }
1301
1302
1303 /* **************** rename marker ***************** */
1304
1305 /* rename first selected TimeMarker */
1306 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
1307 {
1308         TimeMarker *marker= ED_markers_get_first_selected(ED_context_get_markers(C));
1309
1310         if (marker) {
1311                 RNA_string_get(op->ptr, "name", marker->name);
1312                 
1313                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1314                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1315                 
1316                 return OPERATOR_FINISHED;
1317         }
1318         else {
1319                 return OPERATOR_CANCELLED;
1320         }
1321 }
1322
1323 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1324 {
1325         /* must initialise the marker name first if there is a marker selected */
1326         TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1327         if (marker)
1328                 RNA_string_set(op->ptr, "name", marker->name);
1329         
1330         /* now see if the operator is usable */
1331         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
1332 }
1333
1334 static void MARKER_OT_rename(wmOperatorType *ot)
1335 {
1336         /* identifiers */
1337         ot->name= "Rename Marker";
1338         ot->description= "Rename first selected time marker";
1339         ot->idname= "MARKER_OT_rename";
1340         
1341         /* api callbacks */
1342         ot->invoke= ed_marker_rename_invoke_wrapper;
1343         ot->exec= ed_marker_rename_exec;
1344         ot->poll= ed_markers_poll_selected_markers;
1345         
1346         /* flags */
1347         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
1348         
1349         /* properties */
1350         ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
1351         //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
1352 }
1353
1354 /* **************** make links to scene ***************** */
1355
1356 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1357 {
1358         ListBase *markers= ED_context_get_markers(C);
1359         Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
1360         TimeMarker *marker, *marker_new;
1361
1362         if (scene_to==NULL) {
1363                 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1364                 return OPERATOR_CANCELLED;
1365         }
1366
1367         if (scene_to == CTX_data_scene(C)) {
1368                 BKE_report(op->reports, RPT_ERROR, "Can't re-link markers into the same scene");
1369                 return OPERATOR_CANCELLED;
1370         }
1371
1372         /* copy markers */
1373         for (marker= markers->first; marker; marker= marker->next) {
1374                 if (marker->flag & SELECT) {
1375                         marker_new= MEM_dupallocN(marker);
1376                         marker_new->prev= marker_new->next = NULL;
1377                         
1378                         BLI_addtail(&scene_to->markers, marker_new);
1379                 }
1380         }
1381
1382         return OPERATOR_FINISHED;
1383 }
1384
1385 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1386 {
1387         PropertyRNA *prop;
1388
1389         /* identifiers */
1390         ot->name= "Make Links to Scene";
1391         ot->description= "Copy selected markers to another scene";
1392         ot->idname= "MARKER_OT_make_links_scene";
1393
1394         /* api callbacks */
1395         ot->exec= ed_marker_make_links_scene_exec;
1396         ot->invoke = ed_markers_opwrap_invoke;
1397         ot->poll= ed_markers_poll_selected_markers;
1398
1399         /* flags */
1400         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1401
1402         /* properties */
1403         prop= RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
1404         RNA_def_enum_funcs(prop, RNA_scene_itemf);
1405         ot->prop= prop;
1406
1407 }
1408
1409 #ifdef DURIAN_CAMERA_SWITCH
1410 /* ******************************* camera bind marker ***************** */
1411
1412 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
1413 {
1414         Scene *scene= CTX_data_scene(C);
1415         ListBase *markers= ED_context_get_markers(C);
1416         TimeMarker *marker;
1417
1418         marker= ED_markers_get_first_selected(markers);
1419         if(marker == NULL)
1420                 return OPERATOR_CANCELLED;
1421
1422         marker->camera= scene->camera;
1423
1424         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1425         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1426
1427         return OPERATOR_FINISHED;
1428 }
1429
1430 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1431 {
1432         /* identifiers */
1433         ot->name= "Bind Camera to Markers";
1434         ot->description= "Bind the active camera to selected markers(s)";
1435         ot->idname= "MARKER_OT_camera_bind";
1436
1437         /* api callbacks */
1438         ot->exec= ed_marker_camera_bind_exec;
1439         ot->invoke = ed_markers_opwrap_invoke;
1440         ot->poll= ed_markers_poll_selected_markers;
1441
1442         /* flags */
1443         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1444 }
1445 #endif
1446
1447 /* ************************** registration **********************************/
1448
1449 /* called in screen_ops.c:ED_operatortypes_screen() */
1450 void ED_operatortypes_marker(void)
1451 {
1452         WM_operatortype_append(MARKER_OT_add);
1453         WM_operatortype_append(MARKER_OT_move);
1454         WM_operatortype_append(MARKER_OT_duplicate);
1455         WM_operatortype_append(MARKER_OT_select);
1456         WM_operatortype_append(MARKER_OT_select_border);
1457         WM_operatortype_append(MARKER_OT_select_all);
1458         WM_operatortype_append(MARKER_OT_delete);
1459         WM_operatortype_append(MARKER_OT_rename);
1460         WM_operatortype_append(MARKER_OT_make_links_scene);
1461 #ifdef DURIAN_CAMERA_SWITCH
1462         WM_operatortype_append(MARKER_OT_camera_bind);
1463 #endif
1464 }
1465
1466 /* called in screen_ops.c:ED_keymap_screen() */
1467 void ED_marker_keymap(wmKeyConfig *keyconf)
1468 {
1469         wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
1470         wmKeyMapItem *kmi;
1471         
1472         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1473         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1474         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1475         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1476         RNA_boolean_set(WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1477
1478 #ifdef DURIAN_CAMERA_SWITCH
1479         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1480         RNA_boolean_set(kmi->ptr, "camera", 1);
1481
1482         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1483         RNA_boolean_set(kmi->ptr, "extend", 1);
1484         RNA_boolean_set(kmi->ptr, "camera", 1);
1485 #endif
1486         
1487         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1488         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1489         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1490         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1491         WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1492         
1493         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1494 #ifdef DURIAN_CAMERA_SWITCH
1495         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1496 #endif
1497 }