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