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