remove po/ since the workflow for translations uses branches which isnt that useful...
[blender.git] / source / blender / editors / animation / anim_markers.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/animation/anim_markers.c
28  *  \ingroup edanimation
29  */
30
31
32 #include <math.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_scene_types.h"
37 #include "DNA_object_types.h"
38
39 #include "RNA_access.h"
40 #include "RNA_define.h"
41 #include "RNA_enum_types.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_context.h"
47 #include "BKE_fcurve.h"
48 #include "BKE_main.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_screen.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58
59 #include "UI_interface.h"
60 #include "UI_interface_icons.h"
61 #include "UI_view2d.h"
62 #include "UI_resources.h"
63
64 #include "ED_anim_api.h"
65 #include "ED_markers.h"
66 #include "ED_screen.h"
67 #include "ED_util.h"
68 #include "ED_numinput.h"
69 #include "ED_object.h"
70 #include "ED_transform.h"
71 #include "ED_types.h"
72
73 /* ************* Marker API **************** */
74
75 /* helper function for getting the list of markers to work on */
76 static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
77 {
78         /* local marker sets... */
79         if (sa) {
80                 if (sa->spacetype == SPACE_ACTION) {
81                         SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
82                         
83                         /* local markers can only be shown when there's only a single active action to grab them from 
84                          *      - flag only takes effect when there's an action, otherwise it can get too confusing?
85                          */
86                         if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action)) 
87                         {
88                                 if (saction->flag & SACTION_POSEMARKERS_SHOW)
89                                         return &saction->action->markers;
90                         }
91                 }
92         }
93         
94         /* default to using the scene's markers */
95         return &scene->markers;
96 }
97
98 /* ............. */
99
100 /* public API for getting markers from context */
101 ListBase *ED_context_get_markers(const bContext *C)
102 {
103         return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
104 }
105
106 /* public API for getting markers from "animation" context */
107 ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
108 {
109         if (ac)
110                 return context_get_markers(ac->scene, ac->sa);
111         else
112                 return NULL;
113 }
114
115 /* --------------------------------- */
116
117 /* Apply some transformation to markers after the fact 
118  * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything
119  * < scene: current scene (for getting current frame)
120  * < mode: (TfmMode) transform mode that this transform is for
121  * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale)
122  * < side: (B/L/R) for 'extend' functionality, which side of current frame to use
123  */
124 int ED_markers_post_apply_transform (ListBase *markers, Scene *scene, int mode, float value, char side)
125 {
126         TimeMarker *marker;
127         float cfra = (float)CFRA;
128         int changed = 0;
129         
130         /* sanity check */
131         if (markers == NULL)
132                 return changed;
133         
134         /* affect selected markers - it's unlikely that we will want to affect all in this way? */
135         for (marker = markers->first; marker; marker = marker->next) {
136                 if (marker->flag & SELECT) {
137                         switch (mode) {
138                                 case TFM_TIME_TRANSLATE:
139                                 case TFM_TIME_EXTEND:
140                                 {
141                                         /* apply delta if marker is on the right side of the current frame */
142                                         if ((side=='B') ||
143                                                 (side=='L' && marker->frame < cfra) || 
144                                             (side=='R' && marker->frame >= cfra))
145                                         {
146                                                 marker->frame += (int)floorf(value + 0.5f);
147                                                 changed++;
148                                         }
149                                 }
150                                         break;
151                                         
152                                 case TFM_TIME_SCALE:
153                                 {       
154                                         /* rescale the distance between the marker and the current frame */
155                                         marker->frame= cfra + (int)floorf(((float)(marker->frame - cfra) * value) + 0.5f);
156                                         changed++;
157                                 }
158                                         break;
159                         }
160                 }
161         }
162         
163         return changed;
164 }
165
166 /* --------------------------------- */
167
168 /* Get the marker that is closest to this point */
169 /* XXX for select, the min_dist should be small */
170 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x) 
171 {
172         TimeMarker *marker, *nearest=NULL;
173         float dist, min_dist= 1000000;
174         
175         if (markers) {
176                 for (marker= markers->first; marker; marker= marker->next) {
177                         dist = ABS((float)marker->frame - x);
178                         
179                         if (dist < min_dist) {
180                                 min_dist= dist;
181                                 nearest= marker;
182                         }
183                 }
184         }
185         
186         return nearest;
187 }
188
189 /* Return the time of the marker that occurs on a frame closest to the given time */
190 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
191 {
192         TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
193         return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
194 }
195
196
197 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
198 {
199         TimeMarker *marker;
200         float min, max;
201         int selcount = 0;
202         
203         /* sanity check */
204         //printf("markers = %p -  %p, %p \n", markers, markers->first, markers->last);
205         if (markers == NULL) {
206                 *first = 0.0f;
207                 *last = 0.0f;
208                 return;
209         }
210         
211         if (markers->first && markers->last) {
212                 TimeMarker *fm= markers->first;
213                 TimeMarker *lm= markers->last;
214                 
215                 min= (float)fm->frame;
216                 max= (float)lm->frame;
217         }
218         else {
219                 *first = 0.0f;
220                 *last = 0.0f;
221                 return;
222         }
223         
224         /* count how many markers are usable - see later */
225         if (sel) {
226                 for (marker= markers->first; marker; marker= marker->next) {
227                         if (marker->flag & SELECT)
228                                 selcount++;
229                 }
230         }
231         else
232                 selcount= BLI_countlist(markers);
233         
234         /* if only selected are to be considered, only consider the selected ones
235          * (optimisation for not searching list) 
236          */
237         if (selcount > 1) {
238                 for (marker= markers->first; marker; marker= marker->next) {
239                         if (sel) {
240                                 if (marker->flag & SELECT) {
241                                         if (marker->frame < min)
242                                                 min= (float)marker->frame;
243                                         if (marker->frame > max)
244                                                 max= (float)marker->frame;
245                                 }
246                         }
247                         else {
248                                 if (marker->frame < min)
249                                         min= (float)marker->frame;
250                                 if (marker->frame > max)
251                                         max= (float)marker->frame;
252                         }       
253                 }
254         }
255         
256         /* set the min/max values */
257         *first= min;
258         *last= max;
259 }
260
261 /* --------------------------------- */
262
263 /* Adds a marker to list of cfra elems */
264 static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
265 {
266         CfraElem *ce, *cen;
267         
268         /* should this one only be considered if it is selected? */
269         if ((only_sel) && ((marker->flag & SELECT)==0))
270                 return;
271         
272         /* insertion sort - try to find a previous cfra elem */
273         for (ce= lb->first; ce; ce= ce->next) {
274                 if (ce->cfra == marker->frame) {
275                         /* do because of double keys */
276                         if (marker->flag & SELECT) 
277                                 ce->sel= marker->flag;
278                         return;
279                 }
280                 else if (ce->cfra > marker->frame) break;
281         }       
282         
283         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
284         if (ce) BLI_insertlinkbefore(lb, ce, cen);
285         else BLI_addtail(lb, cen);
286
287         cen->cfra= marker->frame;
288         cen->sel= marker->flag;
289 }
290
291 /* This function makes a list of all the markers. The only_sel
292  * argument is used to specify whether only the selected markers
293  * are added.
294  */
295 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
296 {
297         TimeMarker *marker;
298         
299         if (markers == NULL)
300                 return;
301         
302         for (marker= markers->first; marker; marker= marker->next)
303                 add_marker_to_cfra_elem(lb, marker, only_sel);
304 }
305
306 /* --------------------------------- */
307
308 /* Get the first selected marker */
309 TimeMarker *ED_markers_get_first_selected(ListBase *markers)
310 {
311         TimeMarker *marker;
312         
313         if (markers) {
314                 for (marker = markers->first; marker; marker = marker->next) {
315                         if (marker->flag & SELECT)
316                                 return marker;
317                 }
318         }
319         
320         return NULL;
321 }
322
323 /* --------------------------------- */
324
325 /* Print debugging prints of list of markers 
326  * 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!
327  */
328 void debug_markers_print_list(ListBase *markers)
329 {
330         TimeMarker *marker;
331         
332         if (markers == NULL) {
333                 printf("No markers list to print debug for\n");
334                 return;
335         }
336         
337         printf("List of markers follows: -----\n");
338         
339         for (marker = markers->first; marker; marker = marker->next) {
340                 printf("\t'%s' on %d at %p with %u\n", marker->name, marker->frame, (void *)marker, marker->flag);
341         }
342         
343         printf("End of list ------------------\n");
344 }
345
346 /* ************* Marker Drawing ************ */
347
348 /* function to draw markers */
349 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
350 {
351         float xpos, ypixels, xscale, yscale;
352         int icon_id= 0;
353         
354         xpos = marker->frame;
355         
356         /* no time correction for framelen! space is drawn with old values */
357         ypixels= v2d->mask.ymax-v2d->mask.ymin;
358         UI_view2d_getscale(v2d, &xscale, &yscale);
359         
360         glScalef(1.0f/xscale, 1.0f, 1.0f);
361         
362         glEnable(GL_BLEND);
363         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                      
364         
365         /* vertical line - dotted */
366 #ifdef DURIAN_CAMERA_SWITCH
367         if ((marker->camera) || (flag & DRAW_MARKERS_LINES))
368 #else
369         if (flag & DRAW_MARKERS_LINES)
370 #endif
371         {
372                 setlinestyle(3);
373                 
374                 if (marker->flag & SELECT)
375                         glColor4ub(255, 255, 255, 96);
376                 else
377                         glColor4ub(0, 0, 0, 96);
378                 
379                 glBegin(GL_LINES);
380                         glVertex2f((xpos*xscale)+0.5f, 12.0f);
381                         glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
382                 glEnd();
383                 
384                 setlinestyle(0);
385         }
386         
387         /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
388         if (flag & DRAW_MARKERS_LOCAL) {
389                 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : 
390                 (marker->flag & SELECT) ? ICON_PMARKER_SEL : 
391                 ICON_PMARKER;
392         }
393         else {
394                 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT : 
395                 ICON_MARKER;
396         }
397         
398         UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
399         
400         glDisable(GL_BLEND);
401         
402         /* and the marker name too, shifted slightly to the top-right */
403         if (marker->name && marker->name[0]) {
404                 float x, y;
405                 
406                 if (marker->flag & SELECT) {
407                         UI_ThemeColor(TH_TEXT_HI);
408                         x= xpos*xscale + 4.0f;
409                         y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
410                 }
411                 else {
412                         UI_ThemeColor(TH_TEXT);
413                         if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
414                                 x= xpos*xscale + 4.0f;
415                                 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
416                         }
417                         else {
418                                 x= xpos*xscale + 4.0f;
419                                 y= 17.0f;
420                         }
421                 }
422
423 #ifdef DURIAN_CAMERA_SWITCH
424                 if(marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
425                         float col[4];
426                         glGetFloatv(GL_CURRENT_COLOR, col);
427                         col[3]= 0.4;
428                         glColor4fv(col);
429                 }
430 #endif
431
432                 UI_DrawString(x, y, marker->name);
433         }
434         
435         glScalef(xscale, 1.0f, 1.0f);
436 }
437
438 /* Draw Scene-Markers in time window */
439 void draw_markers_time(const bContext *C, int flag)
440 {
441         ListBase *markers= ED_context_get_markers(C);
442         View2D *v2d= UI_view2d_fromcontext(C);
443         TimeMarker *marker;
444         
445         if (markers == NULL)
446                 return;
447         
448         /* unselected markers are drawn at the first time */
449         for (marker= markers->first; marker; marker= marker->next) {
450                 if ((marker->flag & SELECT) == 0) 
451                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
452         }
453         
454         /* selected markers are drawn later */
455         for (marker= markers->first; marker; marker= marker->next) {
456                 if (marker->flag & SELECT) 
457                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
458         }
459 }
460
461 /* ************************ Marker Wrappers API ********************* */
462 /* These wrappers allow marker operators to function within the confines 
463  * of standard animation editors, such that they can coexist with the 
464  * primary operations of those editors.
465  */
466
467 /* ------------------------ */
468
469 /* special poll() which checks if there are selected markers first */
470 static int ed_markers_poll_selected_markers(bContext *C)
471 {
472         ListBase *markers = ED_context_get_markers(C);
473         
474         /* first things first: markers can only exist in timeline views */
475         if (ED_operator_animview_active(C) == 0)
476                 return 0;
477                 
478         /* check if some marker is selected */
479         return ED_markers_get_first_selected(markers) != NULL;
480 }
481
482 /* special poll() which checks if there are any markers at all first */
483 static int ed_markers_poll_markers_exist(bContext *C)
484 {
485         ListBase *markers = ED_context_get_markers(C);
486         
487         /* first things first: markers can only exist in timeline views */
488         if (ED_operator_animview_active(C) == 0)
489                 return 0;
490                 
491         /* list of markers must exist, as well as some markers in it! */
492         return (markers && markers->first);
493 }
494  
495 /* ------------------------ */ 
496
497 /* Second-tier invoke() callback that performs context validation before running the  
498  * "custom"/third-tier invoke() callback supplied as the last arg (which would normally
499  * be the operator's invoke() callback elsewhere)
500  *
501  * < invoke_func: (fn(bContext*, wmOperator*, wmEvent*)=int) "standard" invoke function 
502  *                      that operator would otherwise have used. If NULL, the operator's standard
503  *                      exec() callback will be called instead in the appropriate places.
504  */
505 static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt, 
506                 int (*invoke_func)(bContext*,wmOperator*,wmEvent*))
507 {
508         ScrArea *sa = CTX_wm_area(C);
509         int retval = OPERATOR_PASS_THROUGH;
510         
511         /* removed check for Y coord of event, keymap has bounbox now */
512         
513         /* allow operator to run now */
514         if (invoke_func)
515                 retval = invoke_func(C, op, evt);
516         else if (op->type->exec)
517                 retval = op->type->exec(C, op);
518         else
519                 BKE_report(op->reports, RPT_ERROR, "Programming error: operator doesn't actually have code to do anything!");
520                 
521         /* return status modifications - for now, make this spacetype dependent as above */
522         if (sa->spacetype != SPACE_TIME) {
523                 /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
524                 if (retval != OPERATOR_FINISHED)
525                         retval |= OPERATOR_PASS_THROUGH;
526         }
527         
528         return retval;
529 }
530
531 /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata
532  * for operators which don't need any special invoke calls. Any operators with special invoke calls
533  * though will need to implement their own wrapper which calls the second-tier callback themselves
534  * (passing through the custom invoke function they use)
535  */
536 static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
537 {
538         return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
539 }
540
541 /* ************************** add markers *************************** */
542
543 /* add TimeMarker at curent frame */
544 static int ed_marker_add(bContext *C, wmOperator *UNUSED(op))
545 {
546         ListBase *markers= ED_context_get_markers(C);
547         TimeMarker *marker;
548         int frame= CTX_data_scene(C)->r.cfra;
549         
550         if (markers == NULL)
551                 return OPERATOR_CANCELLED;
552         
553         /* two markers can't be at the same place */
554         for (marker= markers->first; marker; marker= marker->next) {
555                 if (marker->frame == frame) 
556                         return OPERATOR_CANCELLED;
557         }
558         
559         /* deselect all */
560         for (marker= markers->first; marker; marker= marker->next)
561                 marker->flag &= ~SELECT;
562         
563         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
564         marker->flag= SELECT;
565         marker->frame= frame;
566         BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only
567         BLI_addtail(markers, marker);
568         
569         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
570         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
571         
572         return OPERATOR_FINISHED;
573 }
574
575 static void MARKER_OT_add(wmOperatorType *ot)
576 {
577         /* identifiers */
578         ot->name= "Add Time Marker";
579         ot->description= "Add a new time marker";
580         ot->idname= "MARKER_OT_add";
581         
582         /* api callbacks */
583         ot->exec= ed_marker_add;
584         ot->invoke = ed_markers_opwrap_invoke;
585         ot->poll= ED_operator_animview_active;
586         
587         /* flags */
588         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
589 }
590
591 /* ************************** transform markers *************************** */
592
593
594 /* operator state vars used:  
595         frs: delta movement
596
597 functions:
598
599         init()   check selection, add customdata with old values and some lookups
600
601         apply()  do the actual movement
602
603         exit()  cleanup, send notifier
604
605         cancel() to escape from modal
606
607 callbacks:
608
609         exec()  calls init, apply, exit 
610
611         invoke() calls init, adds modal handler
612
613         modal() accept modal events while doing it, ends with apply and exit, or cancel
614
615 */
616
617 typedef struct MarkerMove {
618         SpaceLink *slink;
619         ListBase *markers;
620         int event_type;         /* store invoke-event, to verify */
621         int *oldframe, evtx, firstx;
622         NumInput num;
623 } MarkerMove;
624
625 /* copy selection to temp buffer */
626 /* return 0 if not OK */
627 static int ed_marker_move_init(bContext *C, wmOperator *op)
628 {
629         ListBase *markers= ED_context_get_markers(C);
630         MarkerMove *mm;
631         TimeMarker *marker;
632         int totmark=0;
633         int a;
634
635         if(markers == NULL) return 0;
636         
637         for (marker= markers->first; marker; marker= marker->next)
638                 if (marker->flag & SELECT) totmark++;
639         
640         if (totmark==0) return 0;
641         
642         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
643         mm->slink= CTX_wm_space_data(C);
644         mm->markers= markers;
645         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
646
647         initNumInput(&mm->num);
648         mm->num.idx_max = 0; /* one axis */
649         mm->num.flag |= NUM_NO_FRACTION;
650         mm->num.increment = 1.0f;
651         
652         for (a=0, marker= markers->first; marker; marker= marker->next) {
653                 if (marker->flag & SELECT) {
654                         mm->oldframe[a]= marker->frame;
655                         a++;
656                 }
657         }
658         
659         return 1;
660 }
661
662 /* free stuff */
663 static void ed_marker_move_exit(bContext *C, wmOperator *op)
664 {
665         MarkerMove *mm= op->customdata;
666         
667         /* free data */
668         MEM_freeN(mm->oldframe);
669         MEM_freeN(op->customdata);
670         op->customdata= NULL;
671         
672         /* clear custom header prints */
673         ED_area_headerprint(CTX_wm_area(C), NULL);
674 }
675
676 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
677 {
678         if(ed_marker_move_init(C, op)) {
679                 MarkerMove *mm= op->customdata;
680                 
681                 mm->evtx= evt->x;
682                 mm->firstx= evt->x;
683                 mm->event_type= evt->type;
684                 
685                 /* add temp handler */
686                 WM_event_add_modal_handler(C, op);
687                 
688                 /* reset frs delta */
689                 RNA_int_set(op->ptr, "frames", 0);
690                 
691                 return OPERATOR_RUNNING_MODAL;
692         }
693         
694         return OPERATOR_CANCELLED;
695 }
696
697 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
698 {
699         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
700 }
701
702 /* note, init has to be called succesfully */
703 static void ed_marker_move_apply(wmOperator *op)
704 {
705         MarkerMove *mm= op->customdata;
706         TimeMarker *marker;
707         int a, offs;
708         
709         offs= RNA_int_get(op->ptr, "frames");
710         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
711                 if (marker->flag & SELECT) {
712                         marker->frame= mm->oldframe[a] + offs;
713                         a++;
714                 }
715         }
716 }
717
718 /* only for modal */
719 static int ed_marker_move_cancel(bContext *C, wmOperator *op)
720 {
721         RNA_int_set(op->ptr, "frames", 0);
722         ed_marker_move_apply(op);
723         ed_marker_move_exit(C, op);     
724         
725         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
726         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
727
728         return OPERATOR_CANCELLED;
729 }
730
731
732
733 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
734 {
735         Scene *scene= CTX_data_scene(C);
736         MarkerMove *mm= op->customdata;
737         View2D *v2d= UI_view2d_fromcontext(C);
738         TimeMarker *marker, *selmarker=NULL;
739         float dx, fac;
740         char str[256];
741                 
742         switch(evt->type) {
743                 case ESCKEY:
744                         ed_marker_move_cancel(C, op);
745                         return OPERATOR_CANCELLED;
746                 
747                 case RIGHTMOUSE:
748                         /* press = user manually demands transform to be cancelled */
749                         if (evt->val == KM_PRESS) {
750                                 ed_marker_move_cancel(C, op);
751                                 return OPERATOR_CANCELLED;
752                         }
753                         /* else continue; <--- see if release event should be caught for tweak-end */
754                 
755                 case RETKEY:
756                 case PADENTER:
757                 case LEFTMOUSE:
758                 case MIDDLEMOUSE:
759                         if (WM_modal_tweak_exit(evt, mm->event_type)) {
760                                 ed_marker_move_exit(C, op);
761                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
762                                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
763                                 return OPERATOR_FINISHED;
764                         }
765                         break;
766                 case MOUSEMOVE:
767                         if (hasNumInput(&mm->num))
768                                 break;
769                         
770                         dx= v2d->mask.xmax-v2d->mask.xmin;
771                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
772                         
773                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
774                                 int a, offs, totmark=0;
775                                 
776                                 mm->evtx= evt->x;
777                                 
778                                 fac= ((float)(evt->x - mm->firstx)*dx);
779                                 
780                                 if (mm->slink->spacetype == SPACE_TIME) 
781                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
782                                 else
783                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
784                                 
785                                 offs= (int)fac;
786                                 RNA_int_set(op->ptr, "frames", offs);
787                                 ed_marker_move_apply(op);
788                                 
789                                 /* cruft below is for header print */
790                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
791                                         if (marker->flag & SELECT) {
792                                                 selmarker= marker;
793                                                 a++; totmark++;
794                                         }
795                                 }
796                                 
797                                 if (totmark==1) {       
798                                         /* we print current marker value */
799                                         if (mm->slink->spacetype == SPACE_TIME) {
800                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
801                                                 if (stime->flag & TIME_DRAWFRAMES) 
802                                                         BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
803                                                 else 
804                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
805                                         }
806                                         else if (mm->slink->spacetype == SPACE_ACTION) {
807                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
808                                                 if (saction->flag & SACTION_DRAWTIME)
809                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
810                                                 else
811                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
812                                         }
813                                         else {
814                                                 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
815                                         }
816                                 }
817                                 else {
818                                         /* we only print the offset */
819                                         if (mm->slink->spacetype == SPACE_TIME) { 
820                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
821                                                 if (stime->flag & TIME_DRAWFRAMES) 
822                                                         BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
823                                                 else 
824                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
825                                         }
826                                         else if (mm->slink->spacetype == SPACE_ACTION) {
827                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
828                                                 if (saction->flag & SACTION_DRAWTIME)
829                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
830                                                 else
831                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
832                                         }
833                                         else {
834                                                 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
835                                         }
836                                 }
837                                 
838                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
839                                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
840                                 ED_area_headerprint(CTX_wm_area(C), str);
841                         }
842         }
843
844         if (evt->val==KM_PRESS) {
845                 float vec[3];
846                 char str_tx[256];
847                 
848                 if (handleNumInput(&mm->num, evt))
849                 {
850                         applyNumInput(&mm->num, vec);
851                         outputNumInput(&mm->num, str_tx);
852                         
853                         RNA_int_set(op->ptr, "frames", vec[0]);
854                         ed_marker_move_apply(op);
855                         // ed_marker_header_update(C, op, str, (int)vec[0]);
856                         // strcat(str, str_tx);
857                         BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
858                         ED_area_headerprint(CTX_wm_area(C), str);
859                         
860                         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
861                         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
862                 }
863         }
864
865         return OPERATOR_RUNNING_MODAL;
866 }
867
868 static int ed_marker_move_exec(bContext *C, wmOperator *op)
869 {
870         if(ed_marker_move_init(C, op)) {
871                 ed_marker_move_apply(op);
872                 ed_marker_move_exit(C, op);
873                 return OPERATOR_FINISHED;
874         }
875         return OPERATOR_PASS_THROUGH;
876 }
877
878 static void MARKER_OT_move(wmOperatorType *ot)
879 {
880         /* identifiers */
881         ot->name= "Move Time Marker";
882         ot->description= "Move selected time marker(s)";
883         ot->idname= "MARKER_OT_move";
884         
885         /* api callbacks */
886         ot->exec= ed_marker_move_exec;
887         ot->invoke= ed_marker_move_invoke_wrapper;
888         ot->modal= ed_marker_move_modal;
889         ot->poll= ed_markers_poll_selected_markers;
890         ot->cancel= ed_marker_move_cancel;
891         
892         /* flags */
893         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
894         
895         /* rna storage */
896         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
897 }
898
899 /* ************************** duplicate markers *************************** */
900
901 /* operator state vars used:  
902         frs: delta movement
903
904 functions:
905
906         apply()  do the actual duplicate
907
908 callbacks:
909
910         exec()  calls apply, move_exec
911
912         invoke() calls apply, move_invoke
913
914         modal() uses move_modal
915
916 */
917
918
919 /* duplicate selected TimeMarkers */
920 static void ed_marker_duplicate_apply(bContext *C)
921 {
922         ListBase *markers= ED_context_get_markers(C);
923         TimeMarker *marker, *newmarker;
924         
925         if (markers == NULL) 
926                 return;
927
928         /* go through the list of markers, duplicate selected markers and add duplicated copies
929          * to the begining of the list (unselect original markers) 
930          */
931         for (marker= markers->first; marker; marker= marker->next) {
932                 if (marker->flag & SELECT) {
933                         /* unselect selected marker */
934                         marker->flag &= ~SELECT;
935                         
936                         /* create and set up new marker */
937                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
938                         newmarker->flag= SELECT;
939                         newmarker->frame= marker->frame;
940                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
941                         
942 #ifdef DURIAN_CAMERA_SWITCH
943                         newmarker->camera= marker->camera;
944 #endif
945
946                         /* new marker is added to the begining of list */
947                         // FIXME: bad ordering!
948                         BLI_addhead(markers, newmarker);
949                 }
950         }
951 }
952
953 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
954 {
955         ed_marker_duplicate_apply(C);
956         ed_marker_move_exec(C, op);     /* assumes frs delta set */
957         
958         return OPERATOR_FINISHED;
959         
960 }
961
962 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
963 {
964         ed_marker_duplicate_apply(C);
965         return ed_marker_move_invoke(C, op, evt);
966 }
967
968 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
969 {
970         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
971 }
972
973 static void MARKER_OT_duplicate(wmOperatorType *ot)
974 {
975         /* identifiers */
976         ot->name= "Duplicate Time Marker";
977         ot->description= "Duplicate selected time marker(s)";
978         ot->idname= "MARKER_OT_duplicate";
979         
980         /* api callbacks */
981         ot->exec= ed_marker_duplicate_exec;
982         ot->invoke= ed_marker_duplicate_invoke_wrapper;
983         ot->modal= ed_marker_move_modal;
984         ot->poll= ed_markers_poll_selected_markers;
985         ot->cancel= ed_marker_move_cancel;
986         
987         /* flags */
988         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
989         
990         /* rna storage */
991         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
992 }
993
994 /* ************************** selection ************************************/
995
996 /* select/deselect TimeMarker at current frame */
997 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
998 {
999         TimeMarker *marker;
1000         int select=0;
1001         
1002         for (marker= markers->first; marker; marker= marker->next) {
1003                 /* if Shift is not set, then deselect Markers */
1004                 if (!shift) marker->flag &= ~SELECT;
1005                 
1006                 /* this way a not-shift select will allways give 1 selected marker */
1007                 if ((marker->frame == frame) && (!select)) {
1008                         if (marker->flag & SELECT) 
1009                                 marker->flag &= ~SELECT;
1010                         else
1011                                 marker->flag |= SELECT;
1012                         select = 1;
1013                 }
1014         }
1015 }
1016
1017 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1018 {
1019         ListBase *markers= ED_context_get_markers(C);
1020         View2D *v2d= UI_view2d_fromcontext(C);
1021         float viewx;
1022         int x, y, cfra;
1023         
1024         if (markers == NULL)
1025                 return OPERATOR_PASS_THROUGH;
1026
1027         x= evt->x - CTX_wm_region(C)->winrct.xmin;
1028         y= evt->y - CTX_wm_region(C)->winrct.ymin;
1029         
1030         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
1031         
1032         cfra= ED_markers_find_nearest_marker_time(markers, viewx);
1033         
1034         if (extend)
1035                 select_timeline_marker_frame(markers, cfra, 1);
1036         else
1037                 select_timeline_marker_frame(markers, cfra, 0);
1038         
1039 #ifdef DURIAN_CAMERA_SWITCH
1040
1041         if (camera) {
1042                 Scene *scene= CTX_data_scene(C);
1043                 Base *base;
1044                 TimeMarker *marker;
1045                 int sel= 0;
1046                 
1047                 if (!extend)
1048                         scene_deselect_all(scene);
1049                 
1050                 for (marker= markers->first; marker; marker= marker->next) {
1051                         if(marker->frame==cfra) {
1052                                 sel= (marker->flag & SELECT);
1053                                 break;
1054                         }
1055                 }
1056                 
1057                 for (marker= markers->first; marker; marker= marker->next) {
1058                         if (marker->camera) {
1059                                 if (marker->frame==cfra) {
1060                                         base= object_in_scene(marker->camera, scene);
1061                                         if (base) {
1062                                                 ED_base_object_select(base, sel);
1063                                                 if(sel)
1064                                                         ED_base_object_activate(C, base);
1065                                         }
1066                                 }
1067                         }
1068                 }
1069                 
1070                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1071         }
1072 #else
1073         (void)camera;
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 #else
1499         (void)kmi;
1500 #endif
1501         
1502         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1503         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1504         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1505         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1506         WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1507         
1508         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1509 #ifdef DURIAN_CAMERA_SWITCH
1510         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1511 #endif
1512 }
1513
1514 /* to be called from animation editor keymaps, see note below */
1515 void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
1516 {
1517         /* duplicate of some marker-hotkeys but without the bounds checking
1518          * since these are handy to be able to do unrestricted and won't conflict
1519          * with primary function hotkeys (Usability tweak [#27469])
1520          */
1521         WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1522         WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1523 }