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