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