rename RNA_property_is_set() --> RNA_struct_property_is_set() in preperation to add...
[blender-staging.git] / source / blender / editors / space_clip / clip_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/clip_ops.c
29  *  \ingroup spclip
30  */
31
32 #include <errno.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_userdef_types.h"
37 #include "DNA_scene_types.h"    /* min/max frames */
38
39 #include "BLI_utildefines.h"
40 #include "BLI_math.h"
41
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44 #include "BKE_report.h"
45 #include "BKE_main.h"
46 #include "BKE_library.h"
47 #include "BKE_movieclip.h"
48 #include "BKE_sound.h"
49 #include "BKE_tracking.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "IMB_imbuf_types.h"
55 #include "IMB_imbuf.h"
56
57 #include "ED_screen.h"
58 #include "ED_clip.h"
59
60 #include "UI_interface.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "UI_view2d.h"
66
67 #include "clip_intern.h"        // own include
68
69 /******************** view navigation utilities *********************/
70
71 static void sclip_zoom_set(SpaceClip *sc, ARegion *ar, float zoom)
72 {
73         float oldzoom= sc->zoom;
74         int width, height;
75
76         sc->zoom= zoom;
77
78         if (sc->zoom > 0.1f && sc->zoom < 4.0f)
79                 return;
80
81         /* check zoom limits */
82         ED_space_clip_size(sc, &width, &height);
83
84         width*= sc->zoom;
85         height*= sc->zoom;
86
87         if((width < 4) && (height < 4))
88                 sc->zoom= oldzoom;
89         else if((ar->winrct.xmax - ar->winrct.xmin) <= sc->zoom)
90                 sc->zoom= oldzoom;
91         else if((ar->winrct.ymax - ar->winrct.ymin) <= sc->zoom)
92                 sc->zoom= oldzoom;
93 }
94
95 static void sclip_zoom_set_factor(SpaceClip *sc, ARegion *ar, float zoomfac)
96 {
97         sclip_zoom_set(sc, ar, sc->zoom*zoomfac);
98 }
99
100
101 /******************** open clip operator ********************/
102
103 static void clip_filesel(bContext *C, wmOperator *op, const char *path)
104 {
105         RNA_string_set(op->ptr, "filepath", path);
106         WM_event_add_fileselect(C, op);
107 }
108
109 static void open_init(bContext *C, wmOperator *op)
110 {
111         PropertyPointerRNA *pprop;
112
113         op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
114         uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
115 }
116
117 static int open_cancel(bContext *UNUSED(C), wmOperator *op)
118 {
119         MEM_freeN(op->customdata);
120         op->customdata= NULL;
121
122         return OPERATOR_CANCELLED;
123 }
124
125 static int open_exec(bContext *C, wmOperator *op)
126 {
127         SpaceClip *sc= CTX_wm_space_clip(C);
128         PropertyPointerRNA *pprop;
129         PointerRNA idptr;
130         MovieClip *clip= NULL;
131         char str[FILE_MAX];
132
133         RNA_string_get(op->ptr, "filepath", str);
134         /* default to frame 1 if there's no scene in context */
135
136         errno= 0;
137
138         clip= BKE_add_movieclip_file(str);
139
140         if(!clip) {
141                 if(op->customdata)
142                         MEM_freeN(op->customdata);
143
144                 BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", str, errno ? strerror(errno) : "Unsupported movie clip format");
145
146                 return OPERATOR_CANCELLED;
147         }
148
149         if(!op->customdata)
150                 open_init(C, op);
151
152         /* hook into UI */
153         pprop= op->customdata;
154
155         if(pprop->prop) {
156                 /* when creating new ID blocks, use is already 1, but RNA
157                  * pointer se also increases user, so this compensates it */
158                 clip->id.us--;
159
160                 RNA_id_pointer_create(&clip->id, &idptr);
161                 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
162                 RNA_property_update(C, &pprop->ptr, pprop->prop);
163         }
164         else if(sc) {
165                 ED_space_clip_set(C, sc, clip);
166         }
167
168         WM_event_add_notifier(C, NC_MOVIECLIP|NA_ADDED, clip);
169
170         MEM_freeN(op->customdata);
171
172         return OPERATOR_FINISHED;
173 }
174
175 static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
176 {
177         SpaceClip *sc= CTX_wm_space_clip(C);
178         char *path= U.textudir;
179         MovieClip *clip= NULL;
180
181         if(sc)
182                 clip= ED_space_clip(sc);
183
184         if(clip)
185                 path= clip->name;
186
187         if(!RNA_struct_property_is_set(op->ptr, "relative_path"))
188                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
189
190         if(RNA_struct_property_is_set(op->ptr, "filepath"))
191                 return open_exec(C, op);
192
193         open_init(C, op);
194
195         clip_filesel(C, op, path);
196
197         return OPERATOR_RUNNING_MODAL;
198 }
199
200 void CLIP_OT_open(wmOperatorType *ot)
201 {
202         /* identifiers */
203         ot->name= "Open Clip";
204         ot->description= "Load a sequence of frames or a movie file";
205         ot->idname= "CLIP_OT_open";
206
207         /* api callbacks */
208         ot->exec= open_exec;
209         ot->invoke= open_invoke;
210         ot->cancel= open_cancel;
211
212         /* flags */
213         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
214
215         /* properties */
216         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
217 }
218
219 /******************* reload clip operator *********************/
220
221 static int reload_exec(bContext *C, wmOperator *UNUSED(op))
222 {
223         MovieClip *clip= CTX_data_edit_movieclip(C);
224
225         if(!clip)
226                 return OPERATOR_CANCELLED;
227
228         BKE_movieclip_reload(clip);
229
230         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
231
232         return OPERATOR_FINISHED;
233 }
234
235 void CLIP_OT_reload(wmOperatorType *ot)
236 {
237         /* identifiers */
238         ot->name= "Reload Clip";
239         ot->description= "Reload clip";
240         ot->idname= "CLIP_OT_reload";
241
242         /* api callbacks */
243         ot->exec= reload_exec;
244 }
245
246 /********************** view pan operator *********************/
247
248 typedef struct ViewPanData {
249         float x, y;
250         float xof, yof, xorig, yorig;
251         int event_type;
252         float *vec;
253 } ViewPanData;
254
255 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
256 {
257         SpaceClip *sc= CTX_wm_space_clip(C);
258         ViewPanData *vpd;
259
260         op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ClipViewPanData");
261         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
262
263         vpd->x= event->x;
264         vpd->y= event->y;
265
266         if(sc->flag&SC_LOCK_SELECTION) vpd->vec= &sc->xlockof;
267         else vpd->vec= &sc->xof;
268
269         copy_v2_v2(&vpd->xof, vpd->vec);
270         copy_v2_v2(&vpd->xorig, &vpd->xof);
271
272         vpd->event_type= event->type;
273
274         WM_event_add_modal_handler(C, op);
275 }
276
277 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
278 {
279         ViewPanData *vpd= op->customdata;
280
281         if(cancel) {
282                 copy_v2_v2(vpd->vec, &vpd->xorig);
283
284                 ED_region_tag_redraw(CTX_wm_region(C));
285         }
286
287         WM_cursor_restore(CTX_wm_window(C));
288         MEM_freeN(op->customdata);
289 }
290
291 static int view_pan_exec(bContext *C, wmOperator *op)
292 {
293         SpaceClip *sc= CTX_wm_space_clip(C);
294         float offset[2];
295
296         RNA_float_get_array(op->ptr, "offset", offset);
297
298         if(sc->flag&SC_LOCK_SELECTION) {
299                 sc->xlockof+= offset[0];
300                 sc->ylockof+= offset[1];
301         } else {
302                 sc->xof+= offset[0];
303                 sc->yof+= offset[1];
304         }
305
306         ED_region_tag_redraw(CTX_wm_region(C));
307
308         return OPERATOR_FINISHED;
309 }
310
311 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
312 {
313         if (event->type==MOUSEPAN) {
314                 SpaceClip *sc= CTX_wm_space_clip(C);
315                 float offset[2];
316
317                 offset[0]= (event->x - event->prevx)/sc->zoom;
318                 offset[1]= (event->y - event->prevy)/sc->zoom;
319
320                 RNA_float_set_array(op->ptr, "offset", offset);
321
322                 view_pan_exec(C, op);
323                 return OPERATOR_FINISHED;
324         }
325         else {
326                 view_pan_init(C, op, event);
327                 return OPERATOR_RUNNING_MODAL;
328         }
329 }
330
331 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
332 {
333         SpaceClip *sc= CTX_wm_space_clip(C);
334         ViewPanData *vpd= op->customdata;
335         float offset[2];
336
337         switch(event->type) {
338                 case MOUSEMOVE:
339                         copy_v2_v2(vpd->vec, &vpd->xorig);
340                         offset[0]= (vpd->x - event->x)/sc->zoom;
341                         offset[1]= (vpd->y - event->y)/sc->zoom;
342                         RNA_float_set_array(op->ptr, "offset", offset);
343                         view_pan_exec(C, op);
344                         break;
345                 case ESCKEY:
346                         view_pan_exit(C, op, 1);
347                         return OPERATOR_CANCELLED;
348                 case SPACEKEY:
349                         view_pan_exit(C, op, 0);
350                         return OPERATOR_FINISHED;
351                 default:
352                         if(event->type==vpd->event_type &&  event->val==KM_RELEASE) {
353                                 view_pan_exit(C, op, 0);
354                                 return OPERATOR_FINISHED;
355                         }
356                         break;
357         }
358
359         return OPERATOR_RUNNING_MODAL;
360 }
361
362 static int view_pan_cancel(bContext *C, wmOperator *op)
363 {
364         view_pan_exit(C, op, 1);
365
366         return OPERATOR_CANCELLED;
367 }
368
369 void CLIP_OT_view_pan(wmOperatorType *ot)
370 {
371         /* identifiers */
372         ot->name= "View Pan";
373         ot->idname= "CLIP_OT_view_pan";
374
375         /* api callbacks */
376         ot->exec= view_pan_exec;
377         ot->invoke= view_pan_invoke;
378         ot->modal= view_pan_modal;
379         ot->cancel= view_pan_cancel;
380         ot->poll= ED_space_clip_poll;
381
382         /* flags */
383         ot->flag= OPTYPE_BLOCKING;
384
385         /* properties */
386         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
387                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
388 }
389
390 /********************** view zoom operator *********************/
391
392 typedef struct ViewZoomData {
393         float x, y;
394         float zoom;
395         int event_type;
396 } ViewZoomData;
397
398 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
399 {
400         SpaceClip *sc= CTX_wm_space_clip(C);
401         ViewZoomData *vpd;
402
403         op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ClipViewZoomData");
404         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
405
406         vpd->x= event->x;
407         vpd->y= event->y;
408         vpd->zoom= sc->zoom;
409         vpd->event_type= event->type;
410
411         WM_event_add_modal_handler(C, op);
412 }
413
414 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
415 {
416         SpaceClip *sc= CTX_wm_space_clip(C);
417         ViewZoomData *vpd= op->customdata;
418
419         if(cancel) {
420                 sc->zoom= vpd->zoom;
421                 ED_region_tag_redraw(CTX_wm_region(C));
422         }
423
424         WM_cursor_restore(CTX_wm_window(C));
425         MEM_freeN(op->customdata);
426 }
427
428 static int view_zoom_exec(bContext *C, wmOperator *op)
429 {
430         SpaceClip *sc= CTX_wm_space_clip(C);
431         ARegion *ar= CTX_wm_region(C);
432
433         sclip_zoom_set_factor(sc, ar, RNA_float_get(op->ptr, "factor"));
434
435         ED_region_tag_redraw(CTX_wm_region(C));
436
437         return OPERATOR_FINISHED;
438 }
439
440 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
441 {
442         if (event->type==MOUSEZOOM) {
443                 SpaceClip *sc= CTX_wm_space_clip(C);
444                 ARegion *ar= CTX_wm_region(C);
445                 float factor;
446
447                 factor= 1.0f + (event->x-event->prevx+event->y-event->prevy)/300.0f;
448                 RNA_float_set(op->ptr, "factor", factor);
449                 sclip_zoom_set(sc, ar, sc->zoom*factor);
450                 ED_region_tag_redraw(CTX_wm_region(C));
451
452                 return OPERATOR_FINISHED;
453         }
454         else {
455                 view_zoom_init(C, op, event);
456                 return OPERATOR_RUNNING_MODAL;
457         }
458 }
459
460 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
461 {
462         SpaceClip *sc= CTX_wm_space_clip(C);
463         ARegion *ar= CTX_wm_region(C);
464         ViewZoomData *vpd= op->customdata;
465         float factor;
466
467         switch(event->type) {
468                 case MOUSEMOVE:
469                         factor= 1.0f + (vpd->x-event->x+vpd->y-event->y)/300.0f;
470                         RNA_float_set(op->ptr, "factor", factor);
471                         sclip_zoom_set(sc, ar, vpd->zoom*factor);
472                         ED_region_tag_redraw(CTX_wm_region(C));
473                         break;
474                 default:
475                         if(event->type==vpd->event_type && event->val==KM_RELEASE) {
476                                 view_zoom_exit(C, op, 0);
477                                 return OPERATOR_FINISHED;
478                         }
479                         break;
480         }
481
482         return OPERATOR_RUNNING_MODAL;
483 }
484
485 static int view_zoom_cancel(bContext *C, wmOperator *op)
486 {
487         view_zoom_exit(C, op, 1);
488         return OPERATOR_CANCELLED;
489 }
490
491 void CLIP_OT_view_zoom(wmOperatorType *ot)
492 {
493         /* identifiers */
494         ot->name= "View Zoom";
495         ot->idname= "CLIP_OT_view_zoom";
496
497         /* api callbacks */
498         ot->exec= view_zoom_exec;
499         ot->invoke= view_zoom_invoke;
500         ot->modal= view_zoom_modal;
501         ot->cancel= view_zoom_cancel;
502         ot->poll= ED_space_clip_poll;
503
504         /* flags */
505         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
506
507         /* properties */
508         RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
509                 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
510 }
511
512 /********************** view zoom in/out operator *********************/
513
514 static int view_zoom_in_exec(bContext *C, wmOperator *UNUSED(op))
515 {
516         SpaceClip *sc= CTX_wm_space_clip(C);
517         ARegion *ar= CTX_wm_region(C);
518
519         sclip_zoom_set_factor(sc, ar, 1.25f);
520
521         ED_region_tag_redraw(CTX_wm_region(C));
522
523         return OPERATOR_FINISHED;
524 }
525
526 static int view_zoom_out_exec(bContext *C, wmOperator *UNUSED(op))
527 {
528         SpaceClip *sc= CTX_wm_space_clip(C);
529         ARegion *ar= CTX_wm_region(C);
530
531         sclip_zoom_set_factor(sc, ar, 0.8f);
532
533         ED_region_tag_redraw(CTX_wm_region(C));
534
535         return OPERATOR_FINISHED;
536 }
537
538 static int view_zoom_inout_invoke(bContext *C, wmOperator *op, wmEvent *event, int out)
539 {
540         SpaceClip *sc= CTX_wm_space_clip(C);
541         float co[2], oldzoom= sc->zoom;
542
543         ED_clip_mouse_pos(C, event, co);
544
545         if(out)
546                 view_zoom_out_exec(C, op);
547         else
548                 view_zoom_in_exec(C, op);
549
550         if(U.uiflag&USER_ZOOM_TO_MOUSEPOS) {
551                 int width, height;
552
553                 ED_space_clip_size(sc, &width, &height);
554
555                 sc->xof+= ((co[0]-0.5f)*width-sc->xof)*(sc->zoom-oldzoom)/sc->zoom;
556                 sc->yof+= ((co[1]-0.5f)*height-sc->yof)*(sc->zoom-oldzoom)/sc->zoom;
557         }
558
559         return OPERATOR_FINISHED;
560 }
561
562 static int view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event)
563 {
564         return view_zoom_inout_invoke(C, op, event, 0);
565 }
566
567 void CLIP_OT_view_zoom_in(wmOperatorType *ot)
568 {
569         /* identifiers */
570         ot->name= "View Zoom In";
571         ot->idname= "CLIP_OT_view_zoom_in";
572
573         /* api callbacks */
574         ot->exec= view_zoom_in_exec;
575         ot->invoke= view_zoom_in_invoke;
576         ot->poll= ED_space_clip_poll;
577 }
578
579 static int view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event)
580 {
581         return view_zoom_inout_invoke(C, op, event, 1);
582 }
583
584 void CLIP_OT_view_zoom_out(wmOperatorType *ot)
585 {
586         /* identifiers */
587         ot->name= "View Zoom Out";
588         ot->idname= "CLIP_OT_view_zoom_out";
589
590         /* api callbacks */
591         ot->exec= view_zoom_out_exec;
592         ot->invoke= view_zoom_out_invoke;
593         ot->poll= ED_space_clip_poll;
594 }
595
596 /********************** view zoom ratio operator *********************/
597
598 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
599 {
600         SpaceClip *sc= CTX_wm_space_clip(C);
601         ARegion *ar= CTX_wm_region(C);
602
603         sclip_zoom_set(sc, ar, RNA_float_get(op->ptr, "ratio"));
604
605         /* ensure pixel exact locations for draw */
606         sc->xof= (int)sc->xof;
607         sc->yof= (int)sc->yof;
608
609         ED_region_tag_redraw(CTX_wm_region(C));
610
611         return OPERATOR_FINISHED;
612 }
613
614 void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
615 {
616         /* identifiers */
617         ot->name= "View Zoom Ratio";
618         ot->idname= "CLIP_OT_view_zoom_ratio";
619
620         /* api callbacks */
621         ot->exec= view_zoom_ratio_exec;
622         ot->poll= ED_space_clip_poll;
623
624         /* properties */
625         RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
626                 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
627 }
628
629 /********************** view all operator *********************/
630
631 static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
632 {
633         SpaceClip *sc;
634         ARegion *ar;
635         int w, h, width, height;
636         float aspx, aspy;
637
638         /* retrieve state */
639         sc= CTX_wm_space_clip(C);
640         ar= CTX_wm_region(C);
641
642         ED_space_clip_size(sc, &w, &h);
643         ED_space_clip_aspect(sc, &aspx, &aspy);
644
645         w= w*aspx;
646         h= h*aspy;
647
648         /* check if the image will fit in the image with zoom==1 */
649         width= ar->winrct.xmax - ar->winrct.xmin + 1;
650         height= ar->winrct.ymax - ar->winrct.ymin + 1;
651
652         if((w >= width || h >= height) && (width > 0 && height > 0)) {
653                 float zoomx, zoomy;
654
655                 /* find the zoom value that will fit the image in the image space */
656                 zoomx= (float)width/w;
657                 zoomy= (float)height/h;
658                 sclip_zoom_set(sc, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
659         }
660         else
661                 sclip_zoom_set(sc, ar, 1.0f);
662
663         sc->xof= sc->yof= 0.0f;
664
665         ED_region_tag_redraw(CTX_wm_region(C));
666
667         return OPERATOR_FINISHED;
668 }
669
670 void CLIP_OT_view_all(wmOperatorType *ot)
671 {
672         /* identifiers */
673         ot->name= "View All";
674         ot->idname= "CLIP_OT_view_all";
675
676         /* api callbacks */
677         ot->exec= view_all_exec;
678         ot->poll= ED_space_clip_poll;
679 }
680
681 /********************** view selected operator *********************/
682
683 static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
684 {
685         SpaceClip *sc= CTX_wm_space_clip(C);
686         ARegion *ar= CTX_wm_region(C);
687
688         sc->xlockof= 0.0f;
689         sc->ylockof= 0.0f;
690
691         ED_clip_view_selection(sc, ar, 1);
692         ED_region_tag_redraw(CTX_wm_region(C));
693
694         return OPERATOR_FINISHED;
695 }
696
697 void CLIP_OT_view_selected(wmOperatorType *ot)
698 {
699         /* identifiers */
700         ot->name= "View Selected";
701         ot->idname= "CLIP_OT_view_selected";
702
703         /* api callbacks */
704         ot->exec= view_selected_exec;
705         ot->poll= ED_space_clip_poll;
706 }
707
708 /********************** change frame operator *********************/
709
710 static int change_frame_poll(bContext *C)
711 {
712         /* prevent changes during render */
713         if(G.rendering)
714                 return 0;
715
716         return ED_space_clip_poll(C);
717 }
718
719 static void change_frame_apply(bContext *C, wmOperator *op)
720 {
721         Scene *scene= CTX_data_scene(C);
722
723         /* set the new frame number */
724         CFRA= RNA_int_get(op->ptr, "frame");
725         FRAMENUMBER_MIN_CLAMP(CFRA);
726         SUBFRA = 0.0f;
727
728         /* do updates */
729         sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
730         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
731 }
732
733 static int change_frame_exec(bContext *C, wmOperator *op)
734 {
735         change_frame_apply(C, op);
736
737         return OPERATOR_FINISHED;
738 }
739
740 static int frame_from_event(bContext *C, wmEvent *event)
741 {
742         ARegion *ar= CTX_wm_region(C);
743         Scene *scene= CTX_data_scene(C);
744         int framenr= 0;
745
746         if(ar->regiontype == RGN_TYPE_WINDOW) {
747                 float sfra= SFRA, efra= EFRA, framelen= ar->winx/(efra-sfra+1);
748
749                 framenr= sfra+event->mval[0]/framelen;
750         } else {
751                 float viewx, viewy;
752
753                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
754
755                 framenr= (int)floor(viewx+0.5f);
756         }
757
758         return framenr;
759 }
760
761 static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
762 {
763         ARegion *ar= CTX_wm_region(C);
764
765         if(ar->regiontype == RGN_TYPE_WINDOW) {
766                 if(event->mval[1]>16)
767                         return OPERATOR_PASS_THROUGH;
768         }
769
770         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
771
772         change_frame_apply(C, op);
773
774         /* add temp handler */
775         WM_event_add_modal_handler(C, op);
776
777         return OPERATOR_RUNNING_MODAL;
778 }
779
780 static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
781 {
782         switch (event->type) {
783                 case ESCKEY:
784                         return OPERATOR_FINISHED;
785
786                 case MOUSEMOVE:
787                         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
788                         change_frame_apply(C, op);
789                         break;
790
791                 case LEFTMOUSE:
792                 case RIGHTMOUSE:
793                         if (event->val==KM_RELEASE)
794                                 return OPERATOR_FINISHED;
795                         break;
796         }
797
798         return OPERATOR_RUNNING_MODAL;
799 }
800
801 void CLIP_OT_change_frame(wmOperatorType *ot)
802 {
803         /* identifiers */
804         ot->name= "Change frame";
805         ot->idname= "CLIP_OT_change_frame";
806         ot->description= "Interactively change the current frame number";
807
808         /* api callbacks */
809         ot->exec= change_frame_exec;
810         ot->invoke= change_frame_invoke;
811         ot->modal= change_frame_modal;
812         ot->poll= change_frame_poll;
813
814         /* flags */
815         ot->flag= OPTYPE_BLOCKING|OPTYPE_UNDO;
816
817         /* rna */
818         RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
819 }
820
821 /********************** rebuild proxies operator *********************/
822
823 typedef struct ProxyBuildJob {
824         Scene *scene;
825         struct Main *main;
826         MovieClip *clip;
827         int clip_flag;
828 } ProxyJob;
829
830 static void proxy_freejob(void *pjv)
831 {
832         ProxyJob *pj= pjv;
833
834         MEM_freeN(pj);
835 }
836
837 /* only this runs inside thread */
838 static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
839 {
840         ProxyJob *pj= pjv;
841         Scene *scene=pj->scene;
842         MovieClip *clip= pj->clip;
843         struct MovieDistortion *distortion= NULL;
844         int cfra, undistort;
845         short tc_flag, size_flag, quality, build_flag;
846         int sfra= SFRA, efra= EFRA;
847         int build_sizes[4], build_count= 0;
848
849         tc_flag= clip->proxy.build_tc_flag;
850         size_flag= clip->proxy.build_size_flag;
851         quality= clip->proxy.quality;
852         build_flag= clip->proxy.build_flag;
853         undistort= build_flag&MCLIP_PROXY_RENDER_UNDISTORT;
854
855         if(clip->source == MCLIP_SRC_MOVIE) {
856                 if(clip->anim)
857                         IMB_anim_index_rebuild(clip->anim, tc_flag, size_flag, quality, stop, do_update, progress);
858
859                 if(!undistort) {
860                         return;
861                 }
862                 else {
863                         sfra= 1;
864                         efra= IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
865                 }
866         }
867
868         if(size_flag&IMB_PROXY_25) build_sizes[build_count++]= MCLIP_PROXY_RENDER_SIZE_25;
869         if(size_flag&IMB_PROXY_50) build_sizes[build_count++]= MCLIP_PROXY_RENDER_SIZE_50;
870         if(size_flag&IMB_PROXY_75) build_sizes[build_count++]= MCLIP_PROXY_RENDER_SIZE_75;
871         if(size_flag&IMB_PROXY_100) build_sizes[build_count++]= MCLIP_PROXY_RENDER_SIZE_100;
872
873         if(undistort)
874                 distortion= BKE_tracking_distortion_create();
875
876         for(cfra= sfra; cfra<=efra; cfra++) {
877                 if(clip->source != MCLIP_SRC_MOVIE)
878                         BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, NULL, cfra, build_sizes, build_count, 0);
879
880                 if(undistort)
881                         BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, distortion, cfra, build_sizes, build_count, 1);
882
883                 if(*stop || G.afbreek)
884                         break;
885
886                 *do_update= 1;
887                 *progress= ((float)cfra)/(efra-sfra);
888         }
889
890         if(distortion)
891                 BKE_tracking_distortion_destroy(distortion);
892 }
893
894 static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
895 {
896         wmJob * steve;
897         ProxyJob *pj;
898         Scene *scene= CTX_data_scene(C);
899         ScrArea *sa= CTX_wm_area(C);
900         SpaceClip *sc= CTX_wm_space_clip(C);
901         MovieClip *clip= ED_space_clip(sc);
902
903         if((clip->flag&MCLIP_USE_PROXY)==0)
904                 return OPERATOR_CANCELLED;
905
906         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies", WM_JOB_PROGRESS);
907
908         pj= MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
909         pj->scene= scene;
910         pj->main= CTX_data_main(C);
911         pj->clip= clip;
912         pj->clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
913
914         WM_jobs_customdata(steve, pj, proxy_freejob);
915         WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|ND_DISPLAY, 0);
916         WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL, NULL);
917
918         G.afbreek= 0;
919         WM_jobs_start(CTX_wm_manager(C), steve);
920
921         ED_area_tag_redraw(CTX_wm_area(C));
922
923         return OPERATOR_FINISHED;
924 }
925
926 void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
927 {
928         /* identifiers */
929         ot->name= "Rebuild Proxy and Timecode Indices";
930         ot->idname= "CLIP_OT_rebuild_proxy";
931         ot->description= "Rebuild all selected proxies and timecode indices in the background";
932
933         /* api callbacks */
934         ot->exec= clip_rebuild_proxy_exec;
935         ot->poll= ED_space_clip_poll;
936
937         /* flags */
938         ot->flag= OPTYPE_REGISTER;
939 }
940
941 /********************** mode set operator *********************/
942
943 static int mode_set_exec(bContext *C, wmOperator *op)
944 {
945         SpaceClip *sc= CTX_wm_space_clip(C);
946         int mode= RNA_enum_get(op->ptr, "mode");
947         int toggle= RNA_boolean_get(op->ptr, "toggle");
948
949         if(sc->mode==mode) {
950                 if(toggle)
951                         sc->mode= SC_MODE_TRACKING;
952         } else {
953                 sc->mode= mode;
954         }
955
956         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_CLIP, NULL);
957
958         return OPERATOR_FINISHED;
959 }
960
961 void CLIP_OT_mode_set(wmOperatorType *ot)
962 {
963         static EnumPropertyItem mode_items[] = {
964                 {SC_MODE_TRACKING, "TRACKING", 0, "Tracking", "Show tracking and solving tools"},
965                 {SC_MODE_RECONSTRUCTION, "RECONSTRUCTION", 0, "Reconstruction", "Show tracking/reconstruction tools"},
966                 {SC_MODE_DISTORTION, "DISTORTION", 0, "Distortion", "Show distortion tools"},
967                 {0, NULL, 0, NULL, NULL}};
968
969
970         /* identifiers */
971         ot->name= "Set Clip Mode";
972         ot->description = "Set the clip interaction mode";
973         ot->idname= "CLIP_OT_mode_set";
974
975         /* api callbacks */
976         ot->exec= mode_set_exec;
977
978         ot->poll= ED_space_clip_poll;
979
980         /* properties */
981         RNA_def_enum(ot->srna, "mode", mode_items, SC_MODE_TRACKING, "Mode", "");
982         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
983 }
984
985 /********************** macroses *********************/
986
987 void ED_operatormacros_clip(void)
988 {
989         wmOperatorType *ot;
990         wmOperatorTypeMacro *otmacro;
991
992         ot= WM_operatortype_append_macro("CLIP_OT_add_marker_move", "Add Marker and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
993         ot->description = "Add new marker and move it on movie";
994         WM_operatortype_macro_define(ot, "CLIP_OT_add_marker");
995         otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
996         RNA_struct_idprops_unset(otmacro->ptr, "release_confirm");
997
998         ot= WM_operatortype_append_macro("CLIP_OT_add_marker_slide", "Add Marker and Slide", OPTYPE_UNDO|OPTYPE_REGISTER);
999         ot->description = "Add new marker and slide it with mouse until mouse button release";
1000         WM_operatortype_macro_define(ot, "CLIP_OT_add_marker");
1001         otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
1002         RNA_boolean_set(otmacro->ptr, "release_confirm", 1);
1003 }