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