branch from 2.5 for kazanbas
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 <stdlib.h>
30 #include <math.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_scene_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_space_types.h"
37 #include "DNA_view2d_types.h"
38 #include "DNA_userdef_types.h"
39 #include "DNA_windowmanager_types.h"
40
41 #include "RNA_access.h"
42 #include "RNA_define.h"
43
44 #include "BLI_blenlib.h"
45
46 #include "BKE_context.h"
47 #include "BKE_global.h"
48 #include "BKE_utildefines.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "BIF_gl.h"
54 #include "BIF_glutil.h"
55
56 #include "UI_interface.h"
57 #include "UI_interface_icons.h"
58 #include "UI_view2d.h"
59 #include "UI_resources.h"
60
61 #include "ED_markers.h"
62 #include "ED_screen.h"
63 #include "ED_types.h"
64 #include "ED_util.h"
65
66 /* ************* Marker API **************** */
67
68 static ListBase *context_get_markers(const bContext *C)
69 {
70         
71 #if 0
72         /* XXX get them from pose */
73         if ((slink->spacetype == SPACE_ACTION) && (saction->flag & SACTION_POSEMARKERS_MOVE)) {
74                 if (saction->action)
75                         markers= &saction->action->markers;
76                 else
77                         markers= NULL;
78         }
79         else
80 #endif
81         
82         return &CTX_data_scene(C)->markers;
83 }
84
85 /* ************* Marker Drawing ************ */
86
87 /* function to draw markers */
88 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
89 {
90         float xpos, ypixels, xscale, yscale;
91         int icon_id= 0;
92         
93         xpos = marker->frame;
94         
95         /* no time correction for framelen! space is drawn with old values */
96         ypixels= v2d->mask.ymax-v2d->mask.ymin;
97         UI_view2d_getscale(v2d, &xscale, &yscale);
98         
99         glScalef(1.0/xscale, 1.0, 1.0);
100         
101         glEnable(GL_BLEND);
102         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                      
103         
104         /* vertical line - dotted */
105         if (flag & DRAW_MARKERS_LINES) {
106                 setlinestyle(3);
107                 
108                 if (marker->flag & SELECT)
109                         glColor4ub(255, 255, 255, 96);
110                 else
111                         glColor4ub(0, 0, 0, 96);
112                 
113                 glBegin(GL_LINES);
114                         glVertex2f((xpos*xscale)+0.5, 12);
115                         glVertex2f((xpos*xscale)+0.5, 34*yscale); /* a bit lazy but we know it cant be greater then 34 strips high*/
116                 glEnd();
117                 
118                 setlinestyle(0);
119         }
120         
121         /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
122         if (flag & DRAW_MARKERS_LOCAL) {
123                 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : 
124                 (marker->flag & SELECT) ? ICON_PMARKER_SEL : 
125                 ICON_PMARKER;
126         }
127         else {
128                 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT : 
129                 ICON_MARKER;
130         }
131         
132         UI_icon_draw(xpos*xscale-5.0, 16.0, icon_id);
133         
134         glBlendFunc(GL_ONE, GL_ZERO);
135         glDisable(GL_BLEND);
136         
137         /* and the marker name too, shifted slightly to the top-right */
138         if (marker->name && marker->name[0]) {
139                 float x, y;
140                 
141                 if(marker->flag & SELECT) {
142                         UI_ThemeColor(TH_TEXT_HI);
143                         x= xpos*xscale+4.0;
144                         y= (ypixels<=39.0)?(ypixels-10.0):29.0;
145                 }
146                 else {
147                         UI_ThemeColor(TH_TEXT);
148                         if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
149                                 x= xpos*xscale+4.0;
150                                 y= (ypixels<=39.0)?(ypixels-10.0):29.0;
151                         }
152                         else {
153                                 x= xpos*xscale+4.0;
154                                 y= 17.0;
155                         }
156                 }
157                 UI_DrawString(x, y, marker->name);
158         }
159         glScalef(xscale, 1.0, 1.0);
160 }
161
162 /* Draw Scene-Markers in time window */
163 void draw_markers_time(const bContext *C, int flag)
164 {
165         ListBase *markers= context_get_markers(C);
166         View2D *v2d= UI_view2d_fromcontext(C);
167         TimeMarker *marker;
168         
169         if(markers == NULL)
170                 return;
171         
172         /* unselected markers are drawn at the first time */
173         for (marker= markers->first; marker; marker= marker->next) {
174                 if (!(marker->flag & SELECT)) draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
175         }
176         
177         /* selected markers are drawn later */
178         for (marker= markers->first; marker; marker= marker->next) {
179                 if (marker->flag & SELECT) draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
180         }
181 }
182
183
184
185 /* ************************** add markers *************************** */
186
187 /* add TimeMarker at curent frame */
188 static int ed_marker_add(bContext *C, wmOperator *op)
189 {
190         ListBase *markers= context_get_markers(C);
191         TimeMarker *marker;
192         int frame= CTX_data_scene(C)->r.cfra;
193         
194         if(markers == NULL)
195                 return OPERATOR_CANCELLED;
196         
197         /* two markers can't be at the same place */
198         for(marker= markers->first; marker; marker= marker->next)
199                 if(marker->frame == frame) 
200                         return OPERATOR_CANCELLED;
201         
202         /* deselect all */
203         for(marker= markers->first; marker; marker= marker->next)
204                 marker->flag &= ~SELECT;
205         
206         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
207         marker->flag= SELECT;
208         marker->frame= frame;
209         sprintf(marker->name, "Frame %d", frame); // XXX - temp code only
210         BLI_addtail(markers, marker);
211         
212         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
213         
214         return OPERATOR_FINISHED;
215 }
216
217 static void MARKER_OT_add(wmOperatorType *ot)
218 {
219         /* identifiers */
220         ot->name= "Add Time Marker";
221         ot->idname= "MARKER_OT_add";
222         
223         /* api callbacks */
224         ot->exec= ed_marker_add;
225         ot->poll= ED_operator_areaactive;
226         
227         /* flags */
228         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
229 }
230
231 /* ************************** transform markers *************************** */
232
233
234 /* operator state vars used:  
235         frs: delta movement
236
237 functions:
238
239         init()   check selection, add customdata with old values and some lookups
240
241         apply()  do the actual movement
242
243         exit()  cleanup, send notifier
244
245     cancel() to escpae from modal
246
247 callbacks:
248
249         exec()  calls init, apply, exit 
250
251         invoke() calls init, adds modal handler
252
253         modal() accept modal events while doing it, ends with apply and exit, or cancel
254
255 */
256
257 typedef struct MarkerMove {
258         SpaceLink *slink;
259         ListBase *markers;
260         int event_type;         /* store invoke-event, to verify */
261         int *oldframe, evtx, firstx;
262 } MarkerMove;
263
264 /* copy selection to temp buffer */
265 /* return 0 if not OK */
266 static int ed_marker_move_init(bContext *C, wmOperator *op)
267 {
268         ListBase *markers= context_get_markers(C);
269         MarkerMove *mm;
270         TimeMarker *marker;
271         int totmark=0;
272         int a;
273
274         if(markers == NULL) return 0;
275         
276         for (marker= markers->first; marker; marker= marker->next)
277                 if (marker->flag & SELECT) totmark++;
278         
279         if (totmark==0) return 0;
280         
281         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
282         mm->slink= CTX_wm_space_data(C);
283         mm->markers= markers;
284         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
285         
286         for (a=0, marker= markers->first; marker; marker= marker->next) {
287                 if (marker->flag & SELECT) {
288                         mm->oldframe[a]= marker->frame;
289                         a++;
290                 }
291         }
292         
293         return 1;
294 }
295
296 /* free stuff */
297 static void ed_marker_move_exit(bContext *C, wmOperator *op)
298 {
299         MarkerMove *mm= op->customdata;
300         
301         MEM_freeN(mm->oldframe);
302         MEM_freeN(op->customdata);
303         op->customdata= NULL;
304 }
305
306 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
307 {
308         if(ed_marker_move_init(C, op)) {
309                 MarkerMove *mm= op->customdata;
310                 
311                 mm->evtx= evt->x;
312                 mm->firstx= evt->x;
313                 mm->event_type= evt->type;
314                 
315                 /* add temp handler */
316                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
317                 
318                 /* reset frs delta */
319                 RNA_int_set(op->ptr, "frames", 0);
320                 
321                 return OPERATOR_RUNNING_MODAL;
322         }
323         
324         return OPERATOR_CANCELLED;
325 }
326
327 /* note, init has to be called succesfully */
328 static void ed_marker_move_apply(bContext *C, wmOperator *op)
329 {
330         MarkerMove *mm= op->customdata;
331         TimeMarker *marker;
332         int a, offs;
333         
334         offs= RNA_int_get(op->ptr, "frames");
335         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
336                 if (marker->flag & SELECT) {
337                         marker->frame= mm->oldframe[a] + offs;
338                         a++;
339                 }
340         }
341 }
342
343 /* only for modal */
344 static void ed_marker_move_cancel(bContext *C, wmOperator *op)
345 {
346         RNA_int_set(op->ptr, "frames", 0);
347         ed_marker_move_apply(C, op);
348         ed_marker_move_exit(C, op);     
349         
350         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
351 }
352
353
354
355 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
356 {
357         Scene *scene= CTX_data_scene(C);
358         MarkerMove *mm= op->customdata;
359         View2D *v2d= UI_view2d_fromcontext(C);
360         TimeMarker *marker, *selmarker=NULL;
361         float dx, fac;
362         char str[256];
363                 
364         switch(evt->type) {
365                 case ESCKEY:
366                         ed_marker_move_cancel(C, op);
367                         return OPERATOR_CANCELLED;
368
369                 case LEFTMOUSE:
370                 case MIDDLEMOUSE:
371                 case RIGHTMOUSE:
372                         if(WM_modal_tweak_exit(evt, mm->event_type)) {
373                                 ed_marker_move_exit(C, op);
374                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
375                                 return OPERATOR_FINISHED;
376                         }
377                         
378                         break;
379                 case MOUSEMOVE:
380         
381                         dx= v2d->mask.xmax-v2d->mask.xmin;
382                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
383                         
384                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
385                                 int a, offs, totmark=0;
386                                 
387                                 mm->evtx= evt->x;
388                                 
389                                 fac= ((float)(evt->x - mm->firstx)*dx);
390                                 
391                                 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) 
392                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
393                                 else
394                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
395                                 
396                                 offs= (int)fac;
397                                 RNA_int_set(op->ptr, "frames", offs);
398                                 ed_marker_move_apply(C, op);
399                                 
400                                 /* cruft below is for header print */
401                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
402                                         if (marker->flag & SELECT) {
403                                                 selmarker= marker;
404                                                 a++; totmark++;
405                                         }
406                                 }
407                                 
408                                 if (totmark==1) {       
409                                         /* we print current marker value */
410                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
411                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
412                                                 if (stime->flag & TIME_DRAWFRAMES) 
413                                                         sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
414                                                 else 
415                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
416                                         }
417                                         else if (mm->slink->spacetype == SPACE_ACTION) {
418 #if 0                                           
419 XXX                                             if (saction->flag & SACTION_DRAWTIME)
420                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
421                                                 else
422                                                         sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
423 #endif                                  
424                                         }
425                                         else {
426                                                 sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
427                                         }
428                                 }
429                                 else {
430                                         /* we only print the offset */
431                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { 
432                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
433                                                 if (stime->flag & TIME_DRAWFRAMES) 
434                                                         sprintf(str, "Marker offset %d ", offs);
435                                                 else 
436                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
437                                         }
438 #if 0                                   
439 XXX                                     else if (mm->slink->spacetype == SPACE_ACTION) {
440                                                 if (saction->flag & SACTION_DRAWTIME)
441                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
442                                                 else
443                                                         sprintf(str, "Marker offset %.2f ", (double)(offs));
444                                         }
445 #endif                                  
446                                         else {
447                                                 sprintf(str, "Marker offset %.2f ", (double)(offs));
448                                         }
449                                 }
450                                 
451                                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
452                                 // headerprint(str); XXX
453                         }
454         }
455
456         return OPERATOR_RUNNING_MODAL;
457 }
458
459 static int ed_marker_move_exec(bContext *C, wmOperator *op)
460 {
461         if(ed_marker_move_init(C, op)) {
462                 ed_marker_move_apply(C, op);
463                 ed_marker_move_exit(C, op);
464                 return OPERATOR_FINISHED;
465         }
466         return OPERATOR_PASS_THROUGH;
467 }
468
469 static void MARKER_OT_move(wmOperatorType *ot)
470 {
471         /* identifiers */
472         ot->name= "Move Time Marker";
473         ot->idname= "MARKER_OT_move";
474         
475         /* api callbacks */
476         ot->exec= ed_marker_move_exec;
477         ot->invoke= ed_marker_move_invoke;
478         ot->modal= ed_marker_move_modal;
479         ot->poll= ED_operator_areaactive;
480         
481         /* flags */
482         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
483         
484         /* rna storage */
485         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
486 }
487
488 /* ************************** duplicate markers *************************** */
489
490 /* operator state vars used:  
491         frs: delta movement
492
493 functions:
494
495         apply()  do the actual duplicate
496
497 callbacks:
498
499         exec()  calls apply, move_exec
500
501         invoke() calls apply, move_invoke
502
503         modal() uses move_modal
504
505 */
506
507
508 /* duplicate selected TimeMarkers */
509 static void ed_marker_duplicate_apply(bContext *C, wmOperator *op)
510 {
511         ListBase *markers= context_get_markers(C);
512         TimeMarker *marker, *newmarker;
513         
514         if(markers == NULL) return;
515
516         /* go through the list of markers, duplicate selected markers and add duplicated copies
517         * to the begining of the list (unselect original markers) */
518         for(marker= markers->first; marker; marker= marker->next) {
519                 if(marker->flag & SELECT){
520                         /* unselect selected marker */
521                         marker->flag &= ~SELECT;
522                         /* create and set up new marker */
523                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
524                         newmarker->flag= SELECT;
525                         newmarker->frame= marker->frame;
526                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
527                         /* new marker is added to the begining of list */
528                         BLI_addhead(markers, newmarker);
529                 }
530         }
531 }
532
533 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
534 {
535         ed_marker_duplicate_apply(C, op);
536         ed_marker_move_exec(C, op);     /* assumes frs delta set */
537         
538         return OPERATOR_FINISHED;
539         
540 }
541
542 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
543 {
544         ed_marker_duplicate_apply(C, op);
545         return ed_marker_move_invoke(C, op, evt);
546 }
547
548 static void MARKER_OT_duplicate(wmOperatorType *ot)
549 {
550         /* identifiers */
551         ot->name= "Duplicate Time Marker";
552         ot->idname= "MARKER_OT_duplicate";
553         
554         /* api callbacks */
555         ot->exec= ed_marker_duplicate_exec;
556         ot->invoke= ed_marker_duplicate_invoke;
557         ot->modal= ed_marker_move_modal;
558         ot->poll= ED_operator_areaactive;
559         
560         /* flags */
561         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
562         
563         /* rna storage */
564         RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
565 }
566
567 /* ************************** selection ************************************/
568
569 /* select/deselect TimeMarker at current frame */
570 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
571 {
572         TimeMarker *marker;
573         int select=0;
574         
575         for(marker= markers->first; marker; marker= marker->next) {
576                 /* if Shift is not set, then deselect Markers */
577                 if(!shift) marker->flag &= ~SELECT;
578                 /* this way a not-shift select will allways give 1 selected marker */
579                 if((marker->frame == frame) && (!select)) {
580                         if(marker->flag & SELECT) 
581                                 marker->flag &= ~SELECT;
582                         else
583                                 marker->flag |= SELECT;
584                         select = 1;
585                 }
586         }
587 }
588
589 int find_nearest_marker_time(ListBase *markers, float dx)
590 {
591         TimeMarker *marker, *nearest= NULL;
592         float dist, min_dist= 1000000;
593         
594         for(marker= markers->first; marker; marker= marker->next) {
595                 dist = ABS((float)marker->frame - dx);
596                 if(dist < min_dist){
597                         min_dist= dist;
598                         nearest= marker;
599                 }
600         }
601         
602         if(nearest) return nearest->frame;
603         else return (int)floor(dx); /* hrmf? */
604 }
605
606
607 static int ed_marker_select(bContext *C, wmEvent *evt, int extend)
608 {
609         ListBase *markers= context_get_markers(C);
610         View2D *v2d= UI_view2d_fromcontext(C);
611         float viewx;
612         int x, y, cfra;
613         
614         if(markers == NULL)
615                 return OPERATOR_PASS_THROUGH;
616
617         x= evt->x - CTX_wm_region(C)->winrct.xmin;
618         y= evt->y - CTX_wm_region(C)->winrct.ymin;
619         
620         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
621         
622         cfra= find_nearest_marker_time(markers, viewx);
623         
624         if (extend)
625                 select_timeline_marker_frame(markers, cfra, 1);
626         else
627                 select_timeline_marker_frame(markers, cfra, 0);
628         
629         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
630
631         /* allowing tweaks */
632         return OPERATOR_PASS_THROUGH;
633 }
634
635 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
636 {
637         short extend= RNA_boolean_get(op->ptr, "extend");
638         return ed_marker_select(C, evt, extend);
639 }
640
641 static void MARKER_OT_select(wmOperatorType *ot)
642 {
643         /* identifiers */
644         ot->name= "Select Time Marker";
645         ot->idname= "MARKER_OT_select";
646         
647         /* api callbacks */
648         ot->invoke= ed_marker_select_invoke;
649         ot->poll= ED_operator_areaactive;
650         
651         /* flags */
652         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
653
654         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
655 }
656
657 /* *************************** border select markers **************** */
658
659 /* operator state vars used: (added by default WM callbacks)   
660         xmin, ymin     
661         xmax, ymax     
662
663 customdata: the wmGesture pointer, with subwindow
664
665 callbacks:
666
667         exec()  has to be filled in by user
668
669         invoke() default WM function
670                         adds modal handler
671
672         modal() default WM function 
673                         accept modal events while doing it, calls exec(), handles ESC and border drawing
674
675         poll()  has to be filled in by user for context
676 */
677
678 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
679 {
680         View2D *v2d= UI_view2d_fromcontext(C);
681         ListBase *markers= context_get_markers(C);
682         TimeMarker *marker;
683         float xminf, xmaxf, yminf, ymaxf;
684         int event_type= RNA_int_get(op->ptr, "event_type");
685         int xmin= RNA_int_get(op->ptr, "xmin");
686         int xmax= RNA_int_get(op->ptr, "xmax");
687         int ymin= RNA_int_get(op->ptr, "ymin");
688         int ymax= RNA_int_get(op->ptr, "ymax");
689         
690         UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);      
691         UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);      
692         
693         /* XXX disputable */
694         if(yminf > 30.0f || ymaxf < 0.0f)
695                 return 0;
696         
697         if(markers == NULL)
698                 return 0;
699         
700         /* XXX marker context */
701         for(marker= markers->first; marker; marker= marker->next) {
702                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
703                         switch (event_type) {
704                                 case LEFTMOUSE:
705                                         if ((marker->flag & SELECT) == 0) 
706                                                 marker->flag |= SELECT;
707                                         break;
708                                 case RIGHTMOUSE:
709                                         if (marker->flag & SELECT) 
710                                                 marker->flag &= ~SELECT;
711                                         break;
712                         }
713                 }
714         }
715         
716         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
717
718         return 1;
719 }
720
721 static void MARKER_OT_select_border(wmOperatorType *ot)
722 {
723         /* identifiers */
724         ot->name= "Marker Border select";
725         ot->idname= "MARKER_OT_select_border";
726         
727         /* api callbacks */
728         ot->exec= ed_marker_border_select_exec;
729         ot->invoke= WM_border_select_invoke;
730         ot->modal= WM_border_select_modal;
731         
732         ot->poll= ED_operator_areaactive;
733         
734         /* flags */
735         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
736         
737         /* rna */
738         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
739         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
740         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
741         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
742         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
743 }
744
745 /* *********************** (de)select all ***************** */
746
747 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
748 {
749         ListBase *markers= context_get_markers(C);
750         TimeMarker *marker;
751         int select= RNA_int_get(op->ptr, "select_type");
752
753         if(markers == NULL)
754                 return OPERATOR_CANCELLED;
755         
756         if(RNA_boolean_get(op->ptr, "select_swap")) {
757                 for(marker= markers->first; marker; marker= marker->next) {
758                         if(marker->flag & SELECT)
759                                 break;
760                 }
761                 if(marker)
762                         select= 0;
763                 else
764                         select= 1;
765         }
766         
767         for(marker= markers->first; marker; marker= marker->next) {
768                 if(select)
769                         marker->flag |= SELECT;
770                 else
771                         marker->flag &= ~SELECT;
772         }
773         
774         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
775
776         return OPERATOR_FINISHED;
777 }
778
779 static int ed_marker_select_all_invoke(bContext *C, wmOperator *op, wmEvent *evt)
780 {
781         RNA_boolean_set(op->ptr, "select_swap", 1);
782         
783         return ed_marker_select_all_exec(C, op);
784 }
785
786 static void MARKER_OT_select_all_toggle(wmOperatorType *ot)
787 {
788         /* identifiers */
789         ot->name= "(De)select all markers";
790         ot->idname= "MARKER_OT_select_all_toggle";
791         
792         /* api callbacks */
793         ot->exec= ed_marker_select_all_exec;
794         ot->invoke= ed_marker_select_all_invoke;
795         ot->poll= ED_operator_areaactive;
796         
797         /* flags */
798         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
799         
800         /* rna */
801         RNA_def_boolean(ot->srna, "select_swap", 0, "Select Swap", "");
802         RNA_def_int(ot->srna, "select_type", 0, INT_MIN, INT_MAX, "Select Type", "", INT_MIN, INT_MAX);
803 }
804
805 /* ******************************* remove marker ***************** */
806
807 /* remove selected TimeMarkers */
808 static int ed_marker_delete_exec(bContext *C, wmOperator *op)
809 {
810         ListBase *markers= context_get_markers(C);
811         TimeMarker *marker, *nmarker;
812         short changed= 0;
813         
814         if(markers == NULL)
815                 return OPERATOR_CANCELLED;
816         
817         for(marker= markers->first; marker; marker= nmarker) {
818                 nmarker= marker->next;
819                 if(marker->flag & SELECT) {
820                         BLI_freelinkN(markers, marker);
821                         changed= 1;
822                 }
823         }
824         
825         if(changed) {
826                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
827         }
828         return OPERATOR_FINISHED;
829 }
830
831
832 static void MARKER_OT_delete(wmOperatorType *ot)
833 {
834         /* identifiers */
835         ot->name= "Delete Markers";
836         ot->idname= "MARKER_OT_delete";
837         
838         /* api callbacks */
839         ot->invoke= WM_operator_confirm;
840         ot->exec= ed_marker_delete_exec;
841         ot->poll= ED_operator_areaactive;
842         
843         /* flags */
844         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
845         
846 }
847
848 /* ************************** registration **********************************/
849
850 /* called in screen_ops.c:ED_operatortypes_screen() */
851 void ED_marker_operatortypes(void)
852 {
853         WM_operatortype_append(MARKER_OT_add);
854         WM_operatortype_append(MARKER_OT_move);
855         WM_operatortype_append(MARKER_OT_duplicate);
856         WM_operatortype_append(MARKER_OT_select);
857         WM_operatortype_append(MARKER_OT_select_border);
858         WM_operatortype_append(MARKER_OT_select_all_toggle);
859         WM_operatortype_append(MARKER_OT_delete);
860 }
861
862 /* called in screen_ops.c:ED_keymap_screen() */
863 void ED_marker_keymap(wmWindowManager *wm)
864 {
865         ListBase *keymap= WM_keymap_listbase(wm, "Markers", 0, 0);
866         
867         WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
868         WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
869         WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
870         WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
871         RNA_boolean_set(WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
872         WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
873         WM_keymap_verify_item(keymap, "MARKER_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
874         WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
875         
876         WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
877         
878 }