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