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