Camera tracking integration
[blender.git] / source / blender / editors / space_clip / clip_ops.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * Contributor(s): Blender Foundation,
25  *                 Sergey Sharybin
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <errno.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_userdef_types.h"
35 #include "DNA_scene_types.h"    /* min/max frames */
36
37 #include "BLI_utildefines.h"
38 #include "BLI_math.h"
39
40 #include "BKE_context.h"
41 #include "BKE_global.h"
42 #include "BKE_report.h"
43 #include "BKE_main.h"
44 #include "BKE_library.h"
45 #include "BKE_movieclip.h"
46 #include "BKE_sound.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "ED_screen.h"
52 #include "ED_clip.h"
53
54 #include "UI_interface.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58
59 #include "clip_intern.h"        // own include
60
61 /** \file blender/editors/space_clip/clip_ops.c
62  *  \ingroup spclip
63  */
64
65 /******************** view navigation utilities *********************/
66
67 static void sclip_zoom_set(SpaceClip *sc, ARegion *ar, float zoom)
68 {
69         float oldzoom= sc->zoom;
70         int width, height;
71
72         sc->zoom= zoom;
73
74         if (sc->zoom > 0.1f && sc->zoom < 4.0f)
75                 return;
76
77         /* check zoom limits */
78         ED_space_clip_size(sc, &width, &height);
79
80         width*= sc->zoom;
81         height*= sc->zoom;
82
83         if((width < 4) && (height < 4))
84                 sc->zoom= oldzoom;
85         else if((ar->winrct.xmax - ar->winrct.xmin) <= sc->zoom)
86                 sc->zoom= oldzoom;
87         else if((ar->winrct.ymax - ar->winrct.ymin) <= sc->zoom)
88                 sc->zoom= oldzoom;
89 }
90
91 static void sclip_zoom_set_factor(SpaceClip *sc, ARegion *ar, float zoomfac)
92 {
93         sclip_zoom_set(sc, ar, sc->zoom*zoomfac);
94 }
95
96
97 /******************** open clip operator ********************/
98
99 static void clip_filesel(bContext *C, wmOperator *op, const char *path)
100 {
101         RNA_string_set(op->ptr, "filepath", path);
102         WM_event_add_fileselect(C, op);
103 }
104
105 static void open_init(bContext *C, wmOperator *op)
106 {
107         PropertyPointerRNA *pprop;
108
109         op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
110         uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
111 }
112
113 static int open_cancel(bContext *UNUSED(C), wmOperator *op)
114 {
115         MEM_freeN(op->customdata);
116         op->customdata= NULL;
117
118         return OPERATOR_CANCELLED;
119 }
120
121 static int open_exec(bContext *C, wmOperator *op)
122 {
123         SpaceClip *sc= CTX_wm_space_clip(C);
124         PropertyPointerRNA *pprop;
125         PointerRNA idptr;
126         MovieClip *clip= NULL;
127         char str[FILE_MAX];
128
129         RNA_string_get(op->ptr, "filepath", str);
130         /* default to frame 1 if there's no scene in context */
131
132         errno= 0;
133
134         clip= BKE_add_movieclip_file(str);
135
136         if(!clip) {
137                 if(op->customdata)
138                         MEM_freeN(op->customdata);
139
140                 BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", str, errno ? strerror(errno) : "Unsupported movie clip format");
141
142                 return OPERATOR_CANCELLED;
143         }
144
145         if(!op->customdata)
146                 open_init(C, op);
147
148         /* hook into UI */
149         pprop= op->customdata;
150
151         if(pprop->prop) {
152                 /* when creating new ID blocks, use is already 1, but RNA
153                  * pointer se also increases user, so this compensates it */
154                 clip->id.us--;
155
156                 RNA_id_pointer_create(&clip->id, &idptr);
157                 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
158                 RNA_property_update(C, &pprop->ptr, pprop->prop);
159         }
160         else if(sc) {
161                 ED_space_clip_set(C, sc, clip);
162         }
163
164         WM_event_add_notifier(C, NC_MOVIECLIP|NA_ADDED, clip);
165
166         MEM_freeN(op->customdata);
167
168         return OPERATOR_FINISHED;
169 }
170
171 static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
172 {
173         SpaceClip *sc= CTX_wm_space_clip(C);
174         char *path= U.textudir;
175         MovieClip *clip= NULL;
176
177         if(sc)
178                 clip= ED_space_clip(sc);
179
180         if(clip)
181                 path= clip->name;
182
183         if(!RNA_property_is_set(op->ptr, "relative_path"))
184                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
185
186         if(RNA_property_is_set(op->ptr, "filepath"))
187                 return open_exec(C, op);
188
189         open_init(C, op);
190
191         clip_filesel(C, op, path);
192
193         return OPERATOR_RUNNING_MODAL;
194 }
195
196 void CLIP_OT_open(wmOperatorType *ot)
197 {
198         /* identifiers */
199         ot->name= "Open Clip";
200         ot->description= "Open clip";
201         ot->idname= "CLIP_OT_open";
202
203         /* api callbacks */
204         ot->exec= open_exec;
205         ot->invoke= open_invoke;
206         ot->cancel= open_cancel;
207
208         /* flags */
209         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
210
211         /* properties */
212         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
213 }
214
215 /******************* reload clip operator *********************/
216
217 static int reload_exec(bContext *C, wmOperator *UNUSED(op))
218 {
219         SpaceClip *sc= CTX_wm_space_clip(C);
220         MovieClip *clip= CTX_data_edit_movieclip(C);
221
222         if(!clip)
223                 return OPERATOR_CANCELLED;
224
225         sc->scopes.ok= 0;
226
227         BKE_movieclip_reload(clip);
228
229         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
230
231         return OPERATOR_FINISHED;
232 }
233
234 void CLIP_OT_reload(wmOperatorType *ot)
235 {
236         /* identifiers */
237         ot->name= "Reload Clip";
238         ot->description= "Reload clip";
239         ot->idname= "CLIP_OT_reload";
240
241         /* api callbacks */
242         ot->exec= reload_exec;
243 }
244
245 /******************* delete operator *********************/
246
247 #if 0
248 static int unlink_poll(bContext *C)
249 {
250         /* it should be possible to unlink clips if they're lib-linked in... */
251         return CTX_data_edit_movieclip(C) != NULL;
252 }
253
254 static int unlink_exec(bContext *C, wmOperator *UNUSED(op))
255 {
256         Main *bmain= CTX_data_main(C);
257         SpaceClip *sc= CTX_wm_space_clip(C);
258         MovieClip *clip= CTX_data_edit_movieclip(C);
259
260         if(!clip) {
261                 return OPERATOR_CANCELLED;
262         }
263
264         /* make the previous text active, if its not there make the next text active */
265         if(sc) {
266                 if(clip->id.prev) ED_space_clip_set(C, sc, clip->id.prev);
267                 else if(clip->id.next) ED_space_clip_set(C, sc, clip->id.next);
268         }
269
270         unlink_movieclip(bmain, clip);
271         free_libblock(&bmain->movieclip, clip);
272
273         WM_event_add_notifier(C, NC_MOVIECLIP|NA_REMOVED, NULL);
274
275         return OPERATOR_FINISHED;
276 }
277
278 void CLIP_OT_unlink(wmOperatorType *ot)
279 {
280         /* identifiers */
281         ot->name= "Unlink";
282         ot->idname= "CLIP_OT_unlink";
283         ot->description= "Unlink active clip data block";
284
285         /* api callbacks */
286         ot->exec= unlink_exec;
287         ot->invoke= WM_operator_confirm;
288         ot->poll= unlink_poll;
289
290         /* flags */
291         ot->flag= OPTYPE_UNDO;
292 }
293 #endif
294
295 /********************** view pan operator *********************/
296
297 typedef struct ViewPanData {
298         float x, y;
299         float xof, yof;
300         int event_type;
301 } ViewPanData;
302
303 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
304 {
305         SpaceClip *sc= CTX_wm_space_clip(C);
306         ViewPanData *vpd;
307
308         op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ClipViewPanData");
309         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
310
311         vpd->x= event->x;
312         vpd->y= event->y;
313         vpd->xof= sc->xof;
314         vpd->yof= sc->yof;
315         vpd->event_type= event->type;
316
317         WM_event_add_modal_handler(C, op);
318 }
319
320 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
321 {
322         SpaceClip *sc= CTX_wm_space_clip(C);
323         ViewPanData *vpd= op->customdata;
324
325         if(cancel) {
326                 sc->xof= vpd->xof;
327                 sc->yof= vpd->yof;
328                 ED_region_tag_redraw(CTX_wm_region(C));
329         }
330
331         WM_cursor_restore(CTX_wm_window(C));
332         MEM_freeN(op->customdata);
333 }
334
335 static int view_pan_exec(bContext *C, wmOperator *op)
336 {
337         SpaceClip *sc= CTX_wm_space_clip(C);
338         float offset[2];
339
340         RNA_float_get_array(op->ptr, "offset", offset);
341         sc->xof += offset[0];
342         sc->yof += offset[1];
343
344         ED_region_tag_redraw(CTX_wm_region(C));
345
346         return OPERATOR_FINISHED;
347 }
348
349 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
350 {
351         if (event->type==MOUSEPAN) {
352                 SpaceClip *sc= CTX_wm_space_clip(C);
353                 float offset[2];
354
355                 offset[0]= (event->x - event->prevx)/sc->zoom;
356                 offset[1]= (event->y - event->prevy)/sc->zoom;
357                 RNA_float_set_array(op->ptr, "offset", offset);
358
359                 view_pan_exec(C, op);
360                 return OPERATOR_FINISHED;
361         }
362         else {
363                 view_pan_init(C, op, event);
364                 return OPERATOR_RUNNING_MODAL;
365         }
366 }
367
368 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
369 {
370         SpaceClip *sc= CTX_wm_space_clip(C);
371         ViewPanData *vpd= op->customdata;
372         float offset[2];
373
374         switch(event->type) {
375                 case MOUSEMOVE:
376                         sc->xof= vpd->xof;
377                         sc->yof= vpd->yof;
378                         offset[0]= (vpd->x - event->x)/sc->zoom;
379                         offset[1]= (vpd->y - event->y)/sc->zoom;
380                         RNA_float_set_array(op->ptr, "offset", offset);
381                         view_pan_exec(C, op);
382                         break;
383                 default:
384                         if(event->type==vpd->event_type &&  event->val==KM_RELEASE) {
385                                 view_pan_exit(C, op, 0);
386                                 return OPERATOR_FINISHED;
387                         }
388                         break;
389         }
390
391         return OPERATOR_RUNNING_MODAL;
392 }
393
394 static int view_pan_cancel(bContext *C, wmOperator *op)
395 {
396         view_pan_exit(C, op, 1);
397         return OPERATOR_CANCELLED;
398 }
399
400 void CLIP_OT_view_pan(wmOperatorType *ot)
401 {
402         /* identifiers */
403         ot->name= "View Pan";
404         ot->idname= "CLIP_OT_view_pan";
405
406         /* api callbacks */
407         ot->exec= view_pan_exec;
408         ot->invoke= view_pan_invoke;
409         ot->modal= view_pan_modal;
410         ot->cancel= view_pan_cancel;
411         ot->poll= ED_space_clip_poll;
412
413         /* flags */
414         ot->flag= OPTYPE_BLOCKING;
415
416         /* properties */
417         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
418                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
419 }
420
421 /********************** view zoom operator *********************/
422
423 typedef struct ViewZoomData {
424         float x, y;
425         float zoom;
426         int event_type;
427 } ViewZoomData;
428
429 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
430 {
431         SpaceClip *sc= CTX_wm_space_clip(C);
432         ViewZoomData *vpd;
433
434         op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ClipViewZoomData");
435         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
436
437         vpd->x= event->x;
438         vpd->y= event->y;
439         vpd->zoom= sc->zoom;
440         vpd->event_type= event->type;
441
442         WM_event_add_modal_handler(C, op);
443 }
444
445 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
446 {
447         SpaceClip *sc= CTX_wm_space_clip(C);
448         ViewZoomData *vpd= op->customdata;
449
450         if(cancel) {
451                 sc->zoom= vpd->zoom;
452                 ED_region_tag_redraw(CTX_wm_region(C));
453         }
454
455         WM_cursor_restore(CTX_wm_window(C));
456         MEM_freeN(op->customdata);
457 }
458
459 static int view_zoom_exec(bContext *C, wmOperator *op)
460 {
461         SpaceClip *sc= CTX_wm_space_clip(C);
462         ARegion *ar= CTX_wm_region(C);
463
464         sclip_zoom_set_factor(sc, ar, RNA_float_get(op->ptr, "factor"));
465
466         ED_region_tag_redraw(CTX_wm_region(C));
467
468         return OPERATOR_FINISHED;
469 }
470
471 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
472 {
473         if (event->type==MOUSEZOOM) {
474                 SpaceClip *sc= CTX_wm_space_clip(C);
475                 ARegion *ar= CTX_wm_region(C);
476                 float factor;
477
478                 factor= 1.0f + (event->x-event->prevx+event->y-event->prevy)/300.0f;
479                 RNA_float_set(op->ptr, "factor", factor);
480                 sclip_zoom_set(sc, ar, sc->zoom*factor);
481                 ED_region_tag_redraw(CTX_wm_region(C));
482
483                 return OPERATOR_FINISHED;
484         }
485         else {
486                 view_zoom_init(C, op, event);
487                 return OPERATOR_RUNNING_MODAL;
488         }
489 }
490
491 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
492 {
493         SpaceClip *sc= CTX_wm_space_clip(C);
494         ARegion *ar= CTX_wm_region(C);
495         ViewZoomData *vpd= op->customdata;
496         float factor;
497
498         switch(event->type) {
499                 case MOUSEMOVE:
500                         factor= 1.0f + (vpd->x-event->x+vpd->y-event->y)/300.0f;
501                         RNA_float_set(op->ptr, "factor", factor);
502                         sclip_zoom_set(sc, ar, vpd->zoom*factor);
503                         ED_region_tag_redraw(CTX_wm_region(C));
504                         break;
505                 default:
506                         if(event->type==vpd->event_type && event->val==KM_RELEASE) {
507                                 view_zoom_exit(C, op, 0);
508                                 return OPERATOR_FINISHED;
509                         }
510                         break;
511         }
512
513         return OPERATOR_RUNNING_MODAL;
514 }
515
516 static int view_zoom_cancel(bContext *C, wmOperator *op)
517 {
518         view_zoom_exit(C, op, 1);
519         return OPERATOR_CANCELLED;
520 }
521
522 void CLIP_OT_view_zoom(wmOperatorType *ot)
523 {
524         /* identifiers */
525         ot->name= "View Zoom";
526         ot->idname= "CLIP_OT_view_zoom";
527
528         /* api callbacks */
529         ot->exec= view_zoom_exec;
530         ot->invoke= view_zoom_invoke;
531         ot->modal= view_zoom_modal;
532         ot->cancel= view_zoom_cancel;
533         ot->poll= ED_space_clip_poll;
534
535         /* flags */
536         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
537
538         /* properties */
539         RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
540                 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
541 }
542
543 /********************** view zoom in/out operator *********************/
544
545 static int view_zoom_in_exec(bContext *C, wmOperator *UNUSED(op))
546 {
547         SpaceClip *sc= CTX_wm_space_clip(C);
548         ARegion *ar= CTX_wm_region(C);
549
550         sclip_zoom_set_factor(sc, ar, 1.25f);
551
552         ED_region_tag_redraw(CTX_wm_region(C));
553
554         return OPERATOR_FINISHED;
555 }
556
557 static int view_zoom_out_exec(bContext *C, wmOperator *UNUSED(op))
558 {
559         SpaceClip *sc= CTX_wm_space_clip(C);
560         ARegion *ar= CTX_wm_region(C);
561
562         sclip_zoom_set_factor(sc, ar, 0.8f);
563
564         ED_region_tag_redraw(CTX_wm_region(C));
565
566         return OPERATOR_FINISHED;
567 }
568
569 static int view_zoom_inout_invoke(bContext *C, wmOperator *op, wmEvent *event, int out)
570 {
571         SpaceClip *sc= CTX_wm_space_clip(C);
572         float co[2], oldzoom= sc->zoom;
573
574         ED_clip_mouse_pos(C, event, co);
575
576         if(out)
577                 view_zoom_out_exec(C, op);
578         else
579                 view_zoom_in_exec(C, op);
580
581         if(U.uiflag&USER_ZOOM_TO_MOUSEPOS) {
582                 int width, height;
583
584                 ED_space_clip_size(sc, &width, &height);
585
586                 sc->xof+= ((co[0]-0.5)*width-sc->xof)*(sc->zoom-oldzoom)/sc->zoom;
587                 sc->yof+= ((co[1]-0.5)*height-sc->yof)*(sc->zoom-oldzoom)/sc->zoom;
588         }
589
590         return OPERATOR_FINISHED;
591 }
592
593 static int view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event)
594 {
595         return view_zoom_inout_invoke(C, op, event, 0);
596 }
597
598 void CLIP_OT_view_zoom_in(wmOperatorType *ot)
599 {
600         /* identifiers */
601         ot->name= "View Zoom In";
602         ot->idname= "CLIP_OT_view_zoom_in";
603
604         /* api callbacks */
605         ot->exec= view_zoom_in_exec;
606         ot->invoke= view_zoom_in_invoke;
607         ot->poll= ED_space_clip_poll;
608 }
609
610 static int view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event)
611 {
612         return view_zoom_inout_invoke(C, op, event, 1);
613 }
614
615 void CLIP_OT_view_zoom_out(wmOperatorType *ot)
616 {
617         /* identifiers */
618         ot->name= "View Zoom Out";
619         ot->idname= "CLIP_OT_view_zoom_out";
620
621         /* api callbacks */
622         ot->exec= view_zoom_out_exec;
623         ot->invoke= view_zoom_out_invoke;
624         ot->poll= ED_space_clip_poll;
625 }
626
627 /********************** view zoom ratio operator *********************/
628
629 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
630 {
631         SpaceClip *sc= CTX_wm_space_clip(C);
632         ARegion *ar= CTX_wm_region(C);
633
634         sclip_zoom_set(sc, ar, RNA_float_get(op->ptr, "ratio"));
635
636         /* ensure pixel exact locations for draw */
637         sc->xof= (int)sc->xof;
638         sc->yof= (int)sc->yof;
639
640         ED_region_tag_redraw(CTX_wm_region(C));
641
642         return OPERATOR_FINISHED;
643 }
644
645 void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
646 {
647         /* identifiers */
648         ot->name= "View Zoom Ratio";
649         ot->idname= "CLIP_OT_view_zoom_ratio";
650
651         /* api callbacks */
652         ot->exec= view_zoom_ratio_exec;
653         ot->poll= ED_space_clip_poll;
654
655         /* properties */
656         RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
657                 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out.", -FLT_MAX, FLT_MAX);
658 }
659
660 /********************** view all operator *********************/
661
662 static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
663 {
664         SpaceClip *sc;
665         ARegion *ar;
666         int w, h, width, height;
667         float aspx, aspy;
668
669         /* retrieve state */
670         sc= CTX_wm_space_clip(C);
671         ar= CTX_wm_region(C);
672
673         ED_space_clip_size(sc, &w, &h);
674         ED_space_clip_aspect(sc, &aspx, &aspy);
675
676         w= w*aspx;
677         h= h*aspy;
678
679         /* check if the image will fit in the image with zoom==1 */
680         width= ar->winrct.xmax - ar->winrct.xmin + 1;
681         height= ar->winrct.ymax - ar->winrct.ymin + 1;
682
683         if((w >= width || h >= height) && (width > 0 && height > 0)) {
684                 float zoomx, zoomy;
685
686                 /* find the zoom value that will fit the image in the image space */
687                 zoomx= (float)width/w;
688                 zoomy= (float)height/h;
689                 sclip_zoom_set(sc, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
690         }
691         else
692                 sclip_zoom_set(sc, ar, 1.0f);
693
694         sc->xof= sc->yof= 0.0f;
695
696         ED_region_tag_redraw(CTX_wm_region(C));
697
698         return OPERATOR_FINISHED;
699 }
700
701 void CLIP_OT_view_all(wmOperatorType *ot)
702 {
703         /* identifiers */
704         ot->name= "View All";
705         ot->idname= "CLIP_OT_view_all";
706
707         /* api callbacks */
708         ot->exec= view_all_exec;
709         ot->poll= ED_space_clip_poll;
710 }
711
712 /********************** view selected operator *********************/
713
714 static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
715 {
716         SpaceClip *sc= CTX_wm_space_clip(C);
717         ARegion *ar= CTX_wm_region(C);
718
719         ED_clip_view_selection(sc, ar, 1);
720         ED_region_tag_redraw(CTX_wm_region(C));
721
722         return OPERATOR_FINISHED;
723 }
724
725 void CLIP_OT_view_selected(wmOperatorType *ot)
726 {
727         /* identifiers */
728         ot->name= "View Selected";
729         ot->idname= "CLIP_OT_view_selected";
730
731         /* api callbacks */
732         ot->exec= view_selected_exec;
733         ot->poll= ED_space_clip_poll;
734 }
735
736 /********************** change frame operator *********************/
737
738 static int change_frame_poll(bContext *C)
739 {
740         /* prevent changes during render */
741         if(G.rendering)
742                 return 0;
743
744         return ED_space_clip_poll(C);
745 }
746
747 static void change_frame_apply(bContext *C, wmOperator *op)
748 {
749         Scene *scene= CTX_data_scene(C);
750
751         /* set the new frame number */
752         CFRA= RNA_int_get(op->ptr, "frame");
753         FRAMENUMBER_MIN_CLAMP(CFRA);
754         SUBFRA = 0.f;
755
756         /* do updates */
757         sound_seek_scene(C);
758         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
759 }
760
761 static int change_frame_exec(bContext *C, wmOperator *op)
762 {
763         change_frame_apply(C, op);
764
765         return OPERATOR_FINISHED;
766 }
767
768 static int frame_from_event(bContext *C, wmEvent *event)
769 {
770         ARegion *ar= CTX_wm_region(C);
771         Scene *scene= CTX_data_scene(C);
772
773         float sfra= SFRA, efra= EFRA, framelen= ar->winx/(efra-sfra+1);
774
775         return sfra+event->mval[0]/framelen;
776 }
777
778 static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
779 {
780         if(event->mval[1]>16)
781                 return OPERATOR_PASS_THROUGH;
782
783         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
784
785         change_frame_apply(C, op);
786
787         /* add temp handler */
788         WM_event_add_modal_handler(C, op);
789
790         return OPERATOR_RUNNING_MODAL;
791 }
792
793 static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
794 {
795         switch (event->type) {
796                 case ESCKEY:
797                         return OPERATOR_FINISHED;
798
799                 case MOUSEMOVE:
800                         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
801                         change_frame_apply(C, op);
802                         break;
803
804                 case LEFTMOUSE:
805                 case RIGHTMOUSE:
806                         if (event->val==KM_RELEASE)
807                                 return OPERATOR_FINISHED;
808                         break;
809         }
810
811         return OPERATOR_RUNNING_MODAL;
812 }
813
814 void CLIP_OT_change_frame(wmOperatorType *ot)
815 {
816         /* identifiers */
817         ot->name= "Change frame";
818         ot->idname= "CLIP_OT_change_frame";
819         ot->description= "Interactively change the current frame number";
820
821         /* api callbacks */
822         ot->exec= change_frame_exec;
823         ot->invoke= change_frame_invoke;
824         ot->modal= change_frame_modal;
825         ot->poll= change_frame_poll;
826
827         /* flags */
828         ot->flag= OPTYPE_BLOCKING|OPTYPE_UNDO;
829
830         /* rna */
831         RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
832 }
833
834 /********************** macroses *********************/
835
836 void ED_operatormacros_clip(void)
837 {
838         wmOperatorType *ot;
839         wmOperatorTypeMacro *otmacro;
840
841         ot= WM_operatortype_append_macro("CLIP_OT_add_marker_move", "Add Marker and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
842         ot->description = "Add new marker and move it on movie";
843         WM_operatortype_macro_define(ot, "CLIP_OT_add_marker");
844         otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
845         RNA_struct_idprops_unset(otmacro->ptr, "release_confirm");
846
847         ot= WM_operatortype_append_macro("CLIP_OT_add_marker_slide", "Add Marker and Slide", OPTYPE_UNDO|OPTYPE_REGISTER);
848         ot->description = "Add new marker and slide it with mouse until mouse button release";
849         WM_operatortype_macro_define(ot, "CLIP_OT_add_marker");
850         otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
851         RNA_boolean_set(otmacro->ptr, "release_confirm", 1);
852 }