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