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