7f7b1b28319c2dd5fb2e8215e0ba1ece196663f1
[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          * (optimization for not searching list)
236          */
237         if (selcount > 1) {
238                 for (marker= markers->first; marker; marker= marker->next) {
239                         if (sel) {
240                                 if (marker->flag & SELECT) {
241                                         if (marker->frame < min)
242                                                 min= (float)marker->frame;
243                                         if (marker->frame > max)
244                                                 max= (float)marker->frame;
245                                 }
246                         }
247                         else {
248                                 if (marker->frame < min)
249                                         min= (float)marker->frame;
250                                 if (marker->frame > max)
251                                         max= (float)marker->frame;
252                         }       
253                 }
254         }
255         
256         /* set the min/max values */
257         *first= min;
258         *last= max;
259 }
260
261 /* --------------------------------- */
262
263 /* Adds a marker to list of cfra elems */
264 static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
265 {
266         CfraElem *ce, *cen;
267         
268         /* should this one only be considered if it is selected? */
269         if ((only_sel) && ((marker->flag & SELECT)==0))
270                 return;
271         
272         /* insertion sort - try to find a previous cfra elem */
273         for (ce= lb->first; ce; ce= ce->next) {
274                 if (ce->cfra == marker->frame) {
275                         /* do because of double keys */
276                         if (marker->flag & SELECT) 
277                                 ce->sel= marker->flag;
278                         return;
279                 }
280                 else if (ce->cfra > marker->frame) break;
281         }       
282         
283         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
284         if (ce) BLI_insertlinkbefore(lb, ce, cen);
285         else BLI_addtail(lb, cen);
286
287         cen->cfra= marker->frame;
288         cen->sel= marker->flag;
289 }
290
291 /* This function makes a list of all the markers. The only_sel
292  * argument is used to specify whether only the selected markers
293  * are added.
294  */
295 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
296 {
297         TimeMarker *marker;
298         
299         if (markers == NULL)
300                 return;
301         
302         for (marker= markers->first; marker; marker= marker->next)
303                 add_marker_to_cfra_elem(lb, marker, only_sel);
304 }
305
306 /* --------------------------------- */
307
308 /* Get the first selected marker */
309 TimeMarker *ED_markers_get_first_selected(ListBase *markers)
310 {
311         TimeMarker *marker;
312         
313         if (markers) {
314                 for (marker = markers->first; marker; marker = marker->next) {
315                         if (marker->flag & SELECT)
316                                 return marker;
317                 }
318         }
319         
320         return NULL;
321 }
322
323 /* --------------------------------- */
324
325 /* Print debugging prints of list of markers 
326  * BSI's: do NOT make static or put in if-defs as "unused code". That's too much trouble when we need to use for quick debugging!
327  */
328 void debug_markers_print_list(ListBase *markers)
329 {
330         TimeMarker *marker;
331         
332         if (markers == NULL) {
333                 printf("No markers list to print debug for\n");
334                 return;
335         }
336         
337         printf("List of markers follows: -----\n");
338         
339         for (marker = markers->first; marker; marker = marker->next) {
340                 printf("\t'%s' on %d at %p with %u\n", marker->name, marker->frame, (void *)marker, marker->flag);
341         }
342         
343         printf("End of list ------------------\n");
344 }
345
346 /* ************* Marker Drawing ************ */
347
348 /* function to draw markers */
349 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
350 {
351         float xpos, ypixels, xscale, yscale;
352         int icon_id= 0;
353         
354         xpos = marker->frame;
355         
356         /* no time correction for framelen! space is drawn with old values */
357         ypixels= 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 /* operator state vars used:  
601  *     frs: delta movement
602  * 
603  * functions:
604  * 
605  *     init()   check selection, add customdata with old values and some lookups
606  * 
607  *     apply()  do the actual movement
608  * 
609  *     exit()    cleanup, send notifier
610  * 
611  *     cancel() to escape from modal
612  * 
613  * callbacks:
614  * 
615  *     exec()    calls init, apply, exit 
616  * 
617  *     invoke() calls init, adds modal handler
618  * 
619  *     modal()    accept modal events while doing it, ends with apply and exit, or cancel
620  * 
621  */
622
623 typedef struct MarkerMove {
624         SpaceLink *slink;
625         ListBase *markers;
626         int event_type;         /* store invoke-event, to verify */
627         int *oldframe, evtx, firstx;
628         NumInput num;
629 } MarkerMove;
630
631 /* copy selection to temp buffer */
632 /* return 0 if not OK */
633 static int ed_marker_move_init(bContext *C, wmOperator *op)
634 {
635         ListBase *markers= ED_context_get_markers(C);
636         MarkerMove *mm;
637         TimeMarker *marker;
638         int totmark=0;
639         int a;
640
641         if(markers == NULL) return 0;
642         
643         for (marker= markers->first; marker; marker= marker->next)
644                 if (marker->flag & SELECT) totmark++;
645         
646         if (totmark==0) return 0;
647         
648         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
649         mm->slink= CTX_wm_space_data(C);
650         mm->markers= markers;
651         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
652
653         initNumInput(&mm->num);
654         mm->num.idx_max = 0; /* one axis */
655         mm->num.flag |= NUM_NO_FRACTION;
656         mm->num.increment = 1.0f;
657         
658         for (a=0, marker= markers->first; marker; marker= marker->next) {
659                 if (marker->flag & SELECT) {
660                         mm->oldframe[a]= marker->frame;
661                         a++;
662                 }
663         }
664         
665         return 1;
666 }
667
668 /* free stuff */
669 static void ed_marker_move_exit(bContext *C, wmOperator *op)
670 {
671         MarkerMove *mm= op->customdata;
672         
673         /* free data */
674         MEM_freeN(mm->oldframe);
675         MEM_freeN(op->customdata);
676         op->customdata= NULL;
677         
678         /* clear custom header prints */
679         ED_area_headerprint(CTX_wm_area(C), NULL);
680 }
681
682 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
683 {
684         if(ed_marker_move_init(C, op)) {
685                 MarkerMove *mm= op->customdata;
686                 
687                 mm->evtx= evt->x;
688                 mm->firstx= evt->x;
689                 mm->event_type= evt->type;
690                 
691                 /* add temp handler */
692                 WM_event_add_modal_handler(C, op);
693                 
694                 /* reset frs delta */
695                 RNA_int_set(op->ptr, "frames", 0);
696                 
697                 return OPERATOR_RUNNING_MODAL;
698         }
699         
700         return OPERATOR_CANCELLED;
701 }
702
703 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
704 {
705         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
706 }
707
708 /* note, init has to be called succesfully */
709 static void ed_marker_move_apply(wmOperator *op)
710 {
711         MarkerMove *mm= op->customdata;
712         TimeMarker *marker;
713         int a, offs;
714         
715         offs= RNA_int_get(op->ptr, "frames");
716         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
717                 if (marker->flag & SELECT) {
718                         marker->frame= mm->oldframe[a] + offs;
719                         a++;
720                 }
721         }
722 }
723
724 /* only for modal */
725 static int ed_marker_move_cancel(bContext *C, wmOperator *op)
726 {
727         RNA_int_set(op->ptr, "frames", 0);
728         ed_marker_move_apply(op);
729         ed_marker_move_exit(C, op);     
730         
731         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
732         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
733
734         return OPERATOR_CANCELLED;
735 }
736
737
738
739 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
740 {
741         Scene *scene= CTX_data_scene(C);
742         MarkerMove *mm= op->customdata;
743         View2D *v2d= UI_view2d_fromcontext(C);
744         TimeMarker *marker, *selmarker=NULL;
745         float dx, fac;
746         char str[256];
747                 
748         switch(evt->type) {
749                 case ESCKEY:
750                         ed_marker_move_cancel(C, op);
751                         return OPERATOR_CANCELLED;
752                 
753                 case RIGHTMOUSE:
754                         /* press = user manually demands transform to be cancelled */
755                         if (evt->val == KM_PRESS) {
756                                 ed_marker_move_cancel(C, op);
757                                 return OPERATOR_CANCELLED;
758                         }
759                         /* else continue; <--- see if release event should be caught for tweak-end */
760                 
761                 case RETKEY:
762                 case PADENTER:
763                 case LEFTMOUSE:
764                 case MIDDLEMOUSE:
765                         if (WM_modal_tweak_exit(evt, mm->event_type)) {
766                                 ed_marker_move_exit(C, op);
767                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
768                                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
769                                 return OPERATOR_FINISHED;
770                         }
771                         break;
772                 case MOUSEMOVE:
773                         if (hasNumInput(&mm->num))
774                                 break;
775                         
776                         dx= v2d->mask.xmax-v2d->mask.xmin;
777                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
778                         
779                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
780                                 int a, offs, totmark=0;
781                                 
782                                 mm->evtx= evt->x;
783                                 
784                                 fac= ((float)(evt->x - mm->firstx)*dx);
785                                 
786                                 if (mm->slink->spacetype == SPACE_TIME) 
787                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
788                                 else
789                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
790                                 
791                                 offs= (int)fac;
792                                 RNA_int_set(op->ptr, "frames", offs);
793                                 ed_marker_move_apply(op);
794                                 
795                                 /* cruft below is for header print */
796                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
797                                         if (marker->flag & SELECT) {
798                                                 selmarker= marker;
799                                                 a++; totmark++;
800                                         }
801                                 }
802                                 
803                                 if (totmark==1) {       
804                                         /* we print current marker value */
805                                         if (mm->slink->spacetype == SPACE_TIME) {
806                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
807                                                 if (stime->flag & TIME_DRAWFRAMES) 
808                                                         BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
809                                                 else 
810                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
811                                         }
812                                         else if (mm->slink->spacetype == SPACE_ACTION) {
813                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
814                                                 if (saction->flag & SACTION_DRAWTIME)
815                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
816                                                 else
817                                                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
818                                         }
819                                         else {
820                                                 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
821                                         }
822                                 }
823                                 else {
824                                         /* we only print the offset */
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 offset %d ", offs);
829                                                 else 
830                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", 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 offset %.2f ", FRA2TIME(offs));
836                                                 else
837                                                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
838                                         }
839                                         else {
840                                                 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
841                                         }
842                                 }
843                                 
844                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
845                                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
846                                 ED_area_headerprint(CTX_wm_area(C), str);
847                         }
848         }
849
850         if (evt->val==KM_PRESS) {
851                 float vec[3];
852                 char str_tx[256];
853                 
854                 if (handleNumInput(&mm->num, evt))
855                 {
856                         applyNumInput(&mm->num, vec);
857                         outputNumInput(&mm->num, str_tx);
858                         
859                         RNA_int_set(op->ptr, "frames", vec[0]);
860                         ed_marker_move_apply(op);
861                         // ed_marker_header_update(C, op, str, (int)vec[0]);
862                         // strcat(str, str_tx);
863                         BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
864                         ED_area_headerprint(CTX_wm_area(C), str);
865                         
866                         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
867                         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
868                 }
869         }
870
871         return OPERATOR_RUNNING_MODAL;
872 }
873
874 static int ed_marker_move_exec(bContext *C, wmOperator *op)
875 {
876         if(ed_marker_move_init(C, op)) {
877                 ed_marker_move_apply(op);
878                 ed_marker_move_exit(C, op);
879                 return OPERATOR_FINISHED;
880         }
881         return OPERATOR_PASS_THROUGH;
882 }
883
884 static void MARKER_OT_move(wmOperatorType *ot)
885 {
886         /* identifiers */
887         ot->name= "Move Time Marker";
888         ot->description= "Move selected time marker(s)";
889         ot->idname= "MARKER_OT_move";
890         
891         /* api callbacks */
892         ot->exec= ed_marker_move_exec;
893         ot->invoke= ed_marker_move_invoke_wrapper;
894         ot->modal= ed_marker_move_modal;
895         ot->poll= ed_markers_poll_selected_markers;
896         ot->cancel= ed_marker_move_cancel;
897         
898         /* flags */
899         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
900         
901         /* rna storage */
902         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
903 }
904
905 /* ************************** duplicate markers *************************** */
906
907 /* operator state vars used:
908  *     frs: delta movement
909  *
910  * functions:
911  *
912  *     apply()  do the actual duplicate
913  *
914  * callbacks:
915  *
916  *     exec()    calls apply, move_exec
917  *
918  *     invoke() calls apply, move_invoke
919  *
920  *     modal()    uses move_modal
921  */
922
923 /* duplicate selected TimeMarkers */
924 static void ed_marker_duplicate_apply(bContext *C)
925 {
926         ListBase *markers= ED_context_get_markers(C);
927         TimeMarker *marker, *newmarker;
928         
929         if (markers == NULL) 
930                 return;
931
932         /* go through the list of markers, duplicate selected markers and add duplicated copies
933          * to the beginning of the list (unselect original markers)
934          */
935         for (marker= markers->first; marker; marker= marker->next) {
936                 if (marker->flag & SELECT) {
937                         /* unselect selected marker */
938                         marker->flag &= ~SELECT;
939                         
940                         /* create and set up new marker */
941                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
942                         newmarker->flag= SELECT;
943                         newmarker->frame= marker->frame;
944                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
945                         
946 #ifdef DURIAN_CAMERA_SWITCH
947                         newmarker->camera= marker->camera;
948 #endif
949
950                         /* new marker is added to the beginning of list */
951                         // FIXME: bad ordering!
952                         BLI_addhead(markers, newmarker);
953                 }
954         }
955 }
956
957 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
958 {
959         ed_marker_duplicate_apply(C);
960         ed_marker_move_exec(C, op);     /* assumes frs delta set */
961         
962         return OPERATOR_FINISHED;
963         
964 }
965
966 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
967 {
968         ed_marker_duplicate_apply(C);
969         return ed_marker_move_invoke(C, op, evt);
970 }
971
972 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
973 {
974         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
975 }
976
977 static void MARKER_OT_duplicate(wmOperatorType *ot)
978 {
979         /* identifiers */
980         ot->name= "Duplicate Time Marker";
981         ot->description= "Duplicate selected time marker(s)";
982         ot->idname= "MARKER_OT_duplicate";
983         
984         /* api callbacks */
985         ot->exec= ed_marker_duplicate_exec;
986         ot->invoke= ed_marker_duplicate_invoke_wrapper;
987         ot->modal= ed_marker_move_modal;
988         ot->poll= ed_markers_poll_selected_markers;
989         ot->cancel= ed_marker_move_cancel;
990         
991         /* flags */
992         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
993         
994         /* rna storage */
995         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
996 }
997
998 /* ************************** selection ************************************/
999
1000 /* select/deselect TimeMarker at current frame */
1001 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
1002 {
1003         TimeMarker *marker;
1004         int select=0;
1005         
1006         for (marker= markers->first; marker; marker= marker->next) {
1007                 /* if Shift is not set, then deselect Markers */
1008                 if (!shift) marker->flag &= ~SELECT;
1009                 
1010                 /* this way a not-shift select will allways give 1 selected marker */
1011                 if ((marker->frame == frame) && (!select)) {
1012                         if (marker->flag & SELECT) 
1013                                 marker->flag &= ~SELECT;
1014                         else
1015                                 marker->flag |= SELECT;
1016                         select = 1;
1017                 }
1018         }
1019 }
1020
1021 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1022 {
1023         ListBase *markers= ED_context_get_markers(C);
1024         View2D *v2d= UI_view2d_fromcontext(C);
1025         float viewx;
1026         int x, y, cfra;
1027         
1028         if (markers == NULL)
1029                 return OPERATOR_PASS_THROUGH;
1030
1031         x= evt->x - CTX_wm_region(C)->winrct.xmin;
1032         y= evt->y - CTX_wm_region(C)->winrct.ymin;
1033         
1034         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
1035         
1036         cfra= ED_markers_find_nearest_marker_time(markers, viewx);
1037         
1038         if (extend)
1039                 select_timeline_marker_frame(markers, cfra, 1);
1040         else
1041                 select_timeline_marker_frame(markers, cfra, 0);
1042         
1043 #ifdef DURIAN_CAMERA_SWITCH
1044
1045         if (camera) {
1046                 Scene *scene= CTX_data_scene(C);
1047                 Base *base;
1048                 TimeMarker *marker;
1049                 int sel= 0;
1050                 
1051                 if (!extend)
1052                         scene_deselect_all(scene);
1053                 
1054                 for (marker= markers->first; marker; marker= marker->next) {
1055                         if(marker->frame==cfra) {
1056                                 sel= (marker->flag & SELECT);
1057                                 break;
1058                         }
1059                 }
1060                 
1061                 for (marker= markers->first; marker; marker= marker->next) {
1062                         if (marker->camera) {
1063                                 if (marker->frame==cfra) {
1064                                         base= object_in_scene(marker->camera, scene);
1065                                         if (base) {
1066                                                 ED_base_object_select(base, sel);
1067                                                 if(sel)
1068                                                         ED_base_object_activate(C, base);
1069                                         }
1070                                 }
1071                         }
1072                 }
1073                 
1074                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1075         }
1076 #else
1077         (void)camera;
1078 #endif
1079
1080         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1081         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1082
1083         /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
1084         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1085 }
1086
1087 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1088 {
1089         short extend= RNA_boolean_get(op->ptr, "extend");
1090         short camera= 0;
1091 #ifdef DURIAN_CAMERA_SWITCH
1092         camera= RNA_boolean_get(op->ptr, "camera");
1093 #endif
1094         return ed_marker_select(C, evt, extend, camera);
1095 }
1096
1097 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1098 {
1099         return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
1100 }
1101
1102 static void MARKER_OT_select(wmOperatorType *ot)
1103 {
1104         /* identifiers */
1105         ot->name= "Select Time Marker";
1106         ot->description= "Select time marker(s)";
1107         ot->idname= "MARKER_OT_select";
1108         
1109         /* api callbacks */
1110         ot->invoke= ed_marker_select_invoke_wrapper;
1111         ot->poll= ed_markers_poll_markers_exist;
1112         
1113         /* flags */
1114         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1115
1116         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1117 #ifdef DURIAN_CAMERA_SWITCH
1118         RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
1119 #endif
1120 }
1121
1122 /* *************************** border select markers **************** */
1123
1124 /* operator state vars used: (added by default WM callbacks)   
1125  * xmin, ymin
1126  * xmax, ymax
1127  *
1128  * customdata: the wmGesture pointer, with subwindow
1129  *
1130  * callbacks:
1131  *
1132  *      exec()  has to be filled in by user
1133  *
1134  *      invoke() default WM function
1135  *                      adds modal handler
1136  *
1137  *      modal() default WM function 
1138  *                      accept modal events while doing it, calls exec(), handles ESC and border drawing
1139  *
1140  *      poll()  has to be filled in by user for context
1141  */
1142
1143 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
1144 {
1145         View2D *v2d= UI_view2d_fromcontext(C);
1146         ListBase *markers= ED_context_get_markers(C);
1147         TimeMarker *marker;
1148         float xminf, xmaxf, yminf, ymaxf;
1149         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1150         int xmin= RNA_int_get(op->ptr, "xmin");
1151         int xmax= RNA_int_get(op->ptr, "xmax");
1152         int ymin= RNA_int_get(op->ptr, "ymin");
1153         int ymax= RNA_int_get(op->ptr, "ymax");
1154         int extend= RNA_boolean_get(op->ptr, "extend");
1155         
1156         UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);      
1157         UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);      
1158         
1159         if (markers == NULL)
1160                 return 0;
1161         
1162         /* XXX marker context */
1163         for (marker= markers->first; marker; marker= marker->next) {
1164                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
1165                         switch (gesture_mode) {
1166                                 case GESTURE_MODAL_SELECT:
1167                                         marker->flag |= SELECT;
1168                                         break;
1169                                 case GESTURE_MODAL_DESELECT:
1170                                         marker->flag &= ~SELECT;
1171                                         break;
1172                         }
1173                 }
1174                 else if (!extend) {
1175                         marker->flag &= ~SELECT;
1176                 }
1177         }
1178         
1179         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1180         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1181
1182         return 1;
1183 }
1184
1185 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1186 {
1187         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
1188 }
1189
1190 static void MARKER_OT_select_border(wmOperatorType *ot)
1191 {
1192         /* identifiers */
1193         ot->name= "Marker Border select";
1194         ot->description= "Select all time markers using border selection";
1195         ot->idname= "MARKER_OT_select_border";
1196         
1197         /* api callbacks */
1198         ot->exec= ed_marker_border_select_exec;
1199         ot->invoke= ed_marker_select_border_invoke_wrapper;
1200         ot->modal= WM_border_select_modal;
1201         ot->cancel= WM_border_select_cancel;
1202         
1203         ot->poll= ed_markers_poll_markers_exist;
1204         
1205         /* flags */
1206         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1207         
1208         /* rna */
1209         WM_operator_properties_gesture_border(ot, TRUE);
1210 }
1211
1212 /* *********************** (de)select all ***************** */
1213
1214 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
1215 {
1216         ListBase *markers= ED_context_get_markers(C);
1217         TimeMarker *marker;
1218         int action = RNA_enum_get(op->ptr, "action");
1219
1220         if (markers == NULL)
1221                 return OPERATOR_CANCELLED;
1222
1223         if (action == SEL_TOGGLE) {
1224                 action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
1225         }
1226         
1227         for(marker= markers->first; marker; marker= marker->next) {
1228                 switch (action) {
1229                 case SEL_SELECT:
1230                         marker->flag |= SELECT;
1231                         break;
1232                 case SEL_DESELECT:
1233                         marker->flag &= ~SELECT;
1234                         break;
1235                 case SEL_INVERT:
1236                         marker->flag ^= SELECT;
1237                         break;
1238                 }
1239         }
1240         
1241         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1242         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1243
1244         return OPERATOR_FINISHED;
1245 }
1246
1247 static void MARKER_OT_select_all(wmOperatorType *ot)
1248 {
1249         /* identifiers */
1250         ot->name= "(De)select all markers";
1251         ot->description= "Change selection of all time markers";
1252         ot->idname= "MARKER_OT_select_all";
1253         
1254         /* api callbacks */
1255         ot->exec= ed_marker_select_all_exec;
1256         ot->invoke = ed_markers_opwrap_invoke;
1257         ot->poll= ed_markers_poll_markers_exist;
1258         
1259         /* flags */
1260         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1261         
1262         /* rna */
1263         WM_operator_properties_select_all(ot);
1264 }
1265
1266 /* ***************** remove marker *********************** */
1267
1268 /* remove selected TimeMarkers */
1269 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
1270 {
1271         ListBase *markers= ED_context_get_markers(C);
1272         TimeMarker *marker, *nmarker;
1273         short changed= 0;
1274         
1275         if (markers == NULL)
1276                 return OPERATOR_CANCELLED;
1277         
1278         for (marker= markers->first; marker; marker= nmarker) {
1279                 nmarker= marker->next;
1280                 if (marker->flag & SELECT) {
1281                         BLI_freelinkN(markers, marker);
1282                         changed= 1;
1283                 }
1284         }
1285         
1286         if (changed) {
1287                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1288                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1289         }
1290         
1291         return OPERATOR_FINISHED;
1292 }
1293
1294 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1295 {
1296         // XXX: must we keep these confirmations?
1297         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
1298 }
1299
1300 static void MARKER_OT_delete(wmOperatorType *ot)
1301 {
1302         /* identifiers */
1303         ot->name= "Delete Markers";
1304         ot->description= "Delete selected time marker(s)";
1305         ot->idname= "MARKER_OT_delete";
1306         
1307         /* api callbacks */
1308         ot->invoke= ed_marker_delete_invoke_wrapper;
1309         ot->exec= ed_marker_delete_exec;
1310         ot->poll= ed_markers_poll_selected_markers;
1311         
1312         /* flags */
1313         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
1314 }
1315
1316
1317 /* **************** rename marker ***************** */
1318
1319 /* rename first selected TimeMarker */
1320 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
1321 {
1322         TimeMarker *marker= ED_markers_get_first_selected(ED_context_get_markers(C));
1323
1324         if (marker) {
1325                 RNA_string_get(op->ptr, "name", marker->name);
1326                 
1327                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1328                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1329                 
1330                 return OPERATOR_FINISHED;
1331         }
1332         else {
1333                 return OPERATOR_CANCELLED;
1334         }
1335 }
1336
1337 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1338 {
1339         /* must initialize the marker name first if there is a marker selected */
1340         TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1341         if (marker)
1342                 RNA_string_set(op->ptr, "name", marker->name);
1343         
1344         /* now see if the operator is usable */
1345         return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
1346 }
1347
1348 static void MARKER_OT_rename(wmOperatorType *ot)
1349 {
1350         /* identifiers */
1351         ot->name= "Rename Marker";
1352         ot->description= "Rename first selected time marker";
1353         ot->idname= "MARKER_OT_rename";
1354         
1355         /* api callbacks */
1356         ot->invoke= ed_marker_rename_invoke_wrapper;
1357         ot->exec= ed_marker_rename_exec;
1358         ot->poll= ed_markers_poll_selected_markers;
1359         
1360         /* flags */
1361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
1362         
1363         /* properties */
1364         ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
1365         //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
1366 }
1367
1368 /* **************** make links to scene ***************** */
1369
1370 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1371 {
1372         ListBase *markers= ED_context_get_markers(C);
1373         Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
1374         TimeMarker *marker, *marker_new;
1375
1376         if (scene_to==NULL) {
1377                 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1378                 return OPERATOR_CANCELLED;
1379         }
1380
1381         if (scene_to == CTX_data_scene(C)) {
1382                 BKE_report(op->reports, RPT_ERROR, "Can't re-link markers into the same scene");
1383                 return OPERATOR_CANCELLED;
1384         }
1385
1386         /* copy markers */
1387         for (marker= markers->first; marker; marker= marker->next) {
1388                 if (marker->flag & SELECT) {
1389                         marker_new= MEM_dupallocN(marker);
1390                         marker_new->prev= marker_new->next = NULL;
1391                         
1392                         BLI_addtail(&scene_to->markers, marker_new);
1393                 }
1394         }
1395
1396         return OPERATOR_FINISHED;
1397 }
1398
1399 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1400 {
1401         PropertyRNA *prop;
1402
1403         /* identifiers */
1404         ot->name= "Make Links to Scene";
1405         ot->description= "Copy selected markers to another scene";
1406         ot->idname= "MARKER_OT_make_links_scene";
1407
1408         /* api callbacks */
1409         ot->exec= ed_marker_make_links_scene_exec;
1410         ot->invoke = ed_markers_opwrap_invoke;
1411         ot->poll= ed_markers_poll_selected_markers;
1412
1413         /* flags */
1414         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1415
1416         /* properties */
1417         prop= RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
1418         RNA_def_enum_funcs(prop, RNA_scene_itemf);
1419         ot->prop= prop;
1420
1421 }
1422
1423 #ifdef DURIAN_CAMERA_SWITCH
1424 /* ******************************* camera bind marker ***************** */
1425
1426 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
1427 {
1428         bScreen *sc= CTX_wm_screen(C);
1429         Scene *scene= CTX_data_scene(C);
1430         Object *ob = CTX_data_active_object(C);
1431         ListBase *markers= ED_context_get_markers(C);
1432         TimeMarker *marker;
1433
1434         marker= ED_markers_get_first_selected(markers);
1435         if(marker == NULL)
1436                 return OPERATOR_CANCELLED;
1437
1438         marker->camera= ob;
1439
1440         /* camera may have changes */
1441         scene_camera_switch_update(scene);
1442         BKE_screen_view3d_scene_sync(sc);
1443
1444         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1445         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1446         WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene); /* so we get view3d redraws */
1447
1448         return OPERATOR_FINISHED;
1449 }
1450
1451 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1452 {
1453         /* identifiers */
1454         ot->name= "Bind Camera to Markers";
1455         ot->description= "Bind the active camera to selected markers(s)";
1456         ot->idname= "MARKER_OT_camera_bind";
1457
1458         /* api callbacks */
1459         ot->exec= ed_marker_camera_bind_exec;
1460         ot->invoke = ed_markers_opwrap_invoke;
1461         ot->poll= ed_markers_poll_selected_markers;
1462
1463         /* flags */
1464         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1465 }
1466 #endif
1467
1468 /* ************************** registration **********************************/
1469
1470 /* called in screen_ops.c:ED_operatortypes_screen() */
1471 void ED_operatortypes_marker(void)
1472 {
1473         WM_operatortype_append(MARKER_OT_add);
1474         WM_operatortype_append(MARKER_OT_move);
1475         WM_operatortype_append(MARKER_OT_duplicate);
1476         WM_operatortype_append(MARKER_OT_select);
1477         WM_operatortype_append(MARKER_OT_select_border);
1478         WM_operatortype_append(MARKER_OT_select_all);
1479         WM_operatortype_append(MARKER_OT_delete);
1480         WM_operatortype_append(MARKER_OT_rename);
1481         WM_operatortype_append(MARKER_OT_make_links_scene);
1482 #ifdef DURIAN_CAMERA_SWITCH
1483         WM_operatortype_append(MARKER_OT_camera_bind);
1484 #endif
1485 }
1486
1487 /* called in screen_ops.c:ED_keymap_screen() */
1488 void ED_marker_keymap(wmKeyConfig *keyconf)
1489 {
1490         wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
1491         wmKeyMapItem *kmi;
1492         
1493         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1494         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1495         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1496         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1497         kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
1498         RNA_boolean_set(kmi->ptr, "extend", TRUE);
1499
1500 #ifdef DURIAN_CAMERA_SWITCH
1501         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1502         RNA_boolean_set(kmi->ptr, "extend", FALSE);
1503         RNA_boolean_set(kmi->ptr, "camera", TRUE);
1504
1505         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1506         RNA_boolean_set(kmi->ptr, "extend", TRUE);
1507         RNA_boolean_set(kmi->ptr, "camera", TRUE);
1508 #else
1509         (void)kmi;
1510 #endif
1511         
1512         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1513         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1514         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1515         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1516         WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1517         
1518         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1519 #ifdef DURIAN_CAMERA_SWITCH
1520         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1521 #endif
1522 }
1523
1524 /* to be called from animation editor keymaps, see note below */
1525 void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
1526 {
1527         /* duplicate of some marker-hotkeys but without the bounds checking
1528          * since these are handy to be able to do unrestricted and won't conflict
1529          * with primary function hotkeys (Usability tweak [#27469])
1530          */
1531         WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1532         WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1533 }