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