0ae06e71b66885c5d2f3653a9aeab9312143851a
[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                                 if (saction->flag & SACTION_POSEMARKERS_SHOW) {
88                                         return &saction->action->markers;
89                                 }
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          * (optimization 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 debugging!
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 = BLI_rcti_size_y(&v2d->mask);
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;
443         TimeMarker *marker;
444         Scene *scene;
445
446         if (markers == NULL)
447                 return;
448
449         scene = CTX_data_scene(C);
450         v2d = UI_view2d_fromcontext(C);
451
452         /* unselected markers are drawn at the first time */
453         for (marker = markers->first; marker; marker = marker->next) {
454                 if ((marker->flag & SELECT) == 0) {
455                         draw_marker(v2d, marker, scene->r.cfra, flag);
456                 }
457         }
458         
459         /* selected markers are drawn later */
460         for (marker = markers->first; marker; marker = marker->next) {
461                 if (marker->flag & SELECT) {
462                         draw_marker(v2d, marker, scene->r.cfra, flag);
463                 }
464         }
465 }
466
467 /* ************************ Marker Wrappers API ********************* */
468 /* These wrappers allow marker operators to function within the confines 
469  * of standard animation editors, such that they can coexist with the 
470  * primary operations of those editors.
471  */
472
473 /* ------------------------ */
474
475 /* special poll() which checks if there are selected markers first */
476 static int ed_markers_poll_selected_markers(bContext *C)
477 {
478         ListBase *markers = ED_context_get_markers(C);
479         
480         /* first things first: markers can only exist in timeline views */
481         if (ED_operator_animview_active(C) == 0)
482                 return 0;
483                 
484         /* check if some marker is selected */
485         return ED_markers_get_first_selected(markers) != NULL;
486 }
487
488 /* special poll() which checks if there are any markers at all first */
489 static int ed_markers_poll_markers_exist(bContext *C)
490 {
491         ListBase *markers = ED_context_get_markers(C);
492         
493         /* first things first: markers can only exist in timeline views */
494         if (ED_operator_animview_active(C) == 0)
495                 return 0;
496                 
497         /* list of markers must exist, as well as some markers in it! */
498         return (markers && markers->first);
499 }
500  
501 /* ------------------------ */ 
502
503 /* Second-tier invoke() callback that performs context validation before running the  
504  * "custom"/third-tier invoke() callback supplied as the last arg (which would normally
505  * be the operator's invoke() callback elsewhere)
506  *
507  * < invoke_func: (fn(bContext *, wmOperator *, wmEvent *)=int) "standard" invoke function
508  *                      that operator would otherwise have used. If NULL, the operator's standard
509  *                      exec() callback will be called instead in the appropriate places.
510  */
511 static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt, 
512                                            int (*invoke_func)(bContext *, wmOperator *, wmEvent *))
513 {
514         ScrArea *sa = CTX_wm_area(C);
515         int retval = OPERATOR_PASS_THROUGH;
516         
517         /* removed check for Y coord of event, keymap has bounbox now */
518         
519         /* allow operator to run now */
520         if (invoke_func)
521                 retval = invoke_func(C, op, evt);
522         else if (op->type->exec)
523                 retval = op->type->exec(C, op);
524         else
525                 BKE_report(op->reports, RPT_ERROR, "Programming error: operator doesn't actually have code to do anything!");
526                 
527         /* return status modifications - for now, make this spacetype dependent as above */
528         if (sa->spacetype != SPACE_TIME) {
529                 /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
530                 if (retval != OPERATOR_FINISHED)
531                         retval |= OPERATOR_PASS_THROUGH;
532         }
533         
534         return retval;
535 }
536
537 /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata
538  * for operators which don't need any special invoke calls. Any operators with special invoke calls
539  * though will need to implement their own wrapper which calls the second-tier callback themselves
540  * (passing through the custom invoke function they use)
541  */
542 static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
543 {
544         return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
545 }
546
547 /* ************************** add markers *************************** */
548
549 /* add TimeMarker at curent frame */
550 static int ed_marker_add(bContext *C, wmOperator *UNUSED(op))
551 {
552         ListBase *markers = ED_context_get_markers(C);
553         TimeMarker *marker;
554         int frame = CTX_data_scene(C)->r.cfra;
555         
556         if (markers == NULL)
557                 return OPERATOR_CANCELLED;
558         
559         /* prefer not having 2 markers at the same place,
560          * though the user can move them to overlap once added */
561         for (marker = markers->first; marker; marker = marker->next) {
562                 if (marker->frame == frame) 
563                         return OPERATOR_CANCELLED;
564         }
565         
566         /* deselect all */
567         for (marker = markers->first; marker; marker = marker->next)
568                 marker->flag &= ~SELECT;
569         
570         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
571         marker->flag = SELECT;
572         marker->frame = frame;
573         BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only
574         BLI_addtail(markers, marker);
575         
576         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
577         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
578         
579         return OPERATOR_FINISHED;
580 }
581
582 static void MARKER_OT_add(wmOperatorType *ot)
583 {
584         /* identifiers */
585         ot->name = "Add Time Marker";
586         ot->description = "Add a new time marker";
587         ot->idname = "MARKER_OT_add";
588         
589         /* api callbacks */
590         ot->exec = ed_marker_add;
591         ot->invoke = ed_markers_opwrap_invoke;
592         ot->poll = ED_operator_animview_active;
593         
594         /* flags */
595         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
596 }
597
598 /* ************************** transform markers *************************** */
599
600 /* operator state vars used:  
601  *     frs: delta movement
602  * 
603  * functions:
604  * 
605  *     init()   check selection, add customdata with old values and some lookups
606  * 
607  *     apply()  do the actual movement
608  * 
609  *     exit()    cleanup, send notifier
610  * 
611  *     cancel() to escape from modal
612  * 
613  * callbacks:
614  * 
615  *     exec()    calls init, apply, exit 
616  * 
617  *     invoke() calls init, adds modal handler
618  * 
619  *     modal()    accept modal events while doing it, ends with apply and exit, or cancel
620  * 
621  */
622
623 typedef struct MarkerMove {
624         SpaceLink *slink;
625         ListBase *markers;
626         int event_type;     /* store invoke-event, to verify */
627         int *oldframe, evtx, firstx;
628         NumInput num;
629 } MarkerMove;
630
631 /* copy selection to temp buffer */
632 /* return 0 if not OK */
633 static int ed_marker_move_init(bContext *C, wmOperator *op)
634 {
635         ListBase *markers = ED_context_get_markers(C);
636         MarkerMove *mm;
637         TimeMarker *marker;
638         int totmark = 0;
639         int a;
640
641         if (markers == NULL) return 0;
642         
643         for (marker = markers->first; marker; marker = marker->next)
644                 if (marker->flag & SELECT) totmark++;
645         
646         if (totmark == 0) return 0;
647         
648         op->customdata = mm = MEM_callocN(sizeof(MarkerMove), "Markermove");
649         mm->slink = CTX_wm_space_data(C);
650         mm->markers = markers;
651         mm->oldframe = MEM_callocN(totmark * sizeof(int), "MarkerMove oldframe");
652
653         initNumInput(&mm->num);
654         mm->num.idx_max = 0; /* one axis */
655         mm->num.flag |= NUM_NO_FRACTION;
656         mm->num.increment = 1.0f;
657         
658         for (a = 0, marker = markers->first; marker; marker = marker->next) {
659                 if (marker->flag & SELECT) {
660                         mm->oldframe[a] = marker->frame;
661                         a++;
662                 }
663         }
664         
665         return 1;
666 }
667
668 /* free stuff */
669 static void ed_marker_move_exit(bContext *C, wmOperator *op)
670 {
671         MarkerMove *mm = op->customdata;
672         
673         /* free data */
674         MEM_freeN(mm->oldframe);
675         MEM_freeN(op->customdata);
676         op->customdata = NULL;
677         
678         /* clear custom header prints */
679         ED_area_headerprint(CTX_wm_area(C), NULL);
680 }
681
682 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
683 {
684         if (ed_marker_move_init(C, op)) {
685                 MarkerMove *mm = op->customdata;
686                 
687                 mm->evtx = evt->x;
688                 mm->firstx = evt->x;
689                 mm->event_type = evt->type;
690                 
691                 /* add temp handler */
692                 WM_event_add_modal_handler(C, op);
693                 
694                 /* reset frs delta */
695                 RNA_int_set(op->ptr, "frames", 0);
696                 
697                 return OPERATOR_RUNNING_MODAL;
698         }
699         
700         return OPERATOR_CANCELLED;
701 }
702
703 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
704 {
705         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
706 }
707
708 /* note, init has to be called succesfully */
709 static void ed_marker_move_apply(wmOperator *op)
710 {
711         MarkerMove *mm = op->customdata;
712         TimeMarker *marker;
713         int a, offs;
714         
715         offs = RNA_int_get(op->ptr, "frames");
716         for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
717                 if (marker->flag & SELECT) {
718                         marker->frame = mm->oldframe[a] + offs;
719                         a++;
720                 }
721         }
722 }
723
724 /* only for modal */
725 static int ed_marker_move_cancel(bContext *C, wmOperator *op)
726 {
727         RNA_int_set(op->ptr, "frames", 0);
728         ed_marker_move_apply(op);
729         ed_marker_move_exit(C, op);
730         
731         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
732         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
733
734         return OPERATOR_CANCELLED;
735 }
736
737
738
739 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
740 {
741         Scene *scene = CTX_data_scene(C);
742         MarkerMove *mm = op->customdata;
743         View2D *v2d = UI_view2d_fromcontext(C);
744         TimeMarker *marker, *selmarker = NULL;
745         float dx, fac;
746         char str[256];
747                 
748         switch (evt->type) {
749                 case ESCKEY:
750                         ed_marker_move_cancel(C, op);
751                         return OPERATOR_CANCELLED;
752                 
753                 case RIGHTMOUSE:
754                         /* press = user manually demands transform to be canceled */
755                         if (evt->val == KM_PRESS) {
756                                 ed_marker_move_cancel(C, op);
757                                 return OPERATOR_CANCELLED;
758                         }
759                 /* else continue; <--- see if release event should be caught for tweak-end */
760                 
761                 case RETKEY:
762                 case PADENTER:
763                 case LEFTMOUSE:
764                 case MIDDLEMOUSE:
765                         if (WM_modal_tweak_exit(evt, mm->event_type)) {
766                                 ed_marker_move_exit(C, op);
767                                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
768                                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
769                                 return OPERATOR_FINISHED;
770                         }
771                         break;
772                 case MOUSEMOVE:
773                         if (hasNumInput(&mm->num))
774                                 break;
775                         
776                         dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
777                         
778                         if (evt->x != mm->evtx) {   /* XXX maybe init for first time */
779                                 int a, offs, totmark = 0;
780                                 
781                                 mm->evtx = evt->x;
782                                 
783                                 fac = ((float)(evt->x - mm->firstx) * dx);
784                                 
785                                 if (mm->slink->spacetype == SPACE_TIME) 
786                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
787                                 else
788                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
789                                 
790                                 offs = (int)fac;
791                                 RNA_int_set(op->ptr, "frames", offs);
792                                 ed_marker_move_apply(op);
793                                 
794                                 /* cruft below is for header print */
795                                 for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
796                                         if (marker->flag & SELECT) {
797                                                 selmarker = marker;
798                                                 a++; totmark++;
799                                         }
800                                 }
801                                 
802                                 if (totmark == 1) {
803                                         /* we print current marker value */
804                                         if (mm->slink->spacetype == SPACE_TIME) {
805                                                 SpaceTime *stime = (SpaceTime *)mm->slink;
806                                                 if (stime->flag & TIME_DRAWFRAMES) 
807                                                         BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
808                                                 else 
809                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
810                                         }
811                                         else if (mm->slink->spacetype == SPACE_ACTION) {
812                                                 SpaceAction *saction = (SpaceAction *)mm->slink;
813                                                 if (saction->flag & SACTION_DRAWTIME)
814                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
815                                                 else
816                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
817                                         }
818                                         else {
819                                                 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
820                                         }
821                                 }
822                                 else {
823                                         /* we only print the offset */
824                                         if (mm->slink->spacetype == SPACE_TIME) {
825                                                 SpaceTime *stime = (SpaceTime *)mm->slink;
826                                                 if (stime->flag & TIME_DRAWFRAMES) 
827                                                         BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
828                                                 else 
829                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
830                                         }
831                                         else if (mm->slink->spacetype == SPACE_ACTION) {
832                                                 SpaceAction *saction = (SpaceAction *)mm->slink;
833                                                 if (saction->flag & SACTION_DRAWTIME)
834                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
835                                                 else
836                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
837                                         }
838                                         else {
839                                                 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
840                                         }
841                                 }
842                                 
843                                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
844                                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
845                                 ED_area_headerprint(CTX_wm_area(C), str);
846                         }
847         }
848
849         if (evt->val == KM_PRESS) {
850                 float vec;
851                 char str_tx[NUM_STR_REP_LEN];
852                 
853                 if (handleNumInput(&mm->num, evt)) {
854                         applyNumInput(&mm->num, &vec);
855                         outputNumInput(&mm->num, str_tx);
856                         
857                         RNA_int_set(op->ptr, "frames", vec);
858                         ed_marker_move_apply(op);
859                         // ed_marker_header_update(C, op, str, (int)vec[0]);
860                         // strcat(str, str_tx);
861                         BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
862                         ED_area_headerprint(CTX_wm_area(C), str);
863                         
864                         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
865                         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
866                 }
867         }
868
869         return OPERATOR_RUNNING_MODAL;
870 }
871
872 static int ed_marker_move_exec(bContext *C, wmOperator *op)
873 {
874         if (ed_marker_move_init(C, op)) {
875                 ed_marker_move_apply(op);
876                 ed_marker_move_exit(C, op);
877                 return OPERATOR_FINISHED;
878         }
879         return OPERATOR_PASS_THROUGH;
880 }
881
882 static void MARKER_OT_move(wmOperatorType *ot)
883 {
884         /* identifiers */
885         ot->name = "Move Time Marker";
886         ot->description = "Move selected time marker(s)";
887         ot->idname = "MARKER_OT_move";
888         
889         /* api callbacks */
890         ot->exec = ed_marker_move_exec;
891         ot->invoke = ed_marker_move_invoke_wrapper;
892         ot->modal = ed_marker_move_modal;
893         ot->poll = ed_markers_poll_selected_markers;
894         ot->cancel = ed_marker_move_cancel;
895         
896         /* flags */
897         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
898         
899         /* rna storage */
900         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
901 }
902
903 /* ************************** duplicate markers *************************** */
904
905 /* operator state vars used:
906  *     frs: delta movement
907  *
908  * functions:
909  *
910  *     apply()  do the actual duplicate
911  *
912  * callbacks:
913  *
914  *     exec()    calls apply, move_exec
915  *
916  *     invoke() calls apply, move_invoke
917  *
918  *     modal()    uses move_modal
919  */
920
921 /* duplicate selected TimeMarkers */
922 static void ed_marker_duplicate_apply(bContext *C)
923 {
924         ListBase *markers = ED_context_get_markers(C);
925         TimeMarker *marker, *newmarker;
926         
927         if (markers == NULL) 
928                 return;
929
930         /* go through the list of markers, duplicate selected markers and add duplicated copies
931          * to the beginning of the list (unselect original markers)
932          */
933         for (marker = markers->first; marker; marker = marker->next) {
934                 if (marker->flag & SELECT) {
935                         /* unselect selected marker */
936                         marker->flag &= ~SELECT;
937                         
938                         /* create and set up new marker */
939                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
940                         newmarker->flag = SELECT;
941                         newmarker->frame = marker->frame;
942                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
943                         
944 #ifdef DURIAN_CAMERA_SWITCH
945                         newmarker->camera = marker->camera;
946 #endif
947
948                         /* new marker is added to the beginning of list */
949                         // FIXME: bad ordering!
950                         BLI_addhead(markers, newmarker);
951                 }
952         }
953 }
954
955 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
956 {
957         ed_marker_duplicate_apply(C);
958         ed_marker_move_exec(C, op); /* assumes frs delta set */
959         
960         return OPERATOR_FINISHED;
961         
962 }
963
964 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
965 {
966         ed_marker_duplicate_apply(C);
967         return ed_marker_move_invoke(C, op, evt);
968 }
969
970 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
971 {
972         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
973 }
974
975 static void MARKER_OT_duplicate(wmOperatorType *ot)
976 {
977         /* identifiers */
978         ot->name = "Duplicate Time Marker";
979         ot->description = "Duplicate selected time marker(s)";
980         ot->idname = "MARKER_OT_duplicate";
981         
982         /* api callbacks */
983         ot->exec = ed_marker_duplicate_exec;
984         ot->invoke = ed_marker_duplicate_invoke_wrapper;
985         ot->modal = ed_marker_move_modal;
986         ot->poll = ed_markers_poll_selected_markers;
987         ot->cancel = ed_marker_move_cancel;
988         
989         /* flags */
990         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
991         
992         /* rna storage */
993         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
994 }
995
996 /* ************************** selection ************************************/
997
998 /* select/deselect TimeMarker at current frame */
999 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
1000 {
1001         TimeMarker *marker;
1002         int select = 0;
1003         
1004         for (marker = markers->first; marker; marker = marker->next) {
1005                 /* if Shift is not set, then deselect Markers */
1006                 if (!shift) marker->flag &= ~SELECT;
1007                 
1008                 /* this way a not-shift select will allways give 1 selected marker */
1009                 if ((marker->frame == frame) && (!select)) {
1010                         if (marker->flag & SELECT) 
1011                                 marker->flag &= ~SELECT;
1012                         else
1013                                 marker->flag |= SELECT;
1014                         select = 1;
1015                 }
1016         }
1017 }
1018
1019 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1020 {
1021         ListBase *markers = ED_context_get_markers(C);
1022         ARegion *ar = CTX_wm_region(C);
1023         View2D *v2d = UI_view2d_fromcontext(C);
1024         float viewx;
1025         int x, y, cfra;
1026         
1027         if (markers == NULL)
1028                 return OPERATOR_PASS_THROUGH;
1029
1030         x = evt->x - ar->winrct.xmin;
1031         y = evt->y - ar->winrct.ymin;
1032         
1033         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);
1034         
1035         cfra = ED_markers_find_nearest_marker_time(markers, viewx);
1036         
1037         if (extend)
1038                 select_timeline_marker_frame(markers, cfra, 1);
1039         else
1040                 select_timeline_marker_frame(markers, cfra, 0);
1041         
1042 #ifdef DURIAN_CAMERA_SWITCH
1043
1044         if (camera) {
1045                 Scene *scene = CTX_data_scene(C);
1046                 Base *base;
1047                 TimeMarker *marker;
1048                 int sel = 0;
1049                 
1050                 if (!extend)
1051                         BKE_scene_base_deselect_all(scene);
1052                 
1053                 for (marker = markers->first; marker; marker = marker->next) {
1054                         if (marker->frame == cfra) {
1055                                 sel = (marker->flag & SELECT);
1056                                 break;
1057                         }
1058                 }
1059                 
1060                 for (marker = markers->first; marker; marker = marker->next) {
1061                         if (marker->camera) {
1062                                 if (marker->frame == cfra) {
1063                                         base = BKE_scene_base_find(scene, marker->camera);
1064                                         if (base) {
1065                                                 ED_base_object_select(base, sel);
1066                                                 if (sel)
1067                                                         ED_base_object_activate(C, base);
1068                                         }
1069                                 }
1070                         }
1071                 }
1072                 
1073                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1074         }
1075 #else
1076         (void)camera;
1077 #endif
1078
1079         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1080         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1081
1082         /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
1083         return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
1084 }
1085
1086 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1087 {
1088         short extend = RNA_boolean_get(op->ptr, "extend");
1089         short camera = 0;
1090 #ifdef DURIAN_CAMERA_SWITCH
1091         camera = RNA_boolean_get(op->ptr, "camera");
1092 #endif
1093         return ed_marker_select(C, evt, extend, camera);
1094 }
1095
1096 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1097 {
1098         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
1099 }
1100
1101 static void MARKER_OT_select(wmOperatorType *ot)
1102 {
1103         /* identifiers */
1104         ot->name = "Select Time Marker";
1105         ot->description = "Select time marker(s)";
1106         ot->idname = "MARKER_OT_select";
1107         
1108         /* api callbacks */
1109         ot->invoke = ed_marker_select_invoke_wrapper;
1110         ot->poll = ed_markers_poll_markers_exist;
1111         
1112         /* flags */
1113         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1114
1115         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1116 #ifdef DURIAN_CAMERA_SWITCH
1117         RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
1118 #endif
1119 }
1120
1121 /* *************************** border select markers **************** */
1122
1123 /* operator state vars used: (added by default WM callbacks)   
1124  * xmin, ymin
1125  * xmax, ymax
1126  *
1127  * customdata: the wmGesture pointer, with subwindow
1128  *
1129  * callbacks:
1130  *
1131  *  exec()      has to be filled in by user
1132  *
1133  *  invoke() default WM function
1134  *          adds modal handler
1135  *
1136  *  modal()     default WM function
1137  *          accept modal events while doing it, calls exec(), handles ESC and border drawing
1138  *
1139  *  poll()      has to be filled in by user for context
1140  */
1141
1142 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
1143 {
1144         View2D *v2d = UI_view2d_fromcontext(C);
1145         ListBase *markers = ED_context_get_markers(C);
1146         TimeMarker *marker;
1147         float xminf, xmaxf, yminf, ymaxf;
1148         int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
1149         int extend = RNA_boolean_get(op->ptr, "extend");
1150         rcti rect;
1151         
1152         WM_operator_properties_border_to_rcti(op, &rect);
1153
1154         UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin, &xminf, &yminf);
1155         UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax, &xmaxf, &ymaxf);
1156         
1157         if (markers == NULL)
1158                 return 0;
1159         
1160         /* XXX marker context */
1161         for (marker = markers->first; marker; marker = marker->next) {
1162                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
1163                         switch (gesture_mode) {
1164                                 case GESTURE_MODAL_SELECT:
1165                                         marker->flag |= SELECT;
1166                                         break;
1167                                 case GESTURE_MODAL_DESELECT:
1168                                         marker->flag &= ~SELECT;
1169                                         break;
1170                         }
1171                 }
1172                 else if (!extend) {
1173                         marker->flag &= ~SELECT;
1174                 }
1175         }
1176         
1177         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1178         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1179
1180         return 1;
1181 }
1182
1183 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1184 {
1185         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
1186 }
1187
1188 static void MARKER_OT_select_border(wmOperatorType *ot)
1189 {
1190         /* identifiers */
1191         ot->name = "Marker Border select";
1192         ot->description = "Select all time markers using border selection";
1193         ot->idname = "MARKER_OT_select_border";
1194         
1195         /* api callbacks */
1196         ot->exec = ed_marker_border_select_exec;
1197         ot->invoke = ed_marker_select_border_invoke_wrapper;
1198         ot->modal = WM_border_select_modal;
1199         ot->cancel = WM_border_select_cancel;
1200         
1201         ot->poll = ed_markers_poll_markers_exist;
1202         
1203         /* flags */
1204         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1205         
1206         /* rna */
1207         WM_operator_properties_gesture_border(ot, TRUE);
1208 }
1209
1210 /* *********************** (de)select all ***************** */
1211
1212 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
1213 {
1214         ListBase *markers = ED_context_get_markers(C);
1215         TimeMarker *marker;
1216         int action = RNA_enum_get(op->ptr, "action");
1217
1218         if (markers == NULL)
1219                 return OPERATOR_CANCELLED;
1220
1221         if (action == SEL_TOGGLE) {
1222                 action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
1223         }
1224         
1225         for (marker = markers->first; marker; marker = marker->next) {
1226                 switch (action) {
1227                         case SEL_SELECT:
1228                                 marker->flag |= SELECT;
1229                                 break;
1230                         case SEL_DESELECT:
1231                                 marker->flag &= ~SELECT;
1232                                 break;
1233                         case SEL_INVERT:
1234                                 marker->flag ^= SELECT;
1235                                 break;
1236                 }
1237         }
1238         
1239         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1240         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1241
1242         return OPERATOR_FINISHED;
1243 }
1244
1245 static void MARKER_OT_select_all(wmOperatorType *ot)
1246 {
1247         /* identifiers */
1248         ot->name = "(De)select all markers";
1249         ot->description = "Change selection of all time markers";
1250         ot->idname = "MARKER_OT_select_all";
1251         
1252         /* api callbacks */
1253         ot->exec = ed_marker_select_all_exec;
1254         ot->invoke = ed_markers_opwrap_invoke;
1255         ot->poll = ed_markers_poll_markers_exist;
1256         
1257         /* flags */
1258         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1259         
1260         /* rna */
1261         WM_operator_properties_select_all(ot);
1262 }
1263
1264 /* ***************** remove marker *********************** */
1265
1266 /* remove selected TimeMarkers */
1267 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
1268 {
1269         ListBase *markers = ED_context_get_markers(C);
1270         TimeMarker *marker, *nmarker;
1271         short changed = 0;
1272         
1273         if (markers == NULL)
1274                 return OPERATOR_CANCELLED;
1275         
1276         for (marker = markers->first; marker; marker = nmarker) {
1277                 nmarker = marker->next;
1278                 if (marker->flag & SELECT) {
1279                         BLI_freelinkN(markers, marker);
1280                         changed = 1;
1281                 }
1282         }
1283         
1284         if (changed) {
1285                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1286                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1287         }
1288         
1289         return OPERATOR_FINISHED;
1290 }
1291
1292 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1293 {
1294         // XXX: must we keep these confirmations?
1295         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
1296 }
1297
1298 static void MARKER_OT_delete(wmOperatorType *ot)
1299 {
1300         /* identifiers */
1301         ot->name = "Delete Markers";
1302         ot->description = "Delete selected time marker(s)";
1303         ot->idname = "MARKER_OT_delete";
1304         
1305         /* api callbacks */
1306         ot->invoke = ed_marker_delete_invoke_wrapper;
1307         ot->exec = ed_marker_delete_exec;
1308         ot->poll = ed_markers_poll_selected_markers;
1309         
1310         /* flags */
1311         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1312 }
1313
1314
1315 /* **************** rename marker ***************** */
1316
1317 /* rename first selected TimeMarker */
1318 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
1319 {
1320         TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1321
1322         if (marker) {
1323                 RNA_string_get(op->ptr, "name", marker->name);
1324                 
1325                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1326                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1327                 
1328                 return OPERATOR_FINISHED;
1329         }
1330         else {
1331                 return OPERATOR_CANCELLED;
1332         }
1333 }
1334
1335 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1336 {
1337         /* must initialize the marker name first if there is a marker selected */
1338         TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1339         if (marker)
1340                 RNA_string_set(op->ptr, "name", marker->name);
1341         
1342         /* now see if the operator is usable */
1343         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
1344 }
1345
1346 static void MARKER_OT_rename(wmOperatorType *ot)
1347 {
1348         /* identifiers */
1349         ot->name = "Rename Marker";
1350         ot->description = "Rename first selected time marker";
1351         ot->idname = "MARKER_OT_rename";
1352         
1353         /* api callbacks */
1354         ot->invoke = ed_marker_rename_invoke_wrapper;
1355         ot->exec = ed_marker_rename_exec;
1356         ot->poll = ed_markers_poll_selected_markers;
1357         
1358         /* flags */
1359         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1360         
1361         /* properties */
1362         ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
1363         //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
1364 }
1365
1366 /* **************** make links to scene ***************** */
1367
1368 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1369 {
1370         ListBase *markers = ED_context_get_markers(C);
1371         Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
1372         TimeMarker *marker, *marker_new;
1373
1374         if (scene_to == NULL) {
1375                 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1376                 return OPERATOR_CANCELLED;
1377         }
1378
1379         if (scene_to == CTX_data_scene(C)) {
1380                 BKE_report(op->reports, RPT_ERROR, "Can't re-link markers into the same scene");
1381                 return OPERATOR_CANCELLED;
1382         }
1383
1384         /* copy markers */
1385         for (marker = markers->first; marker; marker = marker->next) {
1386                 if (marker->flag & SELECT) {
1387                         marker_new = MEM_dupallocN(marker);
1388                         marker_new->prev = marker_new->next = NULL;
1389                         
1390                         BLI_addtail(&scene_to->markers, marker_new);
1391                 }
1392         }
1393
1394         return OPERATOR_FINISHED;
1395 }
1396
1397 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1398 {
1399         PropertyRNA *prop;
1400
1401         /* identifiers */
1402         ot->name = "Make Links to Scene";
1403         ot->description = "Copy selected markers to another scene";
1404         ot->idname = "MARKER_OT_make_links_scene";
1405
1406         /* api callbacks */
1407         ot->exec = ed_marker_make_links_scene_exec;
1408         ot->invoke = ed_markers_opwrap_invoke;
1409         ot->poll = ed_markers_poll_selected_markers;
1410
1411         /* flags */
1412         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1413
1414         /* properties */
1415         prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
1416         RNA_def_enum_funcs(prop, RNA_scene_itemf);
1417         ot->prop = prop;
1418
1419 }
1420
1421 #ifdef DURIAN_CAMERA_SWITCH
1422 /* ******************************* camera bind marker ***************** */
1423
1424 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
1425 {
1426         bScreen *sc = CTX_wm_screen(C);
1427         Scene *scene = CTX_data_scene(C);
1428         Object *ob = CTX_data_active_object(C);
1429         ListBase *markers = ED_context_get_markers(C);
1430         TimeMarker *marker;
1431
1432         marker = ED_markers_get_first_selected(markers);
1433         if (marker == NULL)
1434                 return OPERATOR_CANCELLED;
1435
1436         marker->camera = ob;
1437
1438         /* camera may have changes */
1439         BKE_scene_camera_switch_update(scene);
1440         BKE_screen_view3d_scene_sync(sc);
1441
1442         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1443         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1444         WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); /* so we get view3d redraws */
1445
1446         return OPERATOR_FINISHED;
1447 }
1448
1449 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1450 {
1451         /* identifiers */
1452         ot->name = "Bind Camera to Markers";
1453         ot->description = "Bind the active camera to selected markers(s)";
1454         ot->idname = "MARKER_OT_camera_bind";
1455
1456         /* api callbacks */
1457         ot->exec = ed_marker_camera_bind_exec;
1458         ot->invoke = ed_markers_opwrap_invoke;
1459         ot->poll = ed_markers_poll_selected_markers;
1460
1461         /* flags */
1462         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1463 }
1464 #endif
1465
1466 /* ************************** registration **********************************/
1467
1468 /* called in screen_ops.c:ED_operatortypes_screen() */
1469 void ED_operatortypes_marker(void)
1470 {
1471         WM_operatortype_append(MARKER_OT_add);
1472         WM_operatortype_append(MARKER_OT_move);
1473         WM_operatortype_append(MARKER_OT_duplicate);
1474         WM_operatortype_append(MARKER_OT_select);
1475         WM_operatortype_append(MARKER_OT_select_border);
1476         WM_operatortype_append(MARKER_OT_select_all);
1477         WM_operatortype_append(MARKER_OT_delete);
1478         WM_operatortype_append(MARKER_OT_rename);
1479         WM_operatortype_append(MARKER_OT_make_links_scene);
1480 #ifdef DURIAN_CAMERA_SWITCH
1481         WM_operatortype_append(MARKER_OT_camera_bind);
1482 #endif
1483 }
1484
1485 /* called in screen_ops.c:ED_keymap_screen() */
1486 void ED_marker_keymap(wmKeyConfig *keyconf)
1487 {
1488         wmKeyMap *keymap = WM_keymap_find(keyconf, "Markers", 0, 0);
1489         wmKeyMapItem *kmi;
1490         
1491         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1492         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1493         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1494         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1495         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
1496         RNA_boolean_set(kmi->ptr, "extend", TRUE);
1497
1498 #ifdef DURIAN_CAMERA_SWITCH
1499         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1500         RNA_boolean_set(kmi->ptr, "extend", FALSE);
1501         RNA_boolean_set(kmi->ptr, "camera", TRUE);
1502
1503         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
1504         RNA_boolean_set(kmi->ptr, "extend", TRUE);
1505         RNA_boolean_set(kmi->ptr, "camera", TRUE);
1506 #else
1507         (void)kmi;
1508 #endif
1509         
1510         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1511         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1512         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1513         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1514         WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1515         
1516         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1517 #ifdef DURIAN_CAMERA_SWITCH
1518         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1519 #endif
1520 }
1521
1522 /* to be called from animation editor keymaps, see note below */
1523 void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
1524 {
1525         /* duplicate of some marker-hotkeys but without the bounds checking
1526          * since these are handy to be able to do unrestricted and won't conflict
1527          * with primary function hotkeys (Usability tweak [#27469])
1528          */
1529         WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1530         WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1531 }