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