310fa127dcdf0299262e46f7df2e34e959a1473d
[blender-staging.git] / source / blender / editors / animation / anim_markers.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_scene_types.h"
34 #include "DNA_object_types.h"
35
36 #include "RNA_access.h"
37 #include "RNA_define.h"
38 #include "RNA_enum_types.h"
39
40 #include "BLI_blenlib.h"
41
42 #include "BKE_context.h"
43 #include "BKE_fcurve.h"
44 #include "BKE_main.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "BIF_gl.h"
52 #include "BIF_glutil.h"
53
54 #include "UI_interface.h"
55 #include "UI_interface_icons.h"
56 #include "UI_view2d.h"
57 #include "UI_resources.h"
58
59 #include "ED_markers.h"
60 #include "ED_screen.h"
61 #include "ED_util.h"
62 #include "ED_numinput.h"
63 #include "ED_object.h"
64
65 /* ************* Marker API **************** */
66
67 static ListBase *context_get_markers(const bContext *C)
68 {
69         
70 #if 0
71         /* XXX get them from pose */
72         if ((slink->spacetype == SPACE_ACTION) && (saction->flag & SACTION_POSEMARKERS_MOVE)) {
73                 if (saction->action)
74                         markers= &saction->action->markers;
75                 else
76                         markers= NULL;
77         }
78         else
79 #endif
80         
81         return &CTX_data_scene(C)->markers;
82 }
83
84 /* Get the marker that is closest to this point */
85 /* XXX for select, the min_dist should be small */
86 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x) 
87 {
88         TimeMarker *marker, *nearest=NULL;
89         float dist, min_dist= 1000000;
90         
91         if (markers) {
92                 for (marker= markers->first; marker; marker= marker->next) {
93                         dist = ABS((float)marker->frame - x);
94                         
95                         if (dist < min_dist) {
96                                 min_dist= dist;
97                                 nearest= marker;
98                         }
99                 }
100         }
101         
102         return nearest;
103 }
104
105 /* Return the time of the marker that occurs on a frame closest to the given time */
106 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
107 {
108         TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
109         return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
110 }
111
112
113 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
114 {
115         TimeMarker *marker;
116         float min, max;
117         int selcount = 0;
118         
119         /* sanity check */
120         //printf("markers = %p -  %p, %p \n", markers, markers->first, markers->last);
121         if (markers == NULL) {
122                 *first = 0.0f;
123                 *last = 0.0f;
124                 return;
125         }
126         
127         if (markers->first && markers->last) {
128                 TimeMarker *fm= markers->first;
129                 TimeMarker *lm= markers->last;
130                 
131                 min= (float)fm->frame;
132                 max= (float)lm->frame;
133         }
134         else {
135                 *first = 0.0f;
136                 *last = 0.0f;
137                 return;
138         }
139         
140         /* count how many markers are usable - see later */
141         if (sel) {
142                 for (marker= markers->first; marker; marker= marker->next) {
143                         if (marker->flag & SELECT)
144                                 selcount++;
145                 }
146         }
147         else
148                 selcount= BLI_countlist(markers);
149         
150         /* if only selected are to be considered, only consider the selected ones
151          * (optimisation for not searching list) 
152          */
153         if (selcount > 1) {
154                 for (marker= markers->first; marker; marker= marker->next) {
155                         if (sel) {
156                                 if (marker->flag & SELECT) {
157                                         if (marker->frame < min)
158                                                 min= (float)marker->frame;
159                                         if (marker->frame > max)
160                                                 max= (float)marker->frame;
161                                 }
162                         }
163                         else {
164                                 if (marker->frame < min)
165                                         min= (float)marker->frame;
166                                 if (marker->frame > max)
167                                         max= (float)marker->frame;
168                         }       
169                 }
170         }
171         
172         /* set the min/max values */
173         *first= min;
174         *last= max;
175 }
176
177 /* Adds a marker to list of cfra elems */
178 void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
179 {
180         CfraElem *ce, *cen;
181         
182         /* should this one only be considered if it is selected? */
183         if ((only_sel) && ((marker->flag & SELECT)==0))
184                 return;
185         
186         /* insertion sort - try to find a previous cfra elem */
187         for (ce= lb->first; ce; ce= ce->next) {
188                 if (ce->cfra == marker->frame) {
189                         /* do because of double keys */
190                         if (marker->flag & SELECT) 
191                                 ce->sel= marker->flag;
192                         return;
193                 }
194                 else if (ce->cfra > marker->frame) break;
195         }       
196         
197         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
198         if (ce) BLI_insertlinkbefore(lb, ce, cen);
199         else BLI_addtail(lb, cen);
200
201         cen->cfra= marker->frame;
202         cen->sel= marker->flag;
203 }
204
205 /* This function makes a list of all the markers. The only_sel
206  * argument is used to specify whether only the selected markers
207  * are added.
208  */
209 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
210 {
211         TimeMarker *marker;
212         
213         if (markers == NULL)
214                 return;
215         
216         for (marker= markers->first; marker; marker= marker->next)
217                 add_marker_to_cfra_elem(lb, marker, only_sel);
218 }
219
220 /* ************* Marker Drawing ************ */
221
222 /* function to draw markers */
223 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
224 {
225         float xpos, ypixels, xscale, yscale;
226         int icon_id= 0;
227         
228         xpos = marker->frame;
229         
230         /* no time correction for framelen! space is drawn with old values */
231         ypixels= v2d->mask.ymax-v2d->mask.ymin;
232         UI_view2d_getscale(v2d, &xscale, &yscale);
233         
234         glScalef(1.0f/xscale, 1.0f, 1.0f);
235         
236         glEnable(GL_BLEND);
237         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                      
238         
239         /* vertical line - dotted */
240 #ifdef DURIAN_CAMERA_SWITCH
241         if ((marker->camera) || (flag & DRAW_MARKERS_LINES)) {
242 #else
243         if (flag & DRAW_MARKERS_LINES) {
244 #endif
245                 setlinestyle(3);
246                 
247                 if (marker->flag & SELECT)
248                         glColor4ub(255, 255, 255, 96);
249                 else
250                         glColor4ub(0, 0, 0, 96);
251                 
252                 glBegin(GL_LINES);
253                         glVertex2f((xpos*xscale)+0.5f, 12.0f);
254                         glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
255                 glEnd();
256                 
257                 setlinestyle(0);
258         }
259         
260         /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
261         if (flag & DRAW_MARKERS_LOCAL) {
262                 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : 
263                 (marker->flag & SELECT) ? ICON_PMARKER_SEL : 
264                 ICON_PMARKER;
265         }
266         else {
267                 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT : 
268                 ICON_MARKER;
269         }
270         
271         UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
272         
273         glBlendFunc(GL_ONE, GL_ZERO);
274         glDisable(GL_BLEND);
275         
276         /* and the marker name too, shifted slightly to the top-right */
277         if (marker->name && marker->name[0]) {
278                 float x, y;
279                 
280                 if (marker->flag & SELECT) {
281                         UI_ThemeColor(TH_TEXT_HI);
282                         x= xpos*xscale + 4.0f;
283                         y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
284                 }
285                 else {
286                         UI_ThemeColor(TH_TEXT);
287                         if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
288                                 x= xpos*xscale + 4.0f;
289                                 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
290                         }
291                         else {
292                                 x= xpos*xscale + 4.0f;
293                                 y= 17.0f;
294                         }
295                 }
296
297 #ifdef DURIAN_CAMERA_SWITCH
298                 if(marker->camera && marker->camera->restrictflag & OB_RESTRICT_RENDER) {
299                         float col[4];
300                         glGetFloatv(GL_CURRENT_COLOR, col);
301                         col[3]= 0.4;
302                         glColor4fv(col);
303                 }
304 #endif
305
306                 UI_DrawString(x, y, marker->name);
307         }
308         
309         glScalef(xscale, 1.0f, 1.0f);
310 }
311
312 /* Draw Scene-Markers in time window */
313 void draw_markers_time(const bContext *C, int flag)
314 {
315         ListBase *markers= context_get_markers(C);
316         View2D *v2d= UI_view2d_fromcontext(C);
317         TimeMarker *marker;
318         
319         if (markers == NULL)
320                 return;
321         
322         /* unselected markers are drawn at the first time */
323         for (marker= markers->first; marker; marker= marker->next) {
324                 if ((marker->flag & SELECT) == 0) 
325                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
326         }
327         
328         /* selected markers are drawn later */
329         for (marker= markers->first; marker; marker= marker->next) {
330                 if (marker->flag & SELECT) 
331                         draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
332         }
333 }
334
335 /* ************************** add markers *************************** */
336
337 /* add TimeMarker at curent frame */
338 static int ed_marker_add(bContext *C, wmOperator *op)
339 {
340         ListBase *markers= context_get_markers(C);
341         TimeMarker *marker;
342         int frame= CTX_data_scene(C)->r.cfra;
343         
344         if (markers == NULL)
345                 return OPERATOR_CANCELLED;
346         
347         /* two markers can't be at the same place */
348         for (marker= markers->first; marker; marker= marker->next) {
349                 if (marker->frame == frame) 
350                         return OPERATOR_CANCELLED;
351         }
352         
353         /* deselect all */
354         for(marker= markers->first; marker; marker= marker->next)
355                 marker->flag &= ~SELECT;
356         
357         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
358         marker->flag= SELECT;
359         marker->frame= frame;
360         sprintf(marker->name, "F_%02d", frame); // XXX - temp code only
361         BLI_addtail(markers, marker);
362         
363         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
364         
365         return OPERATOR_FINISHED;
366 }
367
368 static void MARKER_OT_add(wmOperatorType *ot)
369 {
370         /* identifiers */
371         ot->name= "Add Time Marker";
372         ot->description= "Add a new time marker";
373         ot->idname= "MARKER_OT_add";
374         
375         /* api callbacks */
376         ot->exec= ed_marker_add;
377         ot->poll= ED_operator_areaactive;
378         
379         /* flags */
380         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
381 }
382
383 /* ************************** transform markers *************************** */
384
385
386 /* operator state vars used:  
387         frs: delta movement
388
389 functions:
390
391         init()   check selection, add customdata with old values and some lookups
392
393         apply()  do the actual movement
394
395         exit()  cleanup, send notifier
396
397     cancel() to escpae from modal
398
399 callbacks:
400
401         exec()  calls init, apply, exit 
402
403         invoke() calls init, adds modal handler
404
405         modal() accept modal events while doing it, ends with apply and exit, or cancel
406
407 */
408
409 typedef struct MarkerMove {
410         SpaceLink *slink;
411         ListBase *markers;
412         int event_type;         /* store invoke-event, to verify */
413         int *oldframe, evtx, firstx;
414         NumInput num;
415 } MarkerMove;
416
417 /* copy selection to temp buffer */
418 /* return 0 if not OK */
419 static int ed_marker_move_init(bContext *C, wmOperator *op)
420 {
421         ListBase *markers= context_get_markers(C);
422         MarkerMove *mm;
423         TimeMarker *marker;
424         int totmark=0;
425         int a;
426
427         if(markers == NULL) return 0;
428         
429         for (marker= markers->first; marker; marker= marker->next)
430                 if (marker->flag & SELECT) totmark++;
431         
432         if (totmark==0) return 0;
433         
434         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
435         mm->slink= CTX_wm_space_data(C);
436         mm->markers= markers;
437         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
438
439         initNumInput(&mm->num);
440         mm->num.idx_max = 0; /* one axis */
441         mm->num.flag |= NUM_NO_FRACTION;
442         mm->num.increment = 1.0f;
443         
444         for (a=0, marker= markers->first; marker; marker= marker->next) {
445                 if (marker->flag & SELECT) {
446                         mm->oldframe[a]= marker->frame;
447                         a++;
448                 }
449         }
450         
451         return 1;
452 }
453
454 /* free stuff */
455 static void ed_marker_move_exit(bContext *C, wmOperator *op)
456 {
457         MarkerMove *mm= op->customdata;
458         
459         /* free data */
460         MEM_freeN(mm->oldframe);
461         MEM_freeN(op->customdata);
462         op->customdata= NULL;
463         
464         /* clear custom header prints */
465         ED_area_headerprint(CTX_wm_area(C), NULL);
466 }
467
468 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
469 {
470         if(ed_marker_move_init(C, op)) {
471                 MarkerMove *mm= op->customdata;
472                 
473                 mm->evtx= evt->x;
474                 mm->firstx= evt->x;
475                 mm->event_type= evt->type;
476                 
477                 /* add temp handler */
478                 WM_event_add_modal_handler(C, op);
479                 
480                 /* reset frs delta */
481                 RNA_int_set(op->ptr, "frames", 0);
482                 
483                 return OPERATOR_RUNNING_MODAL;
484         }
485         
486         return OPERATOR_CANCELLED;
487 }
488
489 /* note, init has to be called succesfully */
490 static void ed_marker_move_apply(bContext *C, wmOperator *op)
491 {
492         MarkerMove *mm= op->customdata;
493         TimeMarker *marker;
494         int a, offs;
495         
496         offs= RNA_int_get(op->ptr, "frames");
497         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
498                 if (marker->flag & SELECT) {
499                         marker->frame= mm->oldframe[a] + offs;
500                         a++;
501                 }
502         }
503 }
504
505 /* only for modal */
506 static void ed_marker_move_cancel(bContext *C, wmOperator *op)
507 {
508         RNA_int_set(op->ptr, "frames", 0);
509         ed_marker_move_apply(C, op);
510         ed_marker_move_exit(C, op);     
511         
512         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
513 }
514
515
516
517 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
518 {
519         Scene *scene= CTX_data_scene(C);
520         MarkerMove *mm= op->customdata;
521         View2D *v2d= UI_view2d_fromcontext(C);
522         TimeMarker *marker, *selmarker=NULL;
523         float dx, fac;
524         char str[256];
525                 
526         switch(evt->type) {
527                 case ESCKEY:
528                         ed_marker_move_cancel(C, op);
529                         return OPERATOR_CANCELLED;
530                 
531                 case RETKEY:
532                 case PADENTER:
533                 case LEFTMOUSE:
534                 case MIDDLEMOUSE:
535                 case RIGHTMOUSE:
536                         if(WM_modal_tweak_exit(evt, mm->event_type)) {
537                                 ed_marker_move_exit(C, op);
538                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
539                                 return OPERATOR_FINISHED;
540                         }
541                         
542                         break;
543                 case MOUSEMOVE:
544                         if(hasNumInput(&mm->num))
545                                 break;
546
547                         dx= v2d->mask.xmax-v2d->mask.xmin;
548                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
549                         
550                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
551                                 int a, offs, totmark=0;
552                                 
553                                 mm->evtx= evt->x;
554                                 
555                                 fac= ((float)(evt->x - mm->firstx)*dx);
556                                 
557                                 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) 
558                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
559                                 else
560                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
561                                 
562                                 offs= (int)fac;
563                                 RNA_int_set(op->ptr, "frames", offs);
564                                 ed_marker_move_apply(C, op);
565                                 
566                                 /* cruft below is for header print */
567                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
568                                         if (marker->flag & SELECT) {
569                                                 selmarker= marker;
570                                                 a++; totmark++;
571                                         }
572                                 }
573                                 
574                                 if (totmark==1) {       
575                                         /* we print current marker value */
576                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
577                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
578                                                 if (stime->flag & TIME_DRAWFRAMES) 
579                                                         sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
580                                                 else 
581                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
582                                         }
583                                         else if (mm->slink->spacetype == SPACE_ACTION) {
584                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
585                                                 if (saction->flag & SACTION_DRAWTIME)
586                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
587                                                 else
588                                                         sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
589                                         }
590                                         else {
591                                                 sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
592                                         }
593                                 }
594                                 else {
595                                         /* we only print the offset */
596                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { 
597                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
598                                                 if (stime->flag & TIME_DRAWFRAMES) 
599                                                         sprintf(str, "Marker offset %d ", offs);
600                                                 else 
601                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
602                                         }
603                                         else if (mm->slink->spacetype == SPACE_ACTION) {
604                                                 SpaceAction *saction= (SpaceAction *)mm->slink;
605                                                 if (saction->flag & SACTION_DRAWTIME)
606                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
607                                                 else
608                                                         sprintf(str, "Marker offset %.2f ", (double)(offs));
609                                         }
610                                         else {
611                                                 sprintf(str, "Marker offset %.2f ", (double)(offs));
612                                         }
613                                 }
614                                 
615                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
616                                 ED_area_headerprint(CTX_wm_area(C), str);
617                         }
618         }
619
620         if(evt->val==KM_PRESS) {
621                 float vec[3];
622                 char str_tx[256];
623
624                 if (handleNumInput(&mm->num, evt))
625                 {
626                         applyNumInput(&mm->num, vec);
627                         outputNumInput(&mm->num, str_tx);
628
629                         RNA_int_set(op->ptr, "frames", vec[0]);
630                         ed_marker_move_apply(C, op);
631                         // ed_marker_header_update(C, op, str, (int)vec[0]);
632                         // strcat(str, str_tx);
633                         sprintf(str, "Marker offset %s", str_tx);
634                         ED_area_headerprint(CTX_wm_area(C), str);
635
636                         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
637                 }
638         }
639
640         return OPERATOR_RUNNING_MODAL;
641 }
642
643 static int ed_marker_move_exec(bContext *C, wmOperator *op)
644 {
645         if(ed_marker_move_init(C, op)) {
646                 ed_marker_move_apply(C, op);
647                 ed_marker_move_exit(C, op);
648                 return OPERATOR_FINISHED;
649         }
650         return OPERATOR_PASS_THROUGH;
651 }
652
653 static void MARKER_OT_move(wmOperatorType *ot)
654 {
655         /* identifiers */
656         ot->name= "Move Time Marker";
657         ot->description= "Move selected time marker(s)";
658         ot->idname= "MARKER_OT_move";
659         
660         /* api callbacks */
661         ot->exec= ed_marker_move_exec;
662         ot->invoke= ed_marker_move_invoke;
663         ot->modal= ed_marker_move_modal;
664         ot->poll= ED_operator_areaactive;
665         
666         /* flags */
667         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
668         
669         /* rna storage */
670         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
671 }
672
673 /* ************************** duplicate markers *************************** */
674
675 /* operator state vars used:  
676         frs: delta movement
677
678 functions:
679
680         apply()  do the actual duplicate
681
682 callbacks:
683
684         exec()  calls apply, move_exec
685
686         invoke() calls apply, move_invoke
687
688         modal() uses move_modal
689
690 */
691
692
693 /* duplicate selected TimeMarkers */
694 static void ed_marker_duplicate_apply(bContext *C, wmOperator *op)
695 {
696         ListBase *markers= context_get_markers(C);
697         TimeMarker *marker, *newmarker;
698         
699         if (markers == NULL) 
700                 return;
701
702         /* go through the list of markers, duplicate selected markers and add duplicated copies
703          * to the begining of the list (unselect original markers) 
704          */
705         for (marker= markers->first; marker; marker= marker->next) {
706                 if (marker->flag & SELECT) {
707                         /* unselect selected marker */
708                         marker->flag &= ~SELECT;
709                         
710                         /* create and set up new marker */
711                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
712                         newmarker->flag= SELECT;
713                         newmarker->frame= marker->frame;
714                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
715                         
716 #ifdef DURIAN_CAMERA_SWITCH
717                         newmarker->camera= marker->camera;
718 #endif
719
720                         /* new marker is added to the begining of list */
721                         BLI_addhead(markers, newmarker);
722                 }
723         }
724 }
725
726 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
727 {
728         ed_marker_duplicate_apply(C, op);
729         ed_marker_move_exec(C, op);     /* assumes frs delta set */
730         
731         return OPERATOR_FINISHED;
732         
733 }
734
735 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
736 {
737         ed_marker_duplicate_apply(C, op);
738         return ed_marker_move_invoke(C, op, evt);
739 }
740
741 static void MARKER_OT_duplicate(wmOperatorType *ot)
742 {
743         /* identifiers */
744         ot->name= "Duplicate Time Marker";
745         ot->description= "Duplicate selected time marker(s)";
746         ot->idname= "MARKER_OT_duplicate";
747         
748         /* api callbacks */
749         ot->exec= ed_marker_duplicate_exec;
750         ot->invoke= ed_marker_duplicate_invoke;
751         ot->modal= ed_marker_move_modal;
752         ot->poll= ED_operator_areaactive;
753         
754         /* flags */
755         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
756         
757         /* rna storage */
758         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
759 }
760
761 /* ************************** selection ************************************/
762
763 /* select/deselect TimeMarker at current frame */
764 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
765 {
766         TimeMarker *marker;
767         int select=0;
768         
769         for (marker= markers->first; marker; marker= marker->next) {
770                 /* if Shift is not set, then deselect Markers */
771                 if (!shift) marker->flag &= ~SELECT;
772                 
773                 /* this way a not-shift select will allways give 1 selected marker */
774                 if ((marker->frame == frame) && (!select)) {
775                         if (marker->flag & SELECT) 
776                                 marker->flag &= ~SELECT;
777                         else
778                                 marker->flag |= SELECT;
779                         select = 1;
780                 }
781         }
782 }
783
784 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
785 {
786         ListBase *markers= context_get_markers(C);
787         View2D *v2d= UI_view2d_fromcontext(C);
788         float viewx;
789         int x, y, cfra;
790         
791         if(markers == NULL)
792                 return OPERATOR_PASS_THROUGH;
793
794         x= evt->x - CTX_wm_region(C)->winrct.xmin;
795         y= evt->y - CTX_wm_region(C)->winrct.ymin;
796         
797         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
798         
799         cfra= ED_markers_find_nearest_marker_time(markers, viewx);
800         
801         if (extend)
802                 select_timeline_marker_frame(markers, cfra, 1);
803         else
804                 select_timeline_marker_frame(markers, cfra, 0);
805         
806 #ifdef DURIAN_CAMERA_SWITCH
807
808         if(camera) {
809                 Scene *scene= CTX_data_scene(C);
810                 Base *base;
811                 TimeMarker *marker;
812                 int sel= 0;
813
814                 if (!extend)
815                         scene_deselect_all(scene);
816
817                 for (marker= markers->first; marker; marker= marker->next) {
818                         if(marker->frame==cfra) {
819                                 sel= (marker->flag & SELECT);
820                                 break;
821                         }
822                 }
823
824                 for (marker= markers->first; marker; marker= marker->next) {
825                         if(marker->camera) {
826                                 if(marker->frame==cfra) {
827                                         base= object_in_scene(marker->camera, scene);
828                                         if(base) {
829                                                 ED_base_object_select(base, sel);
830                                                 if(sel)
831                                                         ED_base_object_activate(C, base);
832                                         }
833                                 }
834                         }
835                 }
836
837                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
838         }
839 #endif
840
841         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
842
843         /* allowing tweaks */
844         return OPERATOR_PASS_THROUGH;
845 }
846
847 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
848 {
849         short extend= RNA_boolean_get(op->ptr, "extend");
850         short camera= 0;
851 #ifdef DURIAN_CAMERA_SWITCH
852         camera= RNA_boolean_get(op->ptr, "camera");
853 #endif
854         return ed_marker_select(C, evt, extend, camera);
855 }
856
857 static void MARKER_OT_select(wmOperatorType *ot)
858 {
859         /* identifiers */
860         ot->name= "Select Time Marker";
861         ot->description= "Select time marker(s)";
862         ot->idname= "MARKER_OT_select";
863         
864         /* api callbacks */
865         ot->invoke= ed_marker_select_invoke;
866         ot->poll= ED_operator_areaactive;
867         
868         /* flags */
869         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
870
871         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
872 #ifdef DURIAN_CAMERA_SWITCH
873         RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
874 #endif
875 }
876
877 /* *************************** border select markers **************** */
878
879 /* operator state vars used: (added by default WM callbacks)   
880         xmin, ymin     
881         xmax, ymax     
882
883 customdata: the wmGesture pointer, with subwindow
884
885 callbacks:
886
887         exec()  has to be filled in by user
888
889         invoke() default WM function
890                         adds modal handler
891
892         modal() default WM function 
893                         accept modal events while doing it, calls exec(), handles ESC and border drawing
894
895         poll()  has to be filled in by user for context
896 */
897
898 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
899 {
900         View2D *v2d= UI_view2d_fromcontext(C);
901         ListBase *markers= context_get_markers(C);
902         TimeMarker *marker;
903         float xminf, xmaxf, yminf, ymaxf;
904         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
905         int xmin= RNA_int_get(op->ptr, "xmin");
906         int xmax= RNA_int_get(op->ptr, "xmax");
907         int ymin= RNA_int_get(op->ptr, "ymin");
908         int ymax= RNA_int_get(op->ptr, "ymax");
909         
910         UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);      
911         UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);      
912         
913         /* XXX disputable */
914         if(yminf > 30.0f || ymaxf < 0.0f)
915                 return 0;
916         
917         if(markers == NULL)
918                 return 0;
919         
920         /* XXX marker context */
921         for(marker= markers->first; marker; marker= marker->next) {
922                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
923                         switch (gesture_mode) {
924                                 case GESTURE_MODAL_SELECT:
925                                         if ((marker->flag & SELECT) == 0) 
926                                                 marker->flag |= SELECT;
927                                         break;
928                                 case GESTURE_MODAL_DESELECT:
929                                         if (marker->flag & SELECT) 
930                                                 marker->flag &= ~SELECT;
931                                         break;
932                         }
933                 }
934         }
935         
936         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
937
938         return 1;
939 }
940
941 static void MARKER_OT_select_border(wmOperatorType *ot)
942 {
943         /* identifiers */
944         ot->name= "Marker Border select";
945         ot->description= "Select all time markers using border selection";
946         ot->idname= "MARKER_OT_select_border";
947         
948         /* api callbacks */
949         ot->exec= ed_marker_border_select_exec;
950         ot->invoke= WM_border_select_invoke;
951         ot->modal= WM_border_select_modal;
952         
953         ot->poll= ED_operator_areaactive;
954         
955         /* flags */
956         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
957         
958         /* rna */
959         WM_operator_properties_gesture_border(ot, FALSE);
960 }
961
962 /* *********************** (de)select all ***************** */
963
964 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
965 {
966         ListBase *markers= context_get_markers(C);
967         TimeMarker *marker;
968         int action = RNA_enum_get(op->ptr, "action");
969
970         if(markers == NULL)
971                 return OPERATOR_CANCELLED;
972
973         if (action == SEL_TOGGLE) {
974                 action = SEL_SELECT;
975                 for(marker= markers->first; marker; marker= marker->next) {
976                         if(marker->flag & SELECT) {
977                                 action = SEL_DESELECT;
978                                 break;
979                         }
980                 }
981         }
982         
983         for(marker= markers->first; marker; marker= marker->next) {
984                 switch (action) {
985                 case SEL_SELECT:
986                         marker->flag |= SELECT;
987                         break;
988                 case SEL_DESELECT:
989                         marker->flag &= ~SELECT;
990                         break;
991                 case SEL_INVERT:
992                         if (marker->flag & SELECT) {
993                                 marker->flag &= ~SELECT;
994                         } else {
995                                 marker->flag |= SELECT;
996                         }
997                         break;
998                 }
999         }
1000         
1001         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1002
1003         return OPERATOR_FINISHED;
1004 }
1005
1006 static void MARKER_OT_select_all(wmOperatorType *ot)
1007 {
1008         /* identifiers */
1009         ot->name= "(De)select all markers";
1010         ot->description= "Change selection of all time markers";
1011         ot->idname= "MARKER_OT_select_all";
1012         
1013         /* api callbacks */
1014         ot->exec= ed_marker_select_all_exec;
1015         ot->poll= ED_operator_areaactive;
1016         
1017         /* flags */
1018         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1019         
1020         /* rna */
1021         WM_operator_properties_select_all(ot);
1022 }
1023
1024 /* ******************************* remove marker ***************** */
1025
1026 /* remove selected TimeMarkers */
1027 static int ed_marker_delete_exec(bContext *C, wmOperator *op)
1028 {
1029         ListBase *markers= context_get_markers(C);
1030         TimeMarker *marker, *nmarker;
1031         short changed= 0;
1032         
1033         if(markers == NULL)
1034                 return OPERATOR_CANCELLED;
1035         
1036         for(marker= markers->first; marker; marker= nmarker) {
1037                 nmarker= marker->next;
1038                 if(marker->flag & SELECT) {
1039                         BLI_freelinkN(markers, marker);
1040                         changed= 1;
1041                 }
1042         }
1043         
1044         if (changed)
1045                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1046         
1047         return OPERATOR_FINISHED;
1048 }
1049
1050
1051 static void MARKER_OT_delete(wmOperatorType *ot)
1052 {
1053         /* identifiers */
1054         ot->name= "Delete Markers";
1055         ot->description= "Delete selected time marker(s)";
1056         ot->idname= "MARKER_OT_delete";
1057         
1058         /* api callbacks */
1059         ot->invoke= WM_operator_confirm;
1060         ot->exec= ed_marker_delete_exec;
1061         ot->poll= ED_operator_areaactive;
1062         
1063         /* flags */
1064         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1065         
1066 }
1067
1068 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1069 {
1070         ListBase *markers= context_get_markers(C);
1071         Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "type"));
1072         TimeMarker *marker, *marker_new;
1073
1074         if(scene_to==NULL) {
1075                 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1076                 return OPERATOR_CANCELLED;
1077         }
1078
1079         if(scene_to == CTX_data_scene(C)) {
1080                 BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
1081                 return OPERATOR_CANCELLED;
1082         }
1083
1084         /* copy markers */
1085         for (marker= markers->first; marker; marker= marker->next) {
1086                 if(marker->flag & SELECT) {
1087                         marker_new= MEM_dupallocN(marker);
1088                         BLI_addtail(&scene_to->markers, marker_new);
1089                 }
1090         }
1091
1092         return OPERATOR_FINISHED;
1093 }
1094
1095 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1096 {
1097         PropertyRNA *prop;
1098
1099         /* identifiers */
1100         ot->name= "Make Links to Scene";
1101         ot->description= "Link markers to another scene";
1102         ot->idname= "MARKER_OT_make_links_scene";
1103
1104         /* api callbacks */
1105         ot->exec= ed_marker_make_links_scene_exec;
1106         ot->poll= ED_operator_areaactive;
1107
1108         /* flags */
1109         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1110
1111         /* properties */
1112         prop= RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", "");
1113         RNA_def_enum_funcs(prop, RNA_scene_itemf);
1114
1115 }
1116
1117 #ifdef DURIAN_CAMERA_SWITCH
1118 /* ******************************* camera bind marker ***************** */
1119
1120 /* remove selected TimeMarkers */
1121 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
1122 {
1123         Scene *scene= CTX_data_scene(C);
1124         ListBase *markers= context_get_markers(C);
1125         TimeMarker *marker;
1126         short changed= 0;
1127
1128         if(markers == NULL)
1129                 return OPERATOR_CANCELLED;
1130
1131         for(marker= markers->first; marker; marker= marker->next) {
1132                 if(marker->flag & SELECT) {
1133                         marker->camera= scene->camera;
1134                 }
1135         }
1136
1137         if (changed)
1138                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1139
1140         return OPERATOR_FINISHED;
1141 }
1142
1143 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1144 {
1145         /* identifiers */
1146         ot->name= "Bind Camera to Markers";
1147         ot->description= "Bind the active camera to selected markers(s)";
1148         ot->idname= "MARKER_OT_camera_bind";
1149
1150         /* api callbacks */
1151         ot->exec= ed_marker_camera_bind_exec;
1152         ot->poll= ED_operator_areaactive;
1153
1154         /* flags */
1155         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1156 }
1157 #endif
1158
1159 /* ************************** registration **********************************/
1160
1161 /* called in screen_ops.c:ED_operatortypes_screen() */
1162 void ED_operatortypes_marker(void)
1163 {
1164         WM_operatortype_append(MARKER_OT_add);
1165         WM_operatortype_append(MARKER_OT_move);
1166         WM_operatortype_append(MARKER_OT_duplicate);
1167         WM_operatortype_append(MARKER_OT_select);
1168         WM_operatortype_append(MARKER_OT_select_border);
1169         WM_operatortype_append(MARKER_OT_select_all);
1170         WM_operatortype_append(MARKER_OT_delete);
1171         WM_operatortype_append(MARKER_OT_make_links_scene);
1172 #ifdef DURIAN_CAMERA_SWITCH
1173         WM_operatortype_append(MARKER_OT_camera_bind);
1174 #endif
1175 }
1176
1177 /* called in screen_ops.c:ED_keymap_screen() */
1178 void ED_marker_keymap(wmKeyConfig *keyconf)
1179 {
1180         wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
1181         wmKeyMapItem *kmi;
1182         
1183         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1184         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1185         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1186         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1187         RNA_boolean_set(WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1188
1189 #ifdef DURIAN_CAMERA_SWITCH
1190         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1191         RNA_boolean_set(kmi->ptr, "camera", 1);
1192
1193         kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1194         RNA_boolean_set(kmi->ptr, "extend", 1);
1195         RNA_boolean_set(kmi->ptr, "camera", 1);
1196 #endif
1197         
1198         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1199         WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1200         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1201         WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1202         
1203         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1204 #ifdef DURIAN_CAMERA_SWITCH
1205         WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
1206 #endif
1207 }