2.5 - Animation Editors - common drawing stuff
[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         /* unselected markers are drawn at the first time */
167         for (marker= markers->first; marker; marker= marker->next) {
168                 if (!(marker->flag & SELECT)) draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
169         }
170         
171         /* selected markers are drawn later */
172         for (marker= markers->first; marker; marker= marker->next) {
173                 if (marker->flag & SELECT) draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
174         }
175 }
176
177
178
179 /* ************************** add markers *************************** */
180
181 /* add TimeMarker at curent frame */
182 static int ed_marker_add(bContext *C, wmOperator *op)
183 {
184         ListBase *markers= context_get_markers(C);
185         TimeMarker *marker;
186         int frame= CTX_data_scene(C)->r.cfra;
187         
188         /* two markers can't be at the same place */
189         for(marker= markers->first; marker; marker= marker->next)
190                 if(marker->frame == frame) 
191                         return OPERATOR_CANCELLED;
192         
193         /* deselect all */
194         for(marker= markers->first; marker; marker= marker->next)
195                 marker->flag &= ~SELECT;
196         
197         marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
198         marker->flag= SELECT;
199         marker->frame= frame;
200         sprintf(marker->name, "Frame %d", frame); // XXX - temp code only
201         BLI_addtail(markers, marker);
202         
203         WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
204         //BIF_undo_push("Add Marker");
205         
206         return OPERATOR_FINISHED;
207 }
208
209 static void ED_MARKER_OT_add(wmOperatorType *ot)
210 {
211         /* identifiers */
212         ot->name= "Add Time Marker";
213         ot->idname= "ED_MARKER_OT_add";
214         
215         /* api callbacks */
216         ot->exec= ed_marker_add;
217         ot->poll= ED_operator_areaactive;
218         
219 }
220
221 /* ************************** transform markers *************************** */
222
223
224 /* operator state vars used:  
225         frs: delta movement
226
227 functions:
228
229         init()   check selection, add customdata with old values and some lookups
230
231         apply()  do the actual movement
232
233         exit()  cleanup, send notifier
234
235     cancel() to escpae from modal
236
237 callbacks:
238
239         exec()  calls init, apply, exit 
240
241         invoke() calls init, adds modal handler
242
243         modal() accept modal events while doing it, ends with apply and exit, or cancel
244
245 */
246
247 typedef struct MarkerMove {
248         SpaceLink *slink;
249         ListBase *markers;
250         int event_type;         /* store invoke-event, to verify */
251         int *oldframe, evtx, firstx;
252 } MarkerMove;
253
254 /* copy selection to temp buffer */
255 /* return 0 if not OK */
256 static int ed_marker_move_init(bContext *C, wmOperator *op)
257 {
258         ListBase *markers= context_get_markers(C);
259         MarkerMove *mm;
260         TimeMarker *marker;
261         int totmark=0;
262         int a;
263         
264         for (marker= markers->first; marker; marker= marker->next)
265                 if (marker->flag & SELECT) totmark++;
266         
267         if (totmark==0) return 0;
268         
269         op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
270         mm->slink= CTX_wm_space_data(C);
271         mm->markers= markers;
272         mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
273         
274         for (a=0, marker= markers->first; marker; marker= marker->next) {
275                 if (marker->flag & SELECT) {
276                         mm->oldframe[a]= marker->frame;
277                         a++;
278                 }
279         }
280         
281         return 1;
282 }
283
284 /* free stuff */
285 static void ed_marker_move_exit(bContext *C, wmOperator *op)
286 {
287         MarkerMove *mm= op->customdata;
288         
289         MEM_freeN(mm->oldframe);
290         MEM_freeN(op->customdata);
291         op->customdata= NULL;
292 }
293
294 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
295 {
296         if(ed_marker_move_init(C, op)) {
297                 MarkerMove *mm= op->customdata;
298                 
299                 mm->evtx= evt->x;
300                 mm->firstx= evt->x;
301                 mm->event_type= evt->type;
302                 
303                 /* add temp handler */
304                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
305                 
306                 /* reset frs delta */
307                 RNA_int_set(op->ptr, "frs", 0);
308                 
309                 return OPERATOR_RUNNING_MODAL;
310         }
311         
312         return OPERATOR_CANCELLED;
313 }
314
315 /* note, init has to be called succesfully */
316 static void ed_marker_move_apply(bContext *C, wmOperator *op)
317 {
318         MarkerMove *mm= op->customdata;
319         TimeMarker *marker;
320         int a, offs;
321         
322         offs= RNA_int_get(op->ptr, "frs");
323         for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
324                 if (marker->flag & SELECT) {
325                         marker->frame= mm->oldframe[a] + offs;
326                         a++;
327                 }
328         }
329 }
330
331 /* only for modal */
332 static void ed_marker_move_cancel(bContext *C, wmOperator *op)
333 {
334         
335         RNA_int_set(op->ptr, "frs", 0);
336         ed_marker_move_apply(C, op);
337         ed_marker_move_exit(C, op);     
338         
339         WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
340 }
341
342
343 /* for tweak handlers, check configuration for how to interpret events */
344 int WM_modal_tweak_check(wmEvent *evt, int tweak_event)
345 {
346         /* user preset?? dunno... */
347         int tweak_modal= 1;
348         
349         switch(tweak_event) {
350                 case EVT_TWEAK_L:
351                 case EVT_TWEAK_M:
352                 case EVT_TWEAK_R:
353                         if(evt->val==tweak_modal)
354                                 return 1;
355                 default:
356                         /* this case is when modal callcback didnt get started with a tweak */
357                         if(evt->val)
358                                 return 1;
359         }
360         return 0;
361 }
362
363 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
364 {
365         MarkerMove *mm= op->customdata;
366         View2D *v2d= UI_view2d_fromcontext(C);
367         TimeMarker *marker, *selmarker=NULL;
368         float dx, fac;
369         char str[256];
370                 
371         switch(evt->type) {
372                 case ESCKEY:
373                         ed_marker_move_cancel(C, op);
374                         return OPERATOR_CANCELLED;
375
376                 case LEFTMOUSE:
377                 case MIDDLEMOUSE:
378                 case RIGHTMOUSE:
379                         if(WM_modal_tweak_check(evt, mm->event_type)) {
380                                 ed_marker_move_exit(C, op);
381                                 WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
382                                 return OPERATOR_FINISHED;
383                         }
384                         
385                         break;
386                 case MOUSEMOVE:
387         
388                         dx= v2d->mask.xmax-v2d->mask.xmin;
389                         dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
390                         
391                         if (evt->x != mm->evtx) {       /* XXX maybe init for firsttime */
392                                 int a, offs, totmark=0;
393                                 
394                                 mm->evtx= evt->x;
395                                 
396                                 fac= ((float)(evt->x - mm->firstx)*dx);
397                                 
398                                 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) 
399                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
400                                 else
401                                         apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
402                                 
403                                 offs= (int)fac;
404                                 RNA_int_set(op->ptr, "frs", offs);
405                                 ed_marker_move_apply(C, op);
406                                 
407                                 /* cruft below is for header print */
408                                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
409                                         if (marker->flag & SELECT) {
410                                                 selmarker= marker;
411                                                 a++; totmark++;
412                                         }
413                                 }
414                                 
415                                 if (totmark==1) {       
416                                         /* we print current marker value */
417                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
418                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
419                                                 if (stime->flag & TIME_DRAWFRAMES) 
420                                                         sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
421                                                 else 
422                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
423                                         }
424                                         else if (mm->slink->spacetype == SPACE_ACTION) {
425 #if 0                                           
426 XXX                                             if (saction->flag & SACTION_DRAWTIME)
427                                                         sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
428                                                 else
429                                                         sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
430 #endif                                  
431                                         }
432                                         else {
433                                                 sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
434                                         }
435                                 }
436                                 else {
437                                         /* we only print the offset */
438                                         if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { 
439                                                 SpaceTime *stime= (SpaceTime *)mm->slink;
440                                                 if (stime->flag & TIME_DRAWFRAMES) 
441                                                         sprintf(str, "Marker offset %d ", offs);
442                                                 else 
443                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
444                                         }
445 #if 0                                   
446 XXX                                     else if (mm->slink->spacetype == SPACE_ACTION) {
447                                                 if (saction->flag & SACTION_DRAWTIME)
448                                                         sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
449                                                 else
450                                                         sprintf(str, "Marker offset %.2f ", (double)(offs));
451                                         }
452 #endif                                  
453                                         else {
454                                                 sprintf(str, "Marker offset %.2f ", (double)(offs));
455                                         }
456                                 }
457                                 
458                                 WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
459                                 // headerprint(str); XXX
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_CANCELLED;
474 }
475
476 static void ED_MARKER_OT_move(wmOperatorType *ot)
477 {
478         /* identifiers */
479         ot->name= "Move Time Marker";
480         ot->idname= "ED_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         /* rna storage */
489         RNA_def_property(ot->srna, "frs", PROP_INT, PROP_NONE);
490 }
491
492 /* ************************** duplicate markers *************************** */
493
494 /* operator state vars used:  
495         frs: delta movement
496
497 functions:
498
499         apply()  do the actual duplicate
500
501 callbacks:
502
503         exec()  calls apply, move_exec
504
505         invoke() calls apply, move_invoke
506
507         modal() uses move_modal
508
509 */
510
511
512 /* duplicate selected TimeMarkers */
513 static void ed_marker_duplicate_apply(bContext *C, wmOperator *op)
514 {
515         ListBase *markers= context_get_markers(C);
516         TimeMarker *marker, *newmarker;
517         
518         /* go through the list of markers, duplicate selected markers and add duplicated copies
519         * to the begining of the list (unselect original markers) */
520         for(marker= markers->first; marker; marker= marker->next) {
521                 if(marker->flag & SELECT){
522                         /* unselect selected marker */
523                         marker->flag &= ~SELECT;
524                         /* create and set up new marker */
525                         newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
526                         newmarker->flag= SELECT;
527                         newmarker->frame= marker->frame;
528                         BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
529                         /* new marker is added to the begining of list */
530                         BLI_addhead(markers, newmarker);
531                 }
532         }
533 }
534
535 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
536 {
537         ed_marker_duplicate_apply(C, op);
538         ed_marker_move_exec(C, op);     /* assumes frs delta set */
539         
540         return OPERATOR_FINISHED;
541         
542 }
543
544 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
545 {
546         ed_marker_duplicate_apply(C, op);
547         return ed_marker_move_invoke(C, op, evt);
548 }
549
550 static void ED_MARKER_OT_duplicate(wmOperatorType *ot)
551 {
552         /* identifiers */
553         ot->name= "Duplicate Time Marker";
554         ot->idname= "ED_MARKER_OT_duplicate";
555         
556         /* api callbacks */
557         ot->exec= ed_marker_duplicate_exec;
558         ot->invoke= ed_marker_duplicate_invoke;
559         ot->modal= ed_marker_move_modal;
560         ot->poll= ED_operator_areaactive;
561         
562         /* rna storage */
563         RNA_def_property(ot->srna, "frs", PROP_INT, PROP_NONE);
564 }
565
566 /* ************************** selection ************************************/
567
568 /* select/deselect TimeMarker at current frame */
569 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
570 {
571         TimeMarker *marker;
572         int select=0;
573         
574         for(marker= markers->first; marker; marker= marker->next) {
575                 /* if Shift is not set, then deselect Markers */
576                 if(!shift) marker->flag &= ~SELECT;
577                 /* this way a not-shift select will allways give 1 selected marker */
578                 if((marker->frame == frame) && (!select)) {
579                         if(marker->flag & SELECT) 
580                                 marker->flag &= ~SELECT;
581                         else
582                                 marker->flag |= SELECT;
583                         select = 1;
584                 }
585         }
586 }
587
588 static int find_nearest_marker_time(ListBase *markers, float dx)
589 {
590         TimeMarker *marker, *nearest= NULL;
591         float dist, min_dist= 1000000;
592         
593         for(marker= markers->first; marker; marker= marker->next) {
594                 dist = ABS((float)marker->frame - dx);
595                 if(dist < min_dist){
596                         min_dist= dist;
597                         nearest= marker;
598                 }
599         }
600         
601         if(nearest) return nearest->frame;
602         else return (int)floor(dx); /* hrmf? */
603 }
604
605
606 static int ed_marker_select(bContext *C, wmEvent *evt, int extend)
607 {
608         ListBase *markers= context_get_markers(C);
609         View2D *v2d= UI_view2d_fromcontext(C);
610         float viewx;
611         int x, y, cfra;
612         
613         x= evt->x - CTX_wm_region(C)->winrct.xmin;
614         y= evt->y - CTX_wm_region(C)->winrct.ymin;
615         
616         UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);      
617         
618         cfra= find_nearest_marker_time(markers, viewx);
619         
620         if (extend)
621                 select_timeline_marker_frame(markers, cfra, 1);
622         else
623                 select_timeline_marker_frame(markers, cfra, 0);
624         
625         WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
626
627         return OPERATOR_PASS_THROUGH;
628 }
629
630 static int ed_marker_select_extend_invoke(bContext *C, wmOperator *op, wmEvent *evt)
631 {
632         return ed_marker_select(C, evt, 1);
633 }
634
635 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
636 {
637         return ed_marker_select(C, evt, 0);
638 }
639
640 static void ED_MARKER_OT_mouseselect(wmOperatorType *ot)
641 {
642         /* identifiers */
643         ot->name= "Select Time Marker";
644         ot->idname= "ED_MARKER_OT_mouseselect";
645         
646         /* api callbacks */
647         ot->invoke= ed_marker_select_invoke;
648         ot->poll= ED_operator_areaactive;
649 }
650
651 static void ED_MARKER_OT_mouseselect_extend(wmOperatorType *ot)
652 {
653         /* identifiers */
654         ot->name= "Extend Select Time Marker";
655         ot->idname= "ED_MARKER_OT_mouseselect_extend";
656         
657         /* api callbacks */
658         ot->invoke= ed_marker_select_extend_invoke;
659         ot->poll= ED_operator_areaactive;
660 }
661
662 /* *************************** border select markers **************** */
663
664 /* operator state vars used: (added by default WM callbacks)   
665         xmin, ymin     
666         xmax, ymax     
667
668 customdata: the wmGesture pointer, with subwindow
669
670 callbacks:
671
672         exec()  has to be filled in by user
673
674         invoke() default WM function
675                         adds modal handler
676
677         modal() default WM function 
678                         accept modal events while doing it, calls exec(), handles ESC and border drawing
679
680         poll()  has to be filled in by user for context
681 */
682
683 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
684 {
685         View2D *v2d= UI_view2d_fromcontext(C);
686         ListBase *markers= context_get_markers(C);
687         TimeMarker *marker;
688         float xminf, xmaxf, yminf, ymaxf;
689         int event_type= RNA_int_get(op->ptr, "event_type");
690         int xmin= RNA_int_get(op->ptr, "xmin");
691         int xmax= RNA_int_get(op->ptr, "xmax");
692         int ymin= RNA_int_get(op->ptr, "ymin");
693         int ymax= RNA_int_get(op->ptr, "ymax");
694         
695         UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);      
696         UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);      
697         
698         /* XXX disputable */
699         if(yminf > 30.0f || ymaxf < 0.0f)
700                 return 0;
701         
702         /* XXX marker context */
703         for(marker= markers->first; marker; marker= marker->next) {
704                 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
705                         switch (event_type) {
706                                 case LEFTMOUSE:
707                                         if ((marker->flag & SELECT) == 0) 
708                                                 marker->flag |= SELECT;
709                                         break;
710                                 case RIGHTMOUSE:
711                                         if (marker->flag & SELECT) 
712                                                 marker->flag &= ~SELECT;
713                                         break;
714                         }
715                 }
716         }
717         
718         WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
719
720         return 1;
721 }
722
723 static void ED_MARKER_OT_border_select(wmOperatorType *ot)
724 {
725         /* identifiers */
726         ot->name= "Marker Border select";
727         ot->idname= "ED_MARKER_OT_border_select";
728         
729         /* api callbacks */
730         ot->exec= ed_marker_border_select_exec;
731         ot->invoke= WM_border_select_invoke;
732         ot->modal= WM_border_select_modal;
733         
734         ot->poll= ED_operator_areaactive;
735         
736         /* rna */
737         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
738         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
739         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
740         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
741         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
742         
743 }
744
745 /* *********************** (de)select all ***************** */
746
747 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
748 {
749         ListBase *markers= context_get_markers(C);
750         TimeMarker *marker;
751         int select= RNA_int_get(op->ptr, "select_type");
752         
753         if(RNA_int_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, WM_NOTE_MARKERS_CHANGED, 0, 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_int_set(op->ptr, "select_swap", 1);
779         
780         return ed_marker_select_all_exec(C, op);
781 }
782
783 static void ED_MARKER_OT_select_all(wmOperatorType *ot)
784 {
785         /* identifiers */
786         ot->name= "(De)select all markers";
787         ot->idname= "ED_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_property(ot->srna, "select_swap", PROP_INT, PROP_NONE);
796         RNA_def_property(ot->srna, "select_type", PROP_INT, PROP_NONE);
797         
798 }
799
800 /* ******************************* remove marker ***************** */
801
802 /* remove selected TimeMarkers */
803 static int ed_marker_delete_exec(bContext *C, wmOperator *op)
804 {
805         ListBase *markers= context_get_markers(C);
806         TimeMarker *marker, *nmarker;
807         short changed= 0;
808         
809         for(marker= markers->first; marker; marker= nmarker) {
810                 nmarker= marker->next;
811                 if(marker->flag & SELECT) {
812                         BLI_freelinkN(markers, marker);
813                         changed= 1;
814                 }
815         }
816         
817         if(changed) {
818                 WM_event_add_notifier(C, WM_NOTE_MARKERS_CHANGED, 0, NULL);
819         }
820         return OPERATOR_FINISHED;
821 }
822
823
824 static void ED_MARKER_OT_delete(wmOperatorType *ot)
825 {
826         /* identifiers */
827         ot->name= "Delete Markers";
828         ot->idname= "ED_MARKER_OT_delete";
829         
830         /* api callbacks */
831         ot->invoke= WM_operator_confirm;
832         ot->exec= ed_marker_delete_exec;
833         ot->poll= ED_operator_areaactive;
834         
835 }
836
837 /* ************************** registration **********************************/
838
839 /* called in screen_ops.c:ED_operatortypes_screen() */
840 void ED_marker_operatortypes(void)
841 {
842         WM_operatortype_append(ED_MARKER_OT_add);
843         WM_operatortype_append(ED_MARKER_OT_move);
844         WM_operatortype_append(ED_MARKER_OT_duplicate);
845         WM_operatortype_append(ED_MARKER_OT_mouseselect);
846         WM_operatortype_append(ED_MARKER_OT_mouseselect_extend);
847         WM_operatortype_append(ED_MARKER_OT_border_select);
848         WM_operatortype_append(ED_MARKER_OT_select_all);
849         WM_operatortype_append(ED_MARKER_OT_delete);
850 }
851
852 /* called in screen_ops.c:ED_keymap_screen() */
853 void ED_marker_keymap(wmWindowManager *wm)
854 {
855         ListBase *keymap= WM_keymap_listbase(wm, "Markers", 0, 0);
856         
857         WM_keymap_verify_item(keymap, "ED_MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
858         WM_keymap_verify_item(keymap, "ED_MARKER_OT_move", EVT_TWEAK_R, KM_ANY, 0, 0);
859         WM_keymap_verify_item(keymap, "ED_MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
860         WM_keymap_verify_item(keymap, "ED_MARKER_OT_mouseselect", RIGHTMOUSE, KM_PRESS, 0, 0);
861         WM_keymap_verify_item(keymap, "ED_MARKER_OT_mouseselect_extend", RIGHTMOUSE, KM_PRESS, KM_SHIFT, 0);
862         WM_keymap_verify_item(keymap, "ED_MARKER_OT_border_select", BKEY, KM_PRESS, 0, 0);
863         WM_keymap_verify_item(keymap, "ED_MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
864         WM_keymap_verify_item(keymap, "ED_MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
865         
866         WM_keymap_add_item(keymap, "ED_MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
867         
868         /* generates event, in end to make select work */
869         WM_keymap_verify_item(keymap, "WM_OT_tweak_gesture", RIGHTMOUSE, KM_PRESS, 0, 0);
870         
871 }