code cleanup: pass mouse position as int[2] rather then wmEvent
[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,
279                                        FILE_DEFAULTDISPLAY);
280 }
281
282 /******************* reload clip operator *********************/
283
284 static int reload_exec(bContext *C, wmOperator *UNUSED(op))
285 {
286         MovieClip *clip = CTX_data_edit_movieclip(C);
287
288         if (!clip)
289                 return OPERATOR_CANCELLED;
290
291         BKE_movieclip_reload(clip);
292
293         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
294
295         return OPERATOR_FINISHED;
296 }
297
298 void CLIP_OT_reload(wmOperatorType *ot)
299 {
300         /* identifiers */
301         ot->name = "Reload Clip";
302         ot->description = "Reload clip";
303         ot->idname = "CLIP_OT_reload";
304
305         /* api callbacks */
306         ot->exec = reload_exec;
307 }
308
309 /********************** view pan operator *********************/
310
311 typedef struct ViewPanData {
312         float x, y;
313         float xof, yof, xorig, yorig;
314         int event_type;
315         float *vec;
316 } ViewPanData;
317
318 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
319 {
320         SpaceClip *sc = CTX_wm_space_clip(C);
321         ViewPanData *vpd;
322
323         op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ClipViewPanData");
324         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
325
326         vpd->x = event->x;
327         vpd->y = event->y;
328
329         if (sc->flag & SC_LOCK_SELECTION)
330                 vpd->vec = &sc->xlockof;
331         else
332                 vpd->vec = &sc->xof;
333
334         copy_v2_v2(&vpd->xof, vpd->vec);
335         copy_v2_v2(&vpd->xorig, &vpd->xof);
336
337         vpd->event_type = event->type;
338
339         WM_event_add_modal_handler(C, op);
340 }
341
342 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
343 {
344         ViewPanData *vpd = op->customdata;
345
346         if (cancel) {
347                 copy_v2_v2(vpd->vec, &vpd->xorig);
348
349                 ED_region_tag_redraw(CTX_wm_region(C));
350         }
351
352         WM_cursor_restore(CTX_wm_window(C));
353         MEM_freeN(op->customdata);
354 }
355
356 static int view_pan_exec(bContext *C, wmOperator *op)
357 {
358         SpaceClip *sc = CTX_wm_space_clip(C);
359         float offset[2];
360
361         RNA_float_get_array(op->ptr, "offset", offset);
362
363         if (sc->flag & SC_LOCK_SELECTION) {
364                 sc->xlockof += offset[0];
365                 sc->ylockof += offset[1];
366         }
367         else {
368                 sc->xof += offset[0];
369                 sc->yof += offset[1];
370         }
371
372         ED_region_tag_redraw(CTX_wm_region(C));
373
374         return OPERATOR_FINISHED;
375 }
376
377 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
378 {
379         if (event->type == MOUSEPAN) {
380                 SpaceClip *sc = CTX_wm_space_clip(C);
381                 float offset[2];
382
383                 offset[0] = (event->x - event->prevx) / sc->zoom;
384                 offset[1] = (event->y - event->prevy) / sc->zoom;
385
386                 RNA_float_set_array(op->ptr, "offset", offset);
387
388                 view_pan_exec(C, op);
389
390                 return OPERATOR_FINISHED;
391         }
392         else {
393                 view_pan_init(C, op, event);
394
395                 return OPERATOR_RUNNING_MODAL;
396         }
397 }
398
399 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
400 {
401         SpaceClip *sc = CTX_wm_space_clip(C);
402         ViewPanData *vpd = op->customdata;
403         float offset[2];
404
405         switch (event->type) {
406                 case MOUSEMOVE:
407                         copy_v2_v2(vpd->vec, &vpd->xorig);
408                         offset[0] = (vpd->x - event->x) / sc->zoom;
409                         offset[1] = (vpd->y - event->y) / sc->zoom;
410                         RNA_float_set_array(op->ptr, "offset", offset);
411                         view_pan_exec(C, op);
412                         break;
413                 case ESCKEY:
414                         view_pan_exit(C, op, 1);
415
416                         return OPERATOR_CANCELLED;
417                 case SPACEKEY:
418                         view_pan_exit(C, op, 0);
419
420                         return OPERATOR_FINISHED;
421                 default:
422                         if (event->type == vpd->event_type && event->val == KM_RELEASE) {
423                                 view_pan_exit(C, op, 0);
424
425                                 return OPERATOR_FINISHED;
426                         }
427                         break;
428         }
429
430         return OPERATOR_RUNNING_MODAL;
431 }
432
433 static int view_pan_cancel(bContext *C, wmOperator *op)
434 {
435         view_pan_exit(C, op, 1);
436
437         return OPERATOR_CANCELLED;
438 }
439
440 void CLIP_OT_view_pan(wmOperatorType *ot)
441 {
442         /* identifiers */
443         ot->name = "View Pan";
444         ot->idname = "CLIP_OT_view_pan";
445         ot->description = "Pan the view";
446
447         /* api callbacks */
448         ot->exec = view_pan_exec;
449         ot->invoke = view_pan_invoke;
450         ot->modal = view_pan_modal;
451         ot->cancel = view_pan_cancel;
452         ot->poll = ED_space_clip_view_clip_poll;
453
454         /* flags */
455         ot->flag = OPTYPE_BLOCKING;
456
457         /* properties */
458         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
459                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
460 }
461
462 /********************** view zoom operator *********************/
463
464 typedef struct ViewZoomData {
465         float x, y;
466         float zoom;
467         int event_type;
468         float location[2];
469 } ViewZoomData;
470
471 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
472 {
473         SpaceClip *sc = CTX_wm_space_clip(C);
474         ARegion *ar = CTX_wm_region(C);
475
476         ViewZoomData *vpd;
477
478         op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ClipViewZoomData");
479         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
480
481         vpd->x = event->x;
482         vpd->y = event->y;
483         vpd->zoom = sc->zoom;
484         vpd->event_type = event->type;
485
486         ED_clip_mouse_pos(sc, ar, event->mval, vpd->location);
487
488         WM_event_add_modal_handler(C, op);
489 }
490
491 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
492 {
493         SpaceClip *sc = CTX_wm_space_clip(C);
494         ViewZoomData *vpd = op->customdata;
495
496         if (cancel) {
497                 sc->zoom = vpd->zoom;
498                 ED_region_tag_redraw(CTX_wm_region(C));
499         }
500
501         WM_cursor_restore(CTX_wm_window(C));
502         MEM_freeN(op->customdata);
503 }
504
505 static int view_zoom_exec(bContext *C, wmOperator *op)
506 {
507         sclip_zoom_set_factor(C, RNA_float_get(op->ptr, "factor"), NULL);
508
509         ED_region_tag_redraw(CTX_wm_region(C));
510
511         return OPERATOR_FINISHED;
512 }
513
514 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
515 {
516         if (event->type == MOUSEZOOM) {
517                 float factor;
518
519                 factor = 1.0f + (event->x - event->prevx + event->y - event->prevy) / 300.0f;
520                 RNA_float_set(op->ptr, "factor", factor);
521
522                 sclip_zoom_set_factor_exec(C, event, factor);
523
524                 return OPERATOR_FINISHED;
525         }
526         else {
527                 view_zoom_init(C, op, event);
528
529                 return OPERATOR_RUNNING_MODAL;
530         }
531 }
532
533 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
534 {
535         ViewZoomData *vpd = op->customdata;
536         float factor;
537
538         switch (event->type) {
539                 case MOUSEMOVE:
540                         factor = 1.0f + (vpd->x - event->x + vpd->y - event->y) / 300.0f;
541                         RNA_float_set(op->ptr, "factor", factor);
542                         sclip_zoom_set(C, vpd->zoom * factor, vpd->location);
543                         ED_region_tag_redraw(CTX_wm_region(C));
544                         break;
545                 default:
546                         if (event->type == vpd->event_type && event->val == KM_RELEASE) {
547                                 view_zoom_exit(C, op, 0);
548
549                                 return OPERATOR_FINISHED;
550                         }
551                         break;
552         }
553
554         return OPERATOR_RUNNING_MODAL;
555 }
556
557 static int view_zoom_cancel(bContext *C, wmOperator *op)
558 {
559         view_zoom_exit(C, op, 1);
560
561         return OPERATOR_CANCELLED;
562 }
563
564 void CLIP_OT_view_zoom(wmOperatorType *ot)
565 {
566         /* identifiers */
567         ot->name = "View Zoom";
568         ot->idname = "CLIP_OT_view_zoom";
569         ot->description = "Zoom in/out the view";
570
571         /* api callbacks */
572         ot->exec = view_zoom_exec;
573         ot->invoke = view_zoom_invoke;
574         ot->modal = view_zoom_modal;
575         ot->cancel = view_zoom_cancel;
576         ot->poll = ED_space_clip_view_clip_poll;
577
578         /* flags */
579         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
580
581         /* properties */
582         RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
583                 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
584 }
585
586 /********************** view zoom in/out operator *********************/
587
588 static int view_zoom_in_exec(bContext *C, wmOperator *op)
589 {
590         float location[2];
591
592         RNA_float_get_array(op->ptr, "location", location);
593
594         sclip_zoom_set_factor(C, 1.25f, location);
595
596         ED_region_tag_redraw(CTX_wm_region(C));
597
598         return OPERATOR_FINISHED;
599 }
600
601 static int view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event)
602 {
603         SpaceClip *sc = CTX_wm_space_clip(C);
604         ARegion *ar = CTX_wm_region(C);
605
606         float location[2];
607
608         ED_clip_mouse_pos(sc, ar, event->mval, location);
609         RNA_float_set_array(op->ptr, "location", location);
610
611         return view_zoom_in_exec(C, op);
612 }
613
614 void CLIP_OT_view_zoom_in(wmOperatorType *ot)
615 {
616         /* identifiers */
617         ot->name = "View Zoom In";
618         ot->idname = "CLIP_OT_view_zoom_in";
619         ot->description = "Zoom in the view";
620
621         /* api callbacks */
622         ot->exec = view_zoom_in_exec;
623         ot->invoke = view_zoom_in_invoke;
624         ot->poll = ED_space_clip_view_clip_poll;
625
626         /* properties */
627         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
628                              "Cursor location in screen coordinates", -10.0f, 10.0f);
629 }
630
631 static int view_zoom_out_exec(bContext *C, wmOperator *op)
632 {
633         float location[2];
634
635         RNA_float_get_array(op->ptr, "location", location);
636
637         sclip_zoom_set_factor(C, 0.8f, location);
638
639         ED_region_tag_redraw(CTX_wm_region(C));
640
641         return OPERATOR_FINISHED;
642 }
643
644 static int view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event)
645 {
646         SpaceClip *sc = CTX_wm_space_clip(C);
647         ARegion *ar = CTX_wm_region(C);
648
649         float location[2];
650
651         ED_clip_mouse_pos(sc, ar, event->mval, location);
652         RNA_float_set_array(op->ptr, "location", location);
653
654         return view_zoom_out_exec(C, op);
655 }
656
657 void CLIP_OT_view_zoom_out(wmOperatorType *ot)
658 {
659         /* identifiers */
660         ot->name = "View Zoom Out";
661         ot->idname = "CLIP_OT_view_zoom_out";
662         ot->description = "Zoom out the view";
663
664         /* api callbacks */
665         ot->exec = view_zoom_out_exec;
666         ot->invoke = view_zoom_out_invoke;
667         ot->poll = ED_space_clip_view_clip_poll;
668
669         /* properties */
670         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
671                              "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
672 }
673
674 /********************** view zoom ratio operator *********************/
675
676 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
677 {
678         SpaceClip *sc = CTX_wm_space_clip(C);
679
680         sclip_zoom_set(C, RNA_float_get(op->ptr, "ratio"), NULL);
681
682         /* ensure pixel exact locations for draw */
683         sc->xof = (int) sc->xof;
684         sc->yof = (int) sc->yof;
685
686         ED_region_tag_redraw(CTX_wm_region(C));
687
688         return OPERATOR_FINISHED;
689 }
690
691 void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
692 {
693         /* identifiers */
694         ot->name = "View Zoom Ratio";
695         ot->idname = "CLIP_OT_view_zoom_ratio";
696         ot->description = "Set the zoom ratio (based on clip size)";
697
698         /* api callbacks */
699         ot->exec = view_zoom_ratio_exec;
700         ot->poll = ED_space_clip_view_clip_poll;
701
702         /* properties */
703         RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
704                 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
705 }
706
707 /********************** view all operator *********************/
708
709 static int view_all_exec(bContext *C, wmOperator *op)
710 {
711         SpaceClip *sc;
712         ARegion *ar;
713         int w, h, width, height;
714         float aspx, aspy;
715         int fit_view = RNA_boolean_get(op->ptr, "fit_view");
716         float zoomx, zoomy;
717
718         /* retrieve state */
719         sc = CTX_wm_space_clip(C);
720         ar = CTX_wm_region(C);
721
722         ED_space_clip_get_size(sc, &w, &h);
723         ED_space_clip_get_aspect(sc, &aspx, &aspy);
724
725         w = w * aspx;
726         h = h * aspy;
727
728         /* check if the image will fit in the image with zoom == 1 */
729         width = ar->winrct.xmax - ar->winrct.xmin + 1;
730         height = ar->winrct.ymax - ar->winrct.ymin + 1;
731
732         if (fit_view) {
733                 const int margin = 5; /* margin from border */
734
735                 zoomx = (float) width / (w + 2 * margin);
736                 zoomy = (float) height / (h + 2 * margin);
737
738                 sclip_zoom_set(C, MIN2(zoomx, zoomy), NULL);
739         }
740         else {
741                 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
742                         zoomx = (float) width / w;
743                         zoomy = (float) height / h;
744
745                         /* find the zoom value that will fit the image in the image space */
746                         sclip_zoom_set(C, 1.0f / power_of_2(1.0f / MIN2(zoomx, zoomy)), NULL);
747                 }
748                 else
749                         sclip_zoom_set(C, 1.0f, NULL);
750         }
751
752         sc->xof = sc->yof = 0.0f;
753
754         ED_region_tag_redraw(CTX_wm_region(C));
755
756         return OPERATOR_FINISHED;
757 }
758
759 void CLIP_OT_view_all(wmOperatorType *ot)
760 {
761         /* identifiers */
762         ot->name = "View All";
763         ot->idname = "CLIP_OT_view_all";
764         ot->description = "View whole image with markers";
765
766         /* api callbacks */
767         ot->exec = view_all_exec;
768         ot->poll = ED_space_clip_view_clip_poll;
769
770         /* properties */
771         RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
772 }
773
774 /********************** view selected operator *********************/
775
776 static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
777 {
778         SpaceClip *sc = CTX_wm_space_clip(C);
779         ARegion *ar = CTX_wm_region(C);
780
781         sc->xlockof = 0.0f;
782         sc->ylockof = 0.0f;
783
784         ED_clip_view_selection(C, ar, 1);
785         ED_region_tag_redraw(CTX_wm_region(C));
786
787         return OPERATOR_FINISHED;
788 }
789
790 void CLIP_OT_view_selected(wmOperatorType *ot)
791 {
792         /* identifiers */
793         ot->name = "View Selected";
794         ot->idname = "CLIP_OT_view_selected";
795         ot->description = "View all selected elements";
796
797         /* api callbacks */
798         ot->exec = view_selected_exec;
799         ot->poll = ED_space_clip_view_clip_poll;
800 }
801
802 /********************** change frame operator *********************/
803
804 static int change_frame_poll(bContext *C)
805 {
806         /* prevent changes during render */
807         if (G.rendering)
808                 return 0;
809
810         return ED_space_clip_poll(C);
811 }
812
813 static void change_frame_apply(bContext *C, wmOperator *op)
814 {
815         Scene *scene = CTX_data_scene(C);
816
817         /* set the new frame number */
818         CFRA = RNA_int_get(op->ptr, "frame");
819         FRAMENUMBER_MIN_CLAMP(CFRA);
820         SUBFRA = 0.0f;
821
822         /* do updates */
823         sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
824         WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
825 }
826
827 static int change_frame_exec(bContext *C, wmOperator *op)
828 {
829         change_frame_apply(C, op);
830
831         return OPERATOR_FINISHED;
832 }
833
834 static int frame_from_event(bContext *C, wmEvent *event)
835 {
836         ARegion *ar = CTX_wm_region(C);
837         Scene *scene = CTX_data_scene(C);
838         int framenr = 0;
839
840         if (ar->regiontype == RGN_TYPE_WINDOW) {
841                 float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
842
843                 framenr = sfra + event->mval[0] / framelen;
844         }
845         else {
846                 float viewx, viewy;
847
848                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
849
850                 framenr = (int) floor(viewx + 0.5f);
851         }
852
853         return framenr;
854 }
855
856 static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
857 {
858         ARegion *ar = CTX_wm_region(C);
859
860         if (ar->regiontype == RGN_TYPE_WINDOW) {
861                 if (event->mval[1] > 16)
862                         return OPERATOR_PASS_THROUGH;
863         }
864
865         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
866
867         change_frame_apply(C, op);
868
869         /* add temp handler */
870         WM_event_add_modal_handler(C, op);
871
872         return OPERATOR_RUNNING_MODAL;
873 }
874
875 static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
876 {
877         switch (event->type) {
878                 case ESCKEY:
879                         return OPERATOR_FINISHED;
880
881                 case MOUSEMOVE:
882                         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
883                         change_frame_apply(C, op);
884                         break;
885
886                 case LEFTMOUSE:
887                 case RIGHTMOUSE:
888                         if (event->val == KM_RELEASE)
889                                 return OPERATOR_FINISHED;
890                         break;
891         }
892
893         return OPERATOR_RUNNING_MODAL;
894 }
895
896 void CLIP_OT_change_frame(wmOperatorType *ot)
897 {
898         /* identifiers */
899         ot->name = "Change frame";
900         ot->idname = "CLIP_OT_change_frame";
901         ot->description = "Interactively change the current frame number";
902
903         /* api callbacks */
904         ot->exec = change_frame_exec;
905         ot->invoke = change_frame_invoke;
906         ot->modal = change_frame_modal;
907         ot->poll = change_frame_poll;
908
909         /* flags */
910         ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
911
912         /* rna */
913         RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
914 }
915
916 /********************** rebuild proxies operator *********************/
917
918 typedef struct ProxyBuildJob {
919         Scene *scene;
920         struct Main *main;
921         MovieClip *clip;
922         int clip_flag, stop;
923         struct IndexBuildContext *index_context;
924 } ProxyJob;
925
926 static void proxy_freejob(void *pjv)
927 {
928         ProxyJob *pj = pjv;
929
930         MEM_freeN(pj);
931 }
932
933 static int proxy_bitflag_to_array(int size_flag, int build_sizes[4], int undistort)
934 {
935         int build_count = 0;
936         int size_flags[2][4] = {{MCLIP_PROXY_SIZE_25,
937                                  MCLIP_PROXY_SIZE_50,
938                                  MCLIP_PROXY_SIZE_75,
939                                  MCLIP_PROXY_SIZE_100},
940                                 {MCLIP_PROXY_UNDISTORTED_SIZE_25,
941                                  MCLIP_PROXY_UNDISTORTED_SIZE_50,
942                                  MCLIP_PROXY_UNDISTORTED_SIZE_75,
943                                  MCLIP_PROXY_UNDISTORTED_SIZE_100}};
944         int size_nr = undistort ? 1 : 0;
945
946         if (size_flag & size_flags[size_nr][0])
947                 build_sizes[build_count++] = MCLIP_PROXY_RENDER_SIZE_25;
948
949         if (size_flag & size_flags[size_nr][1])
950                 build_sizes[build_count++] = MCLIP_PROXY_RENDER_SIZE_50;
951
952         if (size_flag & size_flags[size_nr][2])
953                 build_sizes[build_count++] = MCLIP_PROXY_RENDER_SIZE_75;
954
955         if (size_flag & size_flags[size_nr][3])
956                 build_sizes[build_count++] = MCLIP_PROXY_RENDER_SIZE_100;
957
958         return build_count;
959 }
960
961 /* only this runs inside thread */
962 static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
963 {
964         ProxyJob *pj = pjv;
965         Scene *scene = pj->scene;
966         MovieClip *clip = pj->clip;
967         struct MovieDistortion *distortion = NULL;
968         short size_flag;
969         int cfra, sfra = SFRA, efra = EFRA;
970         int build_sizes[4], build_count = 0;
971         int build_undistort_sizes[4], build_undistort_count = 0;
972
973         size_flag = clip->proxy.build_size_flag;
974
975         build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0);
976         build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1);
977
978         if (clip->source == MCLIP_SRC_MOVIE) {
979                 if (pj->index_context)
980                         IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress);
981
982                 if (!build_undistort_count) {
983                         if (*stop)
984                                 pj->stop = 1;
985
986                         return;
987                 }
988                 else {
989                         sfra = 1;
990                         efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE);
991                 }
992         }
993
994         if (build_undistort_count)
995                 distortion = BKE_tracking_distortion_new();
996
997         for (cfra = sfra; cfra <= efra; cfra++) {
998                 if (clip->source != MCLIP_SRC_MOVIE)
999                         BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, NULL, cfra, build_sizes, build_count, 0);
1000
1001                 BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, distortion, cfra,
1002                                                 build_undistort_sizes, build_undistort_count, 1);
1003
1004                 if (*stop || G.afbreek)
1005                         break;
1006
1007                 *do_update = TRUE;
1008                 *progress = ((float) cfra - sfra) / (efra - sfra);
1009         }
1010
1011         if (distortion)
1012                 BKE_tracking_distortion_free(distortion);
1013
1014         if (*stop)
1015                 pj->stop = 1;
1016 }
1017
1018 static void proxy_endjob(void *pjv)
1019 {
1020         ProxyJob *pj = pjv;
1021
1022         if (pj->clip->anim)
1023                 IMB_close_anim_proxies(pj->clip->anim);
1024
1025         if (pj->index_context)
1026                 IMB_anim_index_rebuild_finish(pj->index_context, pj->stop);
1027
1028         BKE_movieclip_reload(pj->clip);
1029
1030         WM_main_add_notifier(NC_MOVIECLIP | ND_DISPLAY, pj->clip);
1031 }
1032
1033 static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
1034 {
1035         wmJob * steve;
1036         ProxyJob *pj;
1037         Scene *scene = CTX_data_scene(C);
1038         ScrArea *sa = CTX_wm_area(C);
1039         SpaceClip *sc = CTX_wm_space_clip(C);
1040         MovieClip *clip = ED_space_clip_get_clip(sc);
1041
1042         if ((clip->flag & MCLIP_USE_PROXY) == 0)
1043                 return OPERATOR_CANCELLED;
1044
1045         steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies", WM_JOB_PROGRESS);
1046
1047         pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
1048         pj->scene = scene;
1049         pj->main = CTX_data_main(C);
1050         pj->clip = clip;
1051         pj->clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
1052
1053         if (clip->anim) {
1054                 pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag,
1055                                         clip->proxy.build_size_flag, clip->proxy.quality);
1056         }
1057
1058         WM_jobs_customdata(steve, pj, proxy_freejob);
1059         WM_jobs_timer(steve, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
1060         WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL, proxy_endjob);
1061
1062         G.afbreek = 0;
1063         WM_jobs_start(CTX_wm_manager(C), steve);
1064
1065         ED_area_tag_redraw(CTX_wm_area(C));
1066
1067         return OPERATOR_FINISHED;
1068 }
1069
1070 void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
1071 {
1072         /* identifiers */
1073         ot->name = "Rebuild Proxy and Timecode Indices";
1074         ot->idname = "CLIP_OT_rebuild_proxy";
1075         ot->description = "Rebuild all selected proxies and timecode indices in the background";
1076
1077         /* api callbacks */
1078         ot->exec = clip_rebuild_proxy_exec;
1079         ot->poll = ED_space_clip_poll;
1080
1081         /* flags */
1082         ot->flag = OPTYPE_REGISTER;
1083 }
1084
1085 /********************** mode set operator *********************/
1086
1087 static int mode_set_exec(bContext *C, wmOperator *op)
1088 {
1089         SpaceClip *sc = CTX_wm_space_clip(C);
1090         int mode = RNA_enum_get(op->ptr, "mode");
1091
1092         sc->mode = mode;
1093
1094         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL);
1095
1096         return OPERATOR_FINISHED;
1097 }
1098
1099 void CLIP_OT_mode_set(wmOperatorType *ot)
1100 {
1101         /* identifiers */
1102         ot->name = "Set Clip Mode";
1103         ot->description = "Set the clip interaction mode";
1104         ot->idname = "CLIP_OT_mode_set";
1105
1106         /* api callbacks */
1107         ot->exec = mode_set_exec;
1108
1109         ot->poll = ED_space_clip_poll;
1110
1111         /* properties */
1112         RNA_def_enum(ot->srna, "mode", clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
1113 }
1114
1115 /********************** macroses *********************/
1116
1117 void ED_operatormacros_clip(void)
1118 {
1119         wmOperatorType *ot;
1120         wmOperatorTypeMacro *otmacro;
1121
1122         ot = WM_operatortype_append_macro("CLIP_OT_add_marker_move", "Add Marker and Move",
1123                                           "Add new marker and move it on movie", OPTYPE_UNDO | OPTYPE_REGISTER);
1124         WM_operatortype_macro_define(ot, "CLIP_OT_add_marker");
1125         otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
1126         RNA_struct_idprops_unset(otmacro->ptr, "release_confirm");
1127
1128         ot = WM_operatortype_append_macro("CLIP_OT_add_marker_slide", "Add Marker and Slide",
1129                                           "Add new marker and slide it with mouse until mouse button release",
1130                                           OPTYPE_UNDO | OPTYPE_REGISTER);
1131         WM_operatortype_macro_define(ot, "CLIP_OT_add_marker");
1132         otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
1133         RNA_boolean_set(otmacro->ptr, "release_confirm", TRUE);
1134 }