62ffdc7fd3a7698b928a01c6572cff5577567561
[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 does not 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(bContext *C, wmOperator *op)
710 {
711 #ifdef DURIAN_CAMERA_SWITCH
712         bScreen *sc = CTX_wm_screen(C);
713         Scene *scene = CTX_data_scene(C);
714         Object *camera = scene->camera;
715 #endif
716         MarkerMove *mm = op->customdata;
717         TimeMarker *marker;
718         int a, offs;
719         
720         offs = RNA_int_get(op->ptr, "frames");
721         for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
722                 if (marker->flag & SELECT) {
723                         marker->frame = mm->oldframe[a] + offs;
724                         a++;
725                 }
726         }
727
728         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
729         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
730         
731 #ifdef DURIAN_CAMERA_SWITCH
732         /* so we get view3d redraws */
733         BKE_scene_camera_switch_update(scene);
734
735         if (camera != scene->camera) {
736                 BKE_screen_view3d_scene_sync(sc);
737                 WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
738         }
739 #endif
740 }
741
742 /* only for modal */
743 static int ed_marker_move_cancel(bContext *C, wmOperator *op)
744 {
745         RNA_int_set(op->ptr, "frames", 0);
746         ed_marker_move_apply(C, op);
747         ed_marker_move_exit(C, op);
748
749         return OPERATOR_CANCELLED;
750 }
751
752
753
754 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
755 {
756         Scene *scene = CTX_data_scene(C);
757         MarkerMove *mm = op->customdata;
758         View2D *v2d = UI_view2d_fromcontext(C);
759         TimeMarker *marker, *selmarker = NULL;
760         float dx, fac;
761         char str[256];
762                 
763         switch (evt->type) {
764                 case ESCKEY:
765                         ed_marker_move_cancel(C, op);
766                         return OPERATOR_CANCELLED;
767                 
768                 case RIGHTMOUSE:
769                         /* press = user manually demands transform to be canceled */
770                         if (evt->val == KM_PRESS) {
771                                 ed_marker_move_cancel(C, op);
772                                 return OPERATOR_CANCELLED;
773                         }
774                 /* else continue; <--- see if release event should be caught for tweak-end */
775                 
776                 case RETKEY:
777                 case PADENTER:
778                 case LEFTMOUSE:
779                 case MIDDLEMOUSE:
780                         if (WM_modal_tweak_exit(evt, mm->event_type)) {
781                                 ed_marker_move_exit(C, op);
782                                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
783                                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
784                                 return OPERATOR_FINISHED;
785                         }
786                         break;
787                 case MOUSEMOVE:
788                         if (hasNumInput(&mm->num))
789                                 break;
790                         
791                         dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
792                         
793                         if (evt->x != mm->evtx) {   /* XXX maybe init for first time */
794                                 int a, offs, totmark = 0;
795                                 
796                                 mm->evtx = evt->x;
797                                 
798                                 fac = ((float)(evt->x - mm->firstx) * dx);
799                                 
800                                 if (mm->slink->spacetype == SPACE_TIME) 
801                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
802                                 else
803                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
804                                 
805                                 offs = (int)fac;
806                                 RNA_int_set(op->ptr, "frames", offs);
807                                 ed_marker_move_apply(C, op);
808                                 
809                                 /* cruft below is for header print */
810                                 for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
811                                         if (marker->flag & SELECT) {
812                                                 selmarker = marker;
813                                                 a++; totmark++;
814                                         }
815                                 }
816                                 
817                                 if (totmark == 1) {
818                                         /* we print current marker value */
819                                         if (mm->slink->spacetype == SPACE_TIME) {
820                                                 SpaceTime *stime = (SpaceTime *)mm->slink;
821                                                 if (stime->flag & TIME_DRAWFRAMES) 
822                                                         BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
823                                                 else 
824                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
825                                         }
826                                         else if (mm->slink->spacetype == SPACE_ACTION) {
827                                                 SpaceAction *saction = (SpaceAction *)mm->slink;
828                                                 if (saction->flag & SACTION_DRAWTIME)
829                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
830                                                 else
831                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
832                                         }
833                                         else {
834                                                 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
835                                         }
836                                 }
837                                 else {
838                                         /* we only print the offset */
839                                         if (mm->slink->spacetype == SPACE_TIME) {
840                                                 SpaceTime *stime = (SpaceTime *)mm->slink;
841                                                 if (stime->flag & TIME_DRAWFRAMES) 
842                                                         BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
843                                                 else 
844                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
845                                         }
846                                         else if (mm->slink->spacetype == SPACE_ACTION) {
847                                                 SpaceAction *saction = (SpaceAction *)mm->slink;
848                                                 if (saction->flag & SACTION_DRAWTIME)
849                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
850                                                 else
851                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
852                                         }
853                                         else {
854                                                 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
855                                         }
856                                 }
857                                 
858                                 ED_area_headerprint(CTX_wm_area(C), str);
859                         }
860         }
861
862         if (evt->val == KM_PRESS) {
863                 if (handleNumInput(&mm->num, evt)) {
864                         char str_tx[NUM_STR_REP_LEN];
865                         float value = RNA_int_get(op->ptr, "frames");
866                         applyNumInput(&mm->num, &value);
867
868                         if (hasNumInput(&mm->num)) {
869                                 outputNumInput(&mm->num, str_tx);
870                         }
871                         else {
872                                 BLI_snprintf(str_tx, sizeof(str_tx), "%d", (int)value);
873                         }
874
875                         RNA_int_set(op->ptr, "frames", value);
876                         ed_marker_move_apply(C, op);
877                         // ed_marker_header_update(C, op, str, (int)value);
878                         // strcat(str, str_tx);
879                         BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
880                         ED_area_headerprint(CTX_wm_area(C), str);
881                 }
882         }
883
884         return OPERATOR_RUNNING_MODAL;
885 }
886
887 static int ed_marker_move_exec(bContext *C, wmOperator *op)
888 {
889         if (ed_marker_move_init(C, op)) {
890                 ed_marker_move_apply(C, op);
891                 ed_marker_move_exit(C, op);
892                 return OPERATOR_FINISHED;
893         }
894         return OPERATOR_PASS_THROUGH;
895 }
896
897 static void MARKER_OT_move(wmOperatorType *ot)
898 {
899         /* identifiers */
900         ot->name = "Move Time Marker";
901         ot->description = "Move selected time marker(s)";
902         ot->idname = "MARKER_OT_move";
903         
904         /* api callbacks */
905         ot->exec = ed_marker_move_exec;
906         ot->invoke = ed_marker_move_invoke_wrapper;
907         ot->modal = ed_marker_move_modal;
908         ot->poll = ed_markers_poll_selected_markers;
909         ot->cancel = ed_marker_move_cancel;
910         
911         /* flags */
912         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
913         
914         /* rna storage */
915         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
916 }
917
918 /* ************************** duplicate markers *************************** */
919
920 /* operator state vars used:
921  *     frs: delta movement
922  *
923  * functions:
924  *
925  *     apply()  do the actual duplicate
926  *
927  * callbacks:
928  *
929  *     exec()    calls apply, move_exec
930  *
931  *     invoke() calls apply, move_invoke
932  *
933  *     modal()    uses move_modal
934  */
935
936 /* duplicate selected TimeMarkers */
937 static void ed_marker_duplicate_apply(bContext *C)
938 {
939         ListBase *markers = ED_context_get_markers(C);
940         TimeMarker *marker, *newmarker;
941         
942         if (markers == NULL) 
943                 return;
944
945         /* go through the list of markers, duplicate selected markers and add duplicated copies
946          * to the beginning of the list (unselect original markers)
947          */
948         for (marker = markers->first; marker; marker = marker->next) {
949                 if (marker->flag & SELECT) {
950                         /* unselect selected marker */
951                         marker->flag &= ~SELECT;
952                         
953                         /* create and set up new marker */
954                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
955                         newmarker->flag = SELECT;
956                         newmarker->frame = marker->frame;
957                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
958                         
959 #ifdef DURIAN_CAMERA_SWITCH
960                         newmarker->camera = marker->camera;
961 #endif
962
963                         /* new marker is added to the beginning of list */
964                         // FIXME: bad ordering!
965                         BLI_addhead(markers, newmarker);
966                 }
967         }
968 }
969
970 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
971 {
972         ed_marker_duplicate_apply(C);
973         ed_marker_move_exec(C, op); /* assumes frs delta set */
974         
975         return OPERATOR_FINISHED;
976         
977 }
978
979 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
980 {
981         ed_marker_duplicate_apply(C);
982         return ed_marker_move_invoke(C, op, evt);
983 }
984
985 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
986 {
987         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
988 }
989
990 static void MARKER_OT_duplicate(wmOperatorType *ot)
991 {
992         /* identifiers */
993         ot->name = "Duplicate Time Marker";
994         ot->description = "Duplicate selected time marker(s)";
995         ot->idname = "MARKER_OT_duplicate";
996         
997         /* api callbacks */
998         ot->exec = ed_marker_duplicate_exec;
999         ot->invoke = ed_marker_duplicate_invoke_wrapper;
1000         ot->modal = ed_marker_move_modal;
1001         ot->poll = ed_markers_poll_selected_markers;
1002         ot->cancel = ed_marker_move_cancel;
1003         
1004         /* flags */
1005         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1006         
1007         /* rna storage */
1008         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
1009 }
1010
1011 /* ************************** selection ************************************/
1012
1013 /* select/deselect TimeMarker at current frame */
1014 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
1015 {
1016         TimeMarker *marker;
1017         int select = 0;
1018         
1019         for (marker = markers->first; marker; marker = marker->next) {
1020                 /* if Shift is not set, then deselect Markers */
1021                 if (!shift) marker->flag &= ~SELECT;
1022                 
1023                 /* this way a not-shift select will allways give 1 selected marker */
1024                 if ((marker->frame == frame) && (!select)) {
1025                         if (marker->flag & SELECT) 
1026                                 marker->flag &= ~SELECT;
1027                         else
1028                                 marker->flag |= SELECT;
1029                         select = 1;
1030                 }
1031         }
1032 }
1033
1034 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1035 {
1036         ListBase *markers = ED_context_get_markers(C);
1037         ARegion *ar = CTX_wm_region(C);
1038         View2D *v2d = UI_view2d_fromcontext(C);
1039         float viewx;
1040         int x, y, cfra;
1041         
1042         if (markers == NULL)
1043                 return OPERATOR_PASS_THROUGH;
1044
1045         x = evt->x - ar->winrct.xmin;
1046         y = evt->y - ar->winrct.ymin;
1047         
1048         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);
1049         
1050         cfra = ED_markers_find_nearest_marker_time(markers, viewx);
1051         
1052         if (extend)
1053                 select_timeline_marker_frame(markers, cfra, 1);
1054         else
1055                 select_timeline_marker_frame(markers, cfra, 0);
1056         
1057 #ifdef DURIAN_CAMERA_SWITCH
1058
1059         if (camera) {
1060                 Scene *scene = CTX_data_scene(C);
1061                 Base *base;
1062                 TimeMarker *marker;
1063                 int sel = 0;
1064                 
1065                 if (!extend)
1066                         BKE_scene_base_deselect_all(scene);
1067                 
1068                 for (marker = markers->first; marker; marker = marker->next) {
1069                         if (marker->frame == cfra) {
1070                                 sel = (marker->flag & SELECT);
1071                                 break;
1072                         }
1073                 }
1074                 
1075                 for (marker = markers->first; marker; marker = marker->next) {
1076                         if (marker->camera) {
1077                                 if (marker->frame == cfra) {
1078                                         base = BKE_scene_base_find(scene, marker->camera);
1079                                         if (base) {
1080                                                 ED_base_object_select(base, sel);
1081                                                 if (sel)
1082                                                         ED_base_object_activate(C, base);
1083                                         }
1084                                 }
1085                         }
1086                 }
1087                 
1088                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
1089         }
1090 #else
1091         (void)camera;
1092 #endif
1093
1094         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1095         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1096
1097         /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
1098         return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
1099 }
1100
1101 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1102 {
1103         short extend = RNA_boolean_get(op->ptr, "extend");
1104         short camera = 0;
1105 #ifdef DURIAN_CAMERA_SWITCH
1106         camera = RNA_boolean_get(op->ptr, "camera");
1107 #endif
1108         return ed_marker_select(C, evt, extend, camera);
1109 }
1110
1111 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1112 {
1113         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
1114 }
1115
1116 static void MARKER_OT_select(wmOperatorType *ot)
1117 {
1118         /* identifiers */
1119         ot->name = "Select Time Marker";
1120         ot->description = "Select time marker(s)";
1121         ot->idname = "MARKER_OT_select";
1122         
1123         /* api callbacks */
1124         ot->invoke = ed_marker_select_invoke_wrapper;
1125         ot->poll = ed_markers_poll_markers_exist;
1126         
1127         /* flags */
1128         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1129
1130         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1131 #ifdef DURIAN_CAMERA_SWITCH
1132         RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
1133 #endif
1134 }
1135
1136 /* *************************** border select markers **************** */
1137
1138 /* operator state vars used: (added by default WM callbacks)   
1139  * xmin, ymin
1140  * xmax, ymax
1141  *
1142  * customdata: the wmGesture pointer, with subwindow
1143  *
1144  * callbacks:
1145  *
1146  *  exec()      has to be filled in by user
1147  *
1148  *  invoke() default WM function
1149  *          adds modal handler
1150  *
1151  *  modal()     default WM function
1152  *          accept modal events while doing it, calls exec(), handles ESC and border drawing
1153  *
1154  *  poll()      has to be filled in by user for context
1155  */
1156
1157 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
1158 {
1159         View2D *v2d = UI_view2d_fromcontext(C);
1160         ListBase *markers = ED_context_get_markers(C);
1161         TimeMarker *marker;
1162         float xminf, xmaxf, yminf, ymaxf;
1163         int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
1164         int extend = RNA_boolean_get(op->ptr, "extend");
1165         rcti rect;
1166         
1167         WM_operator_properties_border_to_rcti(op, &rect);
1168
1169         UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin, &xminf, &yminf);
1170         UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax, &xmaxf, &ymaxf);
1171         
1172         if (markers == NULL)
1173                 return 0;
1174         
1175         /* XXX marker context */
1176         for (marker = markers->first; marker; marker = marker->next) {
1177                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
1178                         switch (gesture_mode) {
1179                                 case GESTURE_MODAL_SELECT:
1180                                         marker->flag |= SELECT;
1181                                         break;
1182                                 case GESTURE_MODAL_DESELECT:
1183                                         marker->flag &= ~SELECT;
1184                                         break;
1185                         }
1186                 }
1187                 else if (!extend) {
1188                         marker->flag &= ~SELECT;
1189                 }
1190         }
1191         
1192         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1193         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1194
1195         return 1;
1196 }
1197
1198 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1199 {
1200         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
1201 }
1202
1203 static void MARKER_OT_select_border(wmOperatorType *ot)
1204 {
1205         /* identifiers */
1206         ot->name = "Marker Border select";
1207         ot->description = "Select all time markers using border selection";
1208         ot->idname = "MARKER_OT_select_border";
1209         
1210         /* api callbacks */
1211         ot->exec = ed_marker_border_select_exec;
1212         ot->invoke = ed_marker_select_border_invoke_wrapper;
1213         ot->modal = WM_border_select_modal;
1214         ot->cancel = WM_border_select_cancel;
1215         
1216         ot->poll = ed_markers_poll_markers_exist;
1217         
1218         /* flags */
1219         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1220         
1221         /* rna */
1222         WM_operator_properties_gesture_border(ot, TRUE);
1223 }
1224
1225 /* *********************** (de)select all ***************** */
1226
1227 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
1228 {
1229         ListBase *markers = ED_context_get_markers(C);
1230         TimeMarker *marker;
1231         int action = RNA_enum_get(op->ptr, "action");
1232
1233         if (markers == NULL)
1234                 return OPERATOR_CANCELLED;
1235
1236         if (action == SEL_TOGGLE) {
1237                 action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
1238         }
1239         
1240         for (marker = markers->first; marker; marker = marker->next) {
1241                 switch (action) {
1242                         case SEL_SELECT:
1243                                 marker->flag |= SELECT;
1244                                 break;
1245                         case SEL_DESELECT:
1246                                 marker->flag &= ~SELECT;
1247                                 break;
1248                         case SEL_INVERT:
1249                                 marker->flag ^= SELECT;
1250                                 break;
1251                 }
1252         }
1253         
1254         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1255         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1256
1257         return OPERATOR_FINISHED;
1258 }
1259
1260 static void MARKER_OT_select_all(wmOperatorType *ot)
1261 {
1262         /* identifiers */
1263         ot->name = "(De)select all markers";
1264         ot->description = "Change selection of all time markers";
1265         ot->idname = "MARKER_OT_select_all";
1266         
1267         /* api callbacks */
1268         ot->exec = ed_marker_select_all_exec;
1269         ot->invoke = ed_markers_opwrap_invoke;
1270         ot->poll = ed_markers_poll_markers_exist;
1271         
1272         /* flags */
1273         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1274         
1275         /* rna */
1276         WM_operator_properties_select_all(ot);
1277 }
1278
1279 /* ***************** remove marker *********************** */
1280
1281 /* remove selected TimeMarkers */
1282 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
1283 {
1284         ListBase *markers = ED_context_get_markers(C);
1285         TimeMarker *marker, *nmarker;
1286         short changed = 0;
1287         
1288         if (markers == NULL)
1289                 return OPERATOR_CANCELLED;
1290         
1291         for (marker = markers->first; marker; marker = nmarker) {
1292                 nmarker = marker->next;
1293                 if (marker->flag & SELECT) {
1294                         BLI_freelinkN(markers, marker);
1295                         changed = 1;
1296                 }
1297         }
1298         
1299         if (changed) {
1300                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1301                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1302         }
1303         
1304         return OPERATOR_FINISHED;
1305 }
1306
1307 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1308 {
1309         // XXX: must we keep these confirmations?
1310         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
1311 }
1312
1313 static void MARKER_OT_delete(wmOperatorType *ot)
1314 {
1315         /* identifiers */
1316         ot->name = "Delete Markers";
1317         ot->description = "Delete selected time marker(s)";
1318         ot->idname = "MARKER_OT_delete";
1319         
1320         /* api callbacks */
1321         ot->invoke = ed_marker_delete_invoke_wrapper;
1322         ot->exec = ed_marker_delete_exec;
1323         ot->poll = ed_markers_poll_selected_markers;
1324         
1325         /* flags */
1326         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1327 }
1328
1329
1330 /* **************** rename marker ***************** */
1331
1332 /* rename first selected TimeMarker */
1333 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
1334 {
1335         TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1336
1337         if (marker) {
1338                 RNA_string_get(op->ptr, "name", marker->name);
1339                 
1340                 WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1341                 WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1342                 
1343                 return OPERATOR_FINISHED;
1344         }
1345         else {
1346                 return OPERATOR_CANCELLED;
1347         }
1348 }
1349
1350 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1351 {
1352         /* must initialize the marker name first if there is a marker selected */
1353         TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1354         if (marker)
1355                 RNA_string_set(op->ptr, "name", marker->name);
1356         
1357         /* now see if the operator is usable */
1358         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
1359 }
1360
1361 static void MARKER_OT_rename(wmOperatorType *ot)
1362 {
1363         /* identifiers */
1364         ot->name = "Rename Marker";
1365         ot->description = "Rename first selected time marker";
1366         ot->idname = "MARKER_OT_rename";
1367         
1368         /* api callbacks */
1369         ot->invoke = ed_marker_rename_invoke_wrapper;
1370         ot->exec = ed_marker_rename_exec;
1371         ot->poll = ed_markers_poll_selected_markers;
1372         
1373         /* flags */
1374         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1375         
1376         /* properties */
1377         ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
1378         //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
1379 }
1380
1381 /* **************** make links to scene ***************** */
1382
1383 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1384 {
1385         ListBase *markers = ED_context_get_markers(C);
1386         Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
1387         TimeMarker *marker, *marker_new;
1388
1389         if (scene_to == NULL) {
1390                 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1391                 return OPERATOR_CANCELLED;
1392         }
1393
1394         if (scene_to == CTX_data_scene(C)) {
1395                 BKE_report(op->reports, RPT_ERROR, "Cannot re-link markers into the same scene");
1396                 return OPERATOR_CANCELLED;
1397         }
1398
1399         /* copy markers */
1400         for (marker = markers->first; marker; marker = marker->next) {
1401                 if (marker->flag & SELECT) {
1402                         marker_new = MEM_dupallocN(marker);
1403                         marker_new->prev = marker_new->next = NULL;
1404                         
1405                         BLI_addtail(&scene_to->markers, marker_new);
1406                 }
1407         }
1408
1409         return OPERATOR_FINISHED;
1410 }
1411
1412 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1413 {
1414         PropertyRNA *prop;
1415
1416         /* identifiers */
1417         ot->name = "Make Links to Scene";
1418         ot->description = "Copy selected markers to another scene";
1419         ot->idname = "MARKER_OT_make_links_scene";
1420
1421         /* api callbacks */
1422         ot->exec = ed_marker_make_links_scene_exec;
1423         ot->invoke = ed_markers_opwrap_invoke;
1424         ot->poll = ed_markers_poll_selected_markers;
1425
1426         /* flags */
1427         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1428
1429         /* properties */
1430         prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
1431         RNA_def_enum_funcs(prop, RNA_scene_itemf);
1432         ot->prop = prop;
1433
1434 }
1435
1436 #ifdef DURIAN_CAMERA_SWITCH
1437 /* ******************************* camera bind marker ***************** */
1438
1439 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
1440 {
1441         bScreen *sc = CTX_wm_screen(C);
1442         Scene *scene = CTX_data_scene(C);
1443         Object *ob = CTX_data_active_object(C);
1444         ListBase *markers = ED_context_get_markers(C);
1445         TimeMarker *marker;
1446
1447         marker = ED_markers_get_first_selected(markers);
1448         if (marker == NULL)
1449                 return OPERATOR_CANCELLED;
1450
1451         marker->camera = ob;
1452
1453         /* camera may have changes */
1454         BKE_scene_camera_switch_update(scene);
1455         BKE_screen_view3d_scene_sync(sc);
1456
1457         WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
1458         WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
1459         WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); /* so we get view3d redraws */
1460
1461         return OPERATOR_FINISHED;
1462 }
1463
1464 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1465 {
1466         /* identifiers */
1467         ot->name = "Bind Camera to Markers";
1468         ot->description = "Bind the active camera to selected markers(s)";
1469         ot->idname = "MARKER_OT_camera_bind";
1470
1471         /* api callbacks */
1472         ot->exec = ed_marker_camera_bind_exec;
1473         ot->invoke = ed_markers_opwrap_invoke;
1474         ot->poll = ed_markers_poll_selected_markers;
1475
1476         /* flags */
1477         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1478 }
1479 #endif
1480
1481 /* ************************** registration **********************************/
1482
1483 /* called in screen_ops.c:ED_operatortypes_screen() */
1484 void ED_operatortypes_marker(void)
1485 {
1486         WM_operatortype_append(MARKER_OT_add);
1487         WM_operatortype_append(MARKER_OT_move);
1488         WM_operatortype_append(MARKER_OT_duplicate);
1489         WM_operatortype_append(MARKER_OT_select);
1490         WM_operatortype_append(MARKER_OT_select_border);
1491         WM_operatortype_append(MARKER_OT_select_all);
1492         WM_operatortype_append(MARKER_OT_delete);
1493         WM_operatortype_append(MARKER_OT_rename);
1494         WM_operatortype_append(MARKER_OT_make_links_scene);
1495 #ifdef DURIAN_CAMERA_SWITCH
1496         WM_operatortype_append(MARKER_OT_camera_bind);
1497 #endif
1498 }
1499
1500 /* called in screen_ops.c:ED_keymap_screen() */
1501 void ED_marker_keymap(wmKeyConfig *keyconf)
1502 {
1503         wmKeyMap *keymap = WM_keymap_find(keyconf, "Markers", 0, 0);
1504         wmKeyMapItem *kmi;
1505         
1506         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1507         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1508         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1509         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1510         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
1511         RNA_boolean_set(kmi->ptr, "extend", TRUE);
1512
1513 #ifdef DURIAN_CAMERA_SWITCH
1514         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1515         RNA_boolean_set(kmi->ptr, "extend", FALSE);
1516         RNA_boolean_set(kmi->ptr, "camera", TRUE);
1517
1518         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
1519         RNA_boolean_set(kmi->ptr, "extend", TRUE);
1520         RNA_boolean_set(kmi->ptr, "camera", TRUE);
1521 #else
1522         (void)kmi;
1523 #endif
1524         
1525         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1526         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1527         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1528         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1529         WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1530         
1531         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1532 #ifdef DURIAN_CAMERA_SWITCH
1533         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1534 #endif
1535 }
1536
1537 /* to be called from animation editor keymaps, see note below */
1538 void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
1539 {
1540         /* duplicate of some marker-hotkeys but without the bounds checking
1541          * since these are handy to be able to do unrestricted and won't conflict
1542          * with primary function hotkeys (Usability tweak [#27469])
1543          */
1544         WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1545         WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1546 }