873eae0790132d22ecc938b4abbcd3170da2e208
[blender.git] / source / blender / editors / space_image / image_ops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spimage
22  */
23
24 #include <stddef.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #ifndef WIN32
30 #  include <unistd.h>
31 #else
32 #  include <io.h>
33 #endif
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_ghash.h"
39 #include "BLI_math.h"
40 #include "BLI_string.h"
41 #include "BLI_utildefines.h"
42
43 #include "BLT_translation.h"
44
45 #include "DNA_camera_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_node_types.h"
48 #include "DNA_packedFile_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51
52 #include "BKE_colortools.h"
53 #include "BKE_context.h"
54 #include "BKE_icons.h"
55 #include "BKE_image.h"
56 #include "BKE_image_save.h"
57 #include "BKE_global.h"
58 #include "BKE_library.h"
59 #include "BKE_main.h"
60 #include "BKE_packedFile.h"
61 #include "BKE_paint.h"
62 #include "BKE_report.h"
63 #include "BKE_screen.h"
64 #include "BKE_sound.h"
65 #include "BKE_scene.h"
66
67 #include "DEG_depsgraph.h"
68
69 #include "GPU_draw.h"
70 #include "GPU_state.h"
71 #include "GPU_immediate.h"
72
73 #include "IMB_colormanagement.h"
74 #include "IMB_imbuf.h"
75 #include "IMB_imbuf_types.h"
76 #include "IMB_moviecache.h"
77 #include "intern/openexr/openexr_multi.h"
78
79 #include "RE_pipeline.h"
80
81 #include "RNA_access.h"
82 #include "RNA_define.h"
83 #include "RNA_enum_types.h"
84
85 #include "ED_image.h"
86 #include "ED_mask.h"
87 #include "ED_paint.h"
88 #include "ED_render.h"
89 #include "ED_screen.h"
90 #include "ED_space_api.h"
91 #include "ED_uvedit.h"
92 #include "ED_util.h"
93
94 #include "UI_interface.h"
95 #include "UI_resources.h"
96 #include "UI_view2d.h"
97
98 #include "WM_api.h"
99 #include "WM_types.h"
100
101 #include "PIL_time.h"
102
103 #include "RE_engine.h"
104
105 #include "image_intern.h"
106
107 /******************** view navigation utilities *********************/
108
109 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float location[2])
110 {
111   float oldzoom = sima->zoom;
112   int width, height;
113
114   sima->zoom = zoom;
115
116   if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
117     /* check zoom limits */
118     ED_space_image_get_size(sima, &width, &height);
119
120     width *= sima->zoom;
121     height *= sima->zoom;
122
123     if ((width < 4) && (height < 4) && sima->zoom < oldzoom) {
124       sima->zoom = oldzoom;
125     }
126     else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom) {
127       sima->zoom = oldzoom;
128     }
129     else if (BLI_rcti_size_y(&ar->winrct) <= sima->zoom) {
130       sima->zoom = oldzoom;
131     }
132   }
133
134   if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) && location) {
135     float aspx, aspy, w, h;
136
137     ED_space_image_get_size(sima, &width, &height);
138     ED_space_image_get_aspect(sima, &aspx, &aspy);
139
140     w = width * aspx;
141     h = height * aspy;
142
143     sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
144     sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
145   }
146 }
147
148 static void sima_zoom_set_factor(SpaceImage *sima,
149                                  ARegion *ar,
150                                  float zoomfac,
151                                  const float location[2])
152 {
153   sima_zoom_set(sima, ar, sima->zoom * zoomfac, location);
154 }
155
156 /**
157  * Fits the view to the bounds exactly, caller should add margin if needed.
158  */
159 static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf *bounds)
160 {
161   int image_size[2];
162   float aspx, aspy;
163
164   ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
165   ED_space_image_get_aspect(sima, &aspx, &aspy);
166
167   image_size[0] = image_size[0] * aspx;
168   image_size[1] = image_size[1] * aspy;
169
170   /* adjust offset and zoom */
171   sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
172   sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
173
174   float size_xy[2], size;
175   size_xy[0] = BLI_rcti_size_x(&ar->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
176   size_xy[1] = BLI_rcti_size_y(&ar->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
177
178   size = min_ff(size_xy[0], size_xy[1]);
179   CLAMP_MAX(size, 100.0f);
180
181   sima_zoom_set(sima, ar, size, NULL);
182 }
183
184 static Image *image_from_context(const bContext *C)
185 {
186   /* Edit image is set by templates used throughout the interface, so image
187    * operations work outside the image editor. */
188   Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data;
189
190   if (ima) {
191     return ima;
192   }
193   else {
194     /* Image editor. */
195     SpaceImage *sima = CTX_wm_space_image(C);
196     return (sima) ? sima->image : NULL;
197   }
198 }
199
200 static ImageUser *image_user_from_context(const bContext *C)
201 {
202   /* Edit image user is set by templates used throughout the interface, so
203    * image operations work outside the image editor. */
204   ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data;
205
206   if (iuser) {
207     return iuser;
208   }
209   else {
210     /* Image editor. */
211     SpaceImage *sima = CTX_wm_space_image(C);
212     return (sima) ? &sima->iuser : NULL;
213   }
214 }
215
216 static bool image_buffer_exists_from_context(bContext *C)
217 {
218   Image *ima = image_from_context(C);
219   ImageUser *iuser = image_user_from_context(C);
220
221   if (ima == NULL) {
222     return false;
223   }
224
225   void *lock;
226   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
227   const bool has_buffer = (ibuf && (ibuf->rect || ibuf->rect_float));
228   BKE_image_release_ibuf(ima, ibuf, lock);
229   return has_buffer;
230 }
231
232 static bool image_not_packed_poll(bContext *C)
233 {
234   /* Do not run 'replace' on packed images, it does not give user expected results at all. */
235   Image *ima = image_from_context(C);
236   return (ima && BLI_listbase_is_empty(&ima->packedfiles));
237 }
238
239 static bool imbuf_format_writeable(const ImBuf *ibuf)
240 {
241   ImageFormatData im_format;
242   ImbFormatOptions options_dummy;
243   BKE_imbuf_to_image_format(&im_format, ibuf);
244   return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
245 }
246
247 static bool space_image_file_exists_poll(bContext *C)
248 {
249   if (image_buffer_exists_from_context(C) == false) {
250     return false;
251   }
252
253   Main *bmain = CTX_data_main(C);
254   Image *ima = image_from_context(C);
255   ImageUser *iuser = image_user_from_context(C);
256   void *lock;
257   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
258   bool ret = false;
259
260   if (ibuf) {
261     char name[FILE_MAX];
262     BLI_strncpy(name, ibuf->name, FILE_MAX);
263     BLI_path_abs(name, BKE_main_blendfile_path(bmain));
264
265     if (BLI_exists(name) == false) {
266       CTX_wm_operator_poll_msg_set(C, "image file not found");
267     }
268     else if (!BLI_file_is_writable(name)) {
269       CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
270     }
271     else if (!imbuf_format_writeable(ibuf)) {
272       CTX_wm_operator_poll_msg_set(C, "image format is read-only");
273     }
274     else {
275       ret = true;
276     }
277   }
278
279   BKE_image_release_ibuf(ima, ibuf, lock);
280   return ret;
281 }
282
283 bool space_image_main_region_poll(bContext *C)
284 {
285   SpaceImage *sima = CTX_wm_space_image(C);
286   /* XXX ARegion *ar = CTX_wm_region(C); */
287
288   if (sima) {
289     return true; /* XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW); */
290   }
291   return false;
292 }
293
294 /* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
295 static bool space_image_main_area_not_uv_brush_poll(bContext *C)
296 {
297   SpaceImage *sima = CTX_wm_space_image(C);
298   Scene *scene = CTX_data_scene(C);
299   ToolSettings *toolsettings = scene->toolsettings;
300
301   if (sima && !toolsettings->uvsculpt && (CTX_data_edit_object(C) == NULL)) {
302     return 1;
303   }
304
305   return 0;
306 }
307
308 static bool image_sample_poll(bContext *C)
309 {
310   SpaceImage *sima = CTX_wm_space_image(C);
311   if (sima == NULL) {
312     return false;
313   }
314
315   Object *obedit = CTX_data_edit_object(C);
316   if (obedit) {
317     /* Disable when UV editing so it doesn't swallow all click events
318      * (use for setting cursor). */
319     if (ED_space_image_show_uvedit(sima, obedit)) {
320       return false;
321     }
322   }
323   else if (sima->mode != SI_MODE_VIEW) {
324     return false;
325   }
326
327   return true;
328 }
329 /********************** view pan operator *********************/
330
331 typedef struct ViewPanData {
332   float x, y;
333   float xof, yof;
334   int event_type;
335 } ViewPanData;
336
337 static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
338 {
339   SpaceImage *sima = CTX_wm_space_image(C);
340   ViewPanData *vpd;
341
342   op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
343   WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
344
345   vpd->x = event->x;
346   vpd->y = event->y;
347   vpd->xof = sima->xof;
348   vpd->yof = sima->yof;
349   vpd->event_type = event->type;
350
351   WM_event_add_modal_handler(C, op);
352 }
353
354 static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
355 {
356   SpaceImage *sima = CTX_wm_space_image(C);
357   ViewPanData *vpd = op->customdata;
358
359   if (cancel) {
360     sima->xof = vpd->xof;
361     sima->yof = vpd->yof;
362     ED_region_tag_redraw(CTX_wm_region(C));
363   }
364
365   WM_cursor_modal_restore(CTX_wm_window(C));
366   MEM_freeN(op->customdata);
367 }
368
369 static int image_view_pan_exec(bContext *C, wmOperator *op)
370 {
371   SpaceImage *sima = CTX_wm_space_image(C);
372   float offset[2];
373
374   RNA_float_get_array(op->ptr, "offset", offset);
375   sima->xof += offset[0];
376   sima->yof += offset[1];
377
378   ED_region_tag_redraw(CTX_wm_region(C));
379
380   return OPERATOR_FINISHED;
381 }
382
383 static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
384 {
385   if (event->type == MOUSEPAN) {
386     SpaceImage *sima = CTX_wm_space_image(C);
387     float offset[2];
388
389     offset[0] = (event->prevx - event->x) / sima->zoom;
390     offset[1] = (event->prevy - event->y) / sima->zoom;
391     RNA_float_set_array(op->ptr, "offset", offset);
392
393     image_view_pan_exec(C, op);
394     return OPERATOR_FINISHED;
395   }
396   else {
397     image_view_pan_init(C, op, event);
398     return OPERATOR_RUNNING_MODAL;
399   }
400 }
401
402 static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
403 {
404   SpaceImage *sima = CTX_wm_space_image(C);
405   ViewPanData *vpd = op->customdata;
406   float offset[2];
407
408   switch (event->type) {
409     case MOUSEMOVE:
410       sima->xof = vpd->xof;
411       sima->yof = vpd->yof;
412       offset[0] = (vpd->x - event->x) / sima->zoom;
413       offset[1] = (vpd->y - event->y) / sima->zoom;
414       RNA_float_set_array(op->ptr, "offset", offset);
415       image_view_pan_exec(C, op);
416       break;
417     default:
418       if (event->type == vpd->event_type && event->val == KM_RELEASE) {
419         image_view_pan_exit(C, op, false);
420         return OPERATOR_FINISHED;
421       }
422       break;
423   }
424
425   return OPERATOR_RUNNING_MODAL;
426 }
427
428 static void image_view_pan_cancel(bContext *C, wmOperator *op)
429 {
430   image_view_pan_exit(C, op, true);
431 }
432
433 void IMAGE_OT_view_pan(wmOperatorType *ot)
434 {
435   /* identifiers */
436   ot->name = "Pan View";
437   ot->idname = "IMAGE_OT_view_pan";
438   ot->description = "Pan the view";
439
440   /* api callbacks */
441   ot->exec = image_view_pan_exec;
442   ot->invoke = image_view_pan_invoke;
443   ot->modal = image_view_pan_modal;
444   ot->cancel = image_view_pan_cancel;
445   ot->poll = space_image_main_region_poll;
446
447   /* flags */
448   ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
449
450   /* properties */
451   RNA_def_float_vector(ot->srna,
452                        "offset",
453                        2,
454                        NULL,
455                        -FLT_MAX,
456                        FLT_MAX,
457                        "Offset",
458                        "Offset in floating point units, 1.0 is the width and height of the image",
459                        -FLT_MAX,
460                        FLT_MAX);
461 }
462
463 /********************** view zoom operator *********************/
464
465 typedef struct ViewZoomData {
466   float origx, origy;
467   float zoom;
468   int event_type;
469   float location[2];
470
471   /* needed for continuous zoom */
472   wmTimer *timer;
473   double timer_lastdraw;
474
475   /* */
476   SpaceImage *sima;
477   ARegion *ar;
478 } ViewZoomData;
479
480 static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
481 {
482   SpaceImage *sima = CTX_wm_space_image(C);
483   ARegion *ar = CTX_wm_region(C);
484   ViewZoomData *vpd;
485
486   op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
487   WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
488
489   vpd->origx = event->x;
490   vpd->origy = event->y;
491   vpd->zoom = sima->zoom;
492   vpd->event_type = event->type;
493
494   UI_view2d_region_to_view(
495       &ar->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
496
497   if (U.viewzoom == USER_ZOOM_CONT) {
498     /* needs a timer to continue redrawing */
499     vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
500     vpd->timer_lastdraw = PIL_check_seconds_timer();
501   }
502
503   vpd->sima = sima;
504   vpd->ar = ar;
505
506   WM_event_add_modal_handler(C, op);
507 }
508
509 static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
510 {
511   SpaceImage *sima = CTX_wm_space_image(C);
512   ViewZoomData *vpd = op->customdata;
513
514   if (cancel) {
515     sima->zoom = vpd->zoom;
516     ED_region_tag_redraw(CTX_wm_region(C));
517   }
518
519   if (vpd->timer) {
520     WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
521   }
522
523   WM_cursor_modal_restore(CTX_wm_window(C));
524   MEM_freeN(op->customdata);
525 }
526
527 static int image_view_zoom_exec(bContext *C, wmOperator *op)
528 {
529   SpaceImage *sima = CTX_wm_space_image(C);
530   ARegion *ar = CTX_wm_region(C);
531
532   sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"), NULL);
533
534   ED_region_tag_redraw(ar);
535
536   return OPERATOR_FINISHED;
537 }
538
539 enum {
540   VIEW_PASS = 0,
541   VIEW_APPLY,
542   VIEW_CONFIRM,
543 };
544
545 static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
546 {
547   if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
548     SpaceImage *sima = CTX_wm_space_image(C);
549     ARegion *ar = CTX_wm_region(C);
550     float delta, factor, location[2];
551
552     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
553
554     delta = event->prevx - event->x + event->prevy - event->y;
555
556     if (U.uiflag & USER_ZOOM_INVERT) {
557       delta *= -1;
558     }
559
560     factor = 1.0f + delta / 300.0f;
561     RNA_float_set(op->ptr, "factor", factor);
562     sima_zoom_set(sima, ar, sima->zoom * factor, location);
563     ED_region_tag_redraw(ar);
564
565     return OPERATOR_FINISHED;
566   }
567   else {
568     image_view_zoom_init(C, op, event);
569     return OPERATOR_RUNNING_MODAL;
570   }
571 }
572
573 static void image_zoom_apply(ViewZoomData *vpd,
574                              wmOperator *op,
575                              const int x,
576                              const int y,
577                              const short viewzoom,
578                              const short zoom_invert)
579 {
580   float factor;
581
582   if (viewzoom == USER_ZOOM_CONT) {
583     double time = PIL_check_seconds_timer();
584     float time_step = (float)(time - vpd->timer_lastdraw);
585     float fac;
586     float zfac;
587
588     if (U.uiflag & USER_ZOOM_HORIZ) {
589       fac = (float)(x - vpd->origx);
590     }
591     else {
592       fac = (float)(y - vpd->origy);
593     }
594
595     if (zoom_invert) {
596       fac = -fac;
597     }
598
599     /* oldstyle zoom */
600     zfac = 1.0f + ((fac / 20.0f) * time_step);
601     vpd->timer_lastdraw = time;
602     /* this is the final zoom, but instead make it into a factor */
603     // zoom = vpd->sima->zoom * zfac;
604     factor = (vpd->sima->zoom * zfac) / vpd->zoom;
605   }
606   else {
607     /* for now do the same things for scale and dolly */
608     float delta = x - vpd->origx + y - vpd->origy;
609
610     if (zoom_invert) {
611       delta *= -1.0f;
612     }
613
614     factor = 1.0f + delta / 300.0f;
615   }
616
617   RNA_float_set(op->ptr, "factor", factor);
618   sima_zoom_set(vpd->sima, vpd->ar, vpd->zoom * factor, vpd->location);
619   ED_region_tag_redraw(vpd->ar);
620 }
621
622 static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
623 {
624   ViewZoomData *vpd = op->customdata;
625   short event_code = VIEW_PASS;
626
627   /* execute the events */
628   if (event->type == TIMER && event->customdata == vpd->timer) {
629     /* continuous zoom */
630     event_code = VIEW_APPLY;
631   }
632   else if (event->type == MOUSEMOVE) {
633     event_code = VIEW_APPLY;
634   }
635   else if (event->type == vpd->event_type && event->val == KM_RELEASE) {
636     event_code = VIEW_CONFIRM;
637   }
638
639   if (event_code == VIEW_APPLY) {
640     image_zoom_apply(vpd, op, event->x, event->y, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
641   }
642   else if (event_code == VIEW_CONFIRM) {
643     image_view_zoom_exit(C, op, false);
644     return OPERATOR_FINISHED;
645   }
646
647   return OPERATOR_RUNNING_MODAL;
648 }
649
650 static void image_view_zoom_cancel(bContext *C, wmOperator *op)
651 {
652   image_view_zoom_exit(C, op, true);
653 }
654
655 void IMAGE_OT_view_zoom(wmOperatorType *ot)
656 {
657   PropertyRNA *prop;
658
659   /* identifiers */
660   ot->name = "Zoom View";
661   ot->idname = "IMAGE_OT_view_zoom";
662   ot->description = "Zoom in/out the image";
663
664   /* api callbacks */
665   ot->exec = image_view_zoom_exec;
666   ot->invoke = image_view_zoom_invoke;
667   ot->modal = image_view_zoom_modal;
668   ot->cancel = image_view_zoom_cancel;
669   ot->poll = space_image_main_region_poll;
670
671   /* flags */
672   ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
673
674   /* properties */
675   prop = RNA_def_float(ot->srna,
676                        "factor",
677                        0.0f,
678                        -FLT_MAX,
679                        FLT_MAX,
680                        "Factor",
681                        "Zoom factor, values higher than 1.0 zoom in, lower values zoom out",
682                        -FLT_MAX,
683                        FLT_MAX);
684   RNA_def_property_flag(prop, PROP_HIDDEN);
685 }
686
687 #ifdef WITH_INPUT_NDOF
688 /********************** NDOF operator *********************/
689
690 /* Combined pan/zoom from a 3D mouse device.
691  * Z zooms, XY pans
692  * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
693  * that explains the negative signs in the code below
694  */
695
696 static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
697 {
698   if (event->type != NDOF_MOTION) {
699     return OPERATOR_CANCELLED;
700   }
701   else {
702     SpaceImage *sima = CTX_wm_space_image(C);
703     ARegion *ar = CTX_wm_region(C);
704     float pan_vec[3];
705
706     const wmNDOFMotionData *ndof = event->customdata;
707     const float speed = NDOF_PIXELS_PER_SECOND;
708
709     WM_event_ndof_pan_get(ndof, pan_vec, true);
710
711     mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
712     pan_vec[2] *= -ndof->dt;
713
714     sima_zoom_set_factor(sima, ar, 1.0f + pan_vec[2], NULL);
715     sima->xof += pan_vec[0];
716     sima->yof += pan_vec[1];
717
718     ED_region_tag_redraw(ar);
719
720     return OPERATOR_FINISHED;
721   }
722 }
723
724 void IMAGE_OT_view_ndof(wmOperatorType *ot)
725 {
726   /* identifiers */
727   ot->name = "NDOF Pan/Zoom";
728   ot->idname = "IMAGE_OT_view_ndof";
729   ot->description = "Use a 3D mouse device to pan/zoom the view";
730
731   /* api callbacks */
732   ot->invoke = image_view_ndof_invoke;
733   ot->poll = space_image_main_region_poll;
734
735   /* flags */
736   ot->flag = OPTYPE_LOCK_BYPASS;
737 }
738 #endif /* WITH_INPUT_NDOF */
739
740 /********************** view all operator *********************/
741
742 /* Updates the fields of the View2D member of the SpaceImage struct.
743  * Default behavior is to reset the position of the image and set the zoom to 1
744  * If the image will not fit within the window rectangle, the zoom is adjusted */
745
746 static int image_view_all_exec(bContext *C, wmOperator *op)
747 {
748   SpaceImage *sima;
749   ARegion *ar;
750   float aspx, aspy, zoomx, zoomy, w, h;
751   int width, height;
752   const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
753
754   /* retrieve state */
755   sima = CTX_wm_space_image(C);
756   ar = CTX_wm_region(C);
757
758   ED_space_image_get_size(sima, &width, &height);
759   ED_space_image_get_aspect(sima, &aspx, &aspy);
760
761   w = width * aspx;
762   h = height * aspy;
763
764   /* check if the image will fit in the image with (zoom == 1) */
765   width = BLI_rcti_size_x(&ar->winrct) + 1;
766   height = BLI_rcti_size_y(&ar->winrct) + 1;
767
768   if (fit_view) {
769     const int margin = 5; /* margin from border */
770
771     zoomx = (float)width / (w + 2 * margin);
772     zoomy = (float)height / (h + 2 * margin);
773
774     sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL);
775   }
776   else {
777     if ((w >= width || h >= height) && (width > 0 && height > 0)) {
778       zoomx = (float)width / w;
779       zoomy = (float)height / h;
780
781       /* find the zoom value that will fit the image in the image space */
782       sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL);
783     }
784     else {
785       sima_zoom_set(sima, ar, 1.0f, NULL);
786     }
787   }
788
789   sima->xof = sima->yof = 0.0f;
790
791   ED_region_tag_redraw(ar);
792
793   return OPERATOR_FINISHED;
794 }
795
796 void IMAGE_OT_view_all(wmOperatorType *ot)
797 {
798   PropertyRNA *prop;
799
800   /* identifiers */
801   ot->name = "View All";
802   ot->idname = "IMAGE_OT_view_all";
803   ot->description = "View the entire image";
804
805   /* api callbacks */
806   ot->exec = image_view_all_exec;
807   ot->poll = space_image_main_region_poll;
808
809   /* flags */
810   ot->flag = OPTYPE_LOCK_BYPASS;
811
812   /* properties */
813   prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
814   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
815 }
816
817 /********************** view selected operator *********************/
818
819 static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
820 {
821   SpaceImage *sima;
822   ARegion *ar;
823   Scene *scene;
824   ViewLayer *view_layer;
825   Object *obedit;
826   Image *ima;
827
828   /* retrieve state */
829   sima = CTX_wm_space_image(C);
830   ar = CTX_wm_region(C);
831   scene = CTX_data_scene(C);
832   view_layer = CTX_data_view_layer(C);
833   obedit = CTX_data_edit_object(C);
834
835   ima = ED_space_image(sima);
836
837   /* get bounds */
838   float min[2], max[2];
839   if (ED_space_image_show_uvedit(sima, obedit)) {
840     if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) {
841       return OPERATOR_CANCELLED;
842     }
843   }
844   else if (ED_space_image_check_show_maskedit(sima, view_layer)) {
845     if (!ED_mask_selected_minmax(C, min, max)) {
846       return OPERATOR_CANCELLED;
847     }
848   }
849   rctf bounds = {
850       .xmin = min[0],
851       .ymin = min[1],
852       .xmax = max[0],
853       .ymax = max[1],
854   };
855
856   /* add some margin */
857   BLI_rctf_scale(&bounds, 1.4f);
858
859   sima_zoom_set_from_bounds(sima, ar, &bounds);
860
861   ED_region_tag_redraw(ar);
862
863   return OPERATOR_FINISHED;
864 }
865
866 static bool image_view_selected_poll(bContext *C)
867 {
868   return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
869 }
870
871 void IMAGE_OT_view_selected(wmOperatorType *ot)
872 {
873   /* identifiers */
874   ot->name = "View Center";
875   ot->idname = "IMAGE_OT_view_selected";
876   ot->description = "View all selected UVs";
877
878   /* api callbacks */
879   ot->exec = image_view_selected_exec;
880   ot->poll = image_view_selected_poll;
881 }
882
883 /********************** view zoom in/out operator *********************/
884
885 static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
886 {
887   SpaceImage *sima = CTX_wm_space_image(C);
888   ARegion *ar = CTX_wm_region(C);
889   float location[2];
890
891   RNA_float_get_array(op->ptr, "location", location);
892
893   sima_zoom_set_factor(sima, ar, powf(2.0f, 1.0f / 3.0f), location);
894
895   ED_region_tag_redraw(ar);
896
897   return OPERATOR_FINISHED;
898 }
899
900 static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
901 {
902   ARegion *ar = CTX_wm_region(C);
903   float location[2];
904
905   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
906   RNA_float_set_array(op->ptr, "location", location);
907
908   return image_view_zoom_in_exec(C, op);
909 }
910
911 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
912 {
913   PropertyRNA *prop;
914
915   /* identifiers */
916   ot->name = "View Zoom In";
917   ot->idname = "IMAGE_OT_view_zoom_in";
918   ot->description = "Zoom in the image (centered around 2D cursor)";
919
920   /* api callbacks */
921   ot->invoke = image_view_zoom_in_invoke;
922   ot->exec = image_view_zoom_in_exec;
923   ot->poll = space_image_main_region_poll;
924
925   /* flags */
926   ot->flag = OPTYPE_LOCK_BYPASS;
927
928   /* properties */
929   prop = RNA_def_float_vector(ot->srna,
930                               "location",
931                               2,
932                               NULL,
933                               -FLT_MAX,
934                               FLT_MAX,
935                               "Location",
936                               "Cursor location in screen coordinates",
937                               -10.0f,
938                               10.0f);
939   RNA_def_property_flag(prop, PROP_HIDDEN);
940 }
941
942 static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
943 {
944   SpaceImage *sima = CTX_wm_space_image(C);
945   ARegion *ar = CTX_wm_region(C);
946   float location[2];
947
948   RNA_float_get_array(op->ptr, "location", location);
949
950   sima_zoom_set_factor(sima, ar, powf(0.5f, 1.0f / 3.0f), location);
951
952   ED_region_tag_redraw(ar);
953
954   return OPERATOR_FINISHED;
955 }
956
957 static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
958 {
959   ARegion *ar = CTX_wm_region(C);
960   float location[2];
961
962   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
963   RNA_float_set_array(op->ptr, "location", location);
964
965   return image_view_zoom_out_exec(C, op);
966 }
967
968 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
969 {
970   PropertyRNA *prop;
971
972   /* identifiers */
973   ot->name = "View Zoom Out";
974   ot->idname = "IMAGE_OT_view_zoom_out";
975   ot->description = "Zoom out the image (centered around 2D cursor)";
976
977   /* api callbacks */
978   ot->invoke = image_view_zoom_out_invoke;
979   ot->exec = image_view_zoom_out_exec;
980   ot->poll = space_image_main_region_poll;
981
982   /* flags */
983   ot->flag = OPTYPE_LOCK_BYPASS;
984
985   /* properties */
986   prop = RNA_def_float_vector(ot->srna,
987                               "location",
988                               2,
989                               NULL,
990                               -FLT_MAX,
991                               FLT_MAX,
992                               "Location",
993                               "Cursor location in screen coordinates",
994                               -10.0f,
995                               10.0f);
996   RNA_def_property_flag(prop, PROP_HIDDEN);
997 }
998
999 /********************** view zoom ratio operator *********************/
1000
1001 static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
1002 {
1003   SpaceImage *sima = CTX_wm_space_image(C);
1004   ARegion *ar = CTX_wm_region(C);
1005
1006   sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"), NULL);
1007
1008   /* ensure pixel exact locations for draw */
1009   sima->xof = (int)sima->xof;
1010   sima->yof = (int)sima->yof;
1011
1012   ED_region_tag_redraw(ar);
1013
1014   return OPERATOR_FINISHED;
1015 }
1016
1017 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
1018 {
1019   /* identifiers */
1020   ot->name = "View Zoom Ratio";
1021   ot->idname = "IMAGE_OT_view_zoom_ratio";
1022   ot->description = "Set zoom ratio of the view";
1023
1024   /* api callbacks */
1025   ot->exec = image_view_zoom_ratio_exec;
1026   ot->poll = space_image_main_region_poll;
1027
1028   /* flags */
1029   ot->flag = OPTYPE_LOCK_BYPASS;
1030
1031   /* properties */
1032   RNA_def_float(ot->srna,
1033                 "ratio",
1034                 0.0f,
1035                 -FLT_MAX,
1036                 FLT_MAX,
1037                 "Ratio",
1038                 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
1039                 -FLT_MAX,
1040                 FLT_MAX);
1041 }
1042
1043 /********************** view border-zoom operator *********************/
1044
1045 static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
1046 {
1047   SpaceImage *sima = CTX_wm_space_image(C);
1048   ARegion *ar = CTX_wm_region(C);
1049   rctf bounds;
1050   const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1051
1052   WM_operator_properties_border_to_rctf(op, &bounds);
1053
1054   UI_view2d_region_to_view_rctf(&ar->v2d, &bounds, &bounds);
1055
1056   const struct {
1057     float xof;
1058     float yof;
1059     float zoom;
1060   } sima_view_prev = {
1061       .xof = sima->xof,
1062       .yof = sima->yof,
1063       .zoom = sima->zoom,
1064   };
1065
1066   sima_zoom_set_from_bounds(sima, ar, &bounds);
1067
1068   /* zoom out */
1069   if (!zoom_in) {
1070     sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
1071     sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
1072     sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
1073   }
1074
1075   ED_region_tag_redraw(ar);
1076
1077   return OPERATOR_FINISHED;
1078 }
1079
1080 void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
1081 {
1082   /* identifiers */
1083   ot->name = "Zoom to Border";
1084   ot->description = "Zoom in the view to the nearest item contained in the border";
1085   ot->idname = "IMAGE_OT_view_zoom_border";
1086
1087   /* api callbacks */
1088   ot->invoke = WM_gesture_box_invoke;
1089   ot->exec = image_view_zoom_border_exec;
1090   ot->modal = WM_gesture_box_modal;
1091   ot->cancel = WM_gesture_box_cancel;
1092
1093   ot->poll = space_image_main_region_poll;
1094
1095   /* rna */
1096   WM_operator_properties_gesture_box_zoom(ot);
1097 }
1098
1099 /**************** load/replace/save callbacks ******************/
1100 static void image_filesel(bContext *C, wmOperator *op, const char *path)
1101 {
1102   RNA_string_set(op->ptr, "filepath", path);
1103   WM_event_add_fileselect(C, op);
1104 }
1105
1106 /******************** open image operator ********************/
1107
1108 typedef struct ImageOpenData {
1109   PropertyPointerRNA pprop;
1110   ImageUser *iuser;
1111   ImageFormatData im_format;
1112 } ImageOpenData;
1113
1114 typedef struct ImageFrameRange {
1115   struct ImageFrameRange *next, *prev;
1116   ListBase frames;
1117   /**  The full path of the first file in the list of image files */
1118   char filepath[FILE_MAX];
1119 } ImageFrameRange;
1120
1121 typedef struct ImageFrame {
1122   struct ImageFrame *next, *prev;
1123   int framenr;
1124 } ImageFrame;
1125
1126 static void image_open_init(bContext *C, wmOperator *op)
1127 {
1128   ImageOpenData *iod;
1129   op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
1130   iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
1131   UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
1132 }
1133
1134 static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
1135 {
1136   MEM_freeN(op->customdata);
1137   op->customdata = NULL;
1138 }
1139
1140 /**
1141  * Get a list of frames from the list of image files matching the first file name sequence pattern.
1142  * \param ptr[in]: The RNA pointer containing the "directory" entry and "files" collection.
1143  * \param frames_all[out]: the list of frame numbers found in the files matching
1144  * the first one by name.
1145  */
1146 static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
1147 {
1148   char dir[FILE_MAXDIR];
1149   const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
1150   ImageFrameRange *frame_range = NULL;
1151
1152   RNA_string_get(ptr, "directory", dir);
1153   RNA_BEGIN (ptr, itemptr, "files") {
1154     char base_head[FILE_MAX], base_tail[FILE_MAX];
1155     char head[FILE_MAX], tail[FILE_MAX];
1156     unsigned short digits;
1157     char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
1158     ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
1159
1160     /* use the first file in the list as base filename */
1161     frame->framenr = BLI_stringdec(filename, head, tail, &digits);
1162
1163     /* still in the same sequence */
1164     if (do_frame_range && (frame_range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
1165         (STREQLEN(base_tail, tail, FILE_MAX))) {
1166       /* pass */
1167     }
1168     else {
1169       /* start a new frame range */
1170       frame_range = MEM_callocN(sizeof(*frame_range), __func__);
1171       BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
1172       BLI_addtail(frames_all, frame_range);
1173
1174       BLI_strncpy(base_head, head, sizeof(base_head));
1175       BLI_strncpy(base_tail, tail, sizeof(base_tail));
1176     }
1177
1178     BLI_addtail(&frame_range->frames, frame);
1179     MEM_freeN(filename);
1180   }
1181   RNA_END;
1182 }
1183
1184 static int image_cmp_frame(const void *a, const void *b)
1185 {
1186   const ImageFrame *frame_a = a;
1187   const ImageFrame *frame_b = b;
1188
1189   if (frame_a->framenr < frame_b->framenr) {
1190     return -1;
1191   }
1192   if (frame_a->framenr > frame_b->framenr) {
1193     return 1;
1194   }
1195   return 0;
1196 }
1197
1198 /**
1199  * Return the start (offset) and the length of the sequence of
1200  * continuous frames in the list of frames.
1201  *
1202  * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted.
1203  * \param ofs: [out] offset the first frame number in the sequence.
1204  * \return the number of contiguous frames in the sequence
1205  */
1206 static int image_sequence_get_len(ListBase *frames, int *ofs)
1207 {
1208   ImageFrame *frame;
1209
1210   BLI_listbase_sort(frames, image_cmp_frame);
1211
1212   frame = frames->first;
1213   if (frame) {
1214     int frame_curr = frame->framenr;
1215     (*ofs) = frame_curr;
1216     while (frame && (frame->framenr == frame_curr)) {
1217       frame_curr++;
1218       frame = frame->next;
1219     }
1220     return frame_curr - (*ofs);
1221   }
1222   *ofs = 0;
1223   return 0;
1224 }
1225
1226 static Image *image_open_single(Main *bmain,
1227                                 wmOperator *op,
1228                                 const char *filepath,
1229                                 const char *relbase,
1230                                 bool is_relative_path,
1231                                 bool use_multiview,
1232                                 int frame_seq_len)
1233 {
1234   bool exists = false;
1235   Image *ima = NULL;
1236
1237   errno = 0;
1238   ima = BKE_image_load_exists_ex(bmain, filepath, &exists);
1239
1240   if (!ima) {
1241     if (op->customdata) {
1242       MEM_freeN(op->customdata);
1243     }
1244     BKE_reportf(op->reports,
1245                 RPT_ERROR,
1246                 "Cannot read '%s': %s",
1247                 filepath,
1248                 errno ? strerror(errno) : TIP_("unsupported image format"));
1249     return NULL;
1250   }
1251
1252   if (!exists) {
1253     /* only image path after save, never ibuf */
1254     if (is_relative_path) {
1255       BLI_path_rel(ima->name, relbase);
1256     }
1257
1258     /* handle multiview images */
1259     if (use_multiview) {
1260       ImageOpenData *iod = op->customdata;
1261       ImageFormatData *imf = &iod->im_format;
1262
1263       ima->flag |= IMA_USE_VIEWS;
1264       ima->views_format = imf->views_format;
1265       *ima->stereo3d_format = imf->stereo3d_format;
1266     }
1267     else {
1268       ima->flag &= ~IMA_USE_VIEWS;
1269       BKE_image_free_views(ima);
1270     }
1271
1272     if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
1273       ima->source = IMA_SRC_SEQUENCE;
1274     }
1275   }
1276
1277   return ima;
1278 }
1279
1280 static int image_open_exec(bContext *C, wmOperator *op)
1281 {
1282   Main *bmain = CTX_data_main(C);
1283   ScrArea *sa = CTX_wm_area(C);
1284   Scene *scene = CTX_data_scene(C);
1285   Object *obedit = CTX_data_edit_object(C);
1286   ImageUser *iuser = NULL;
1287   ImageOpenData *iod = op->customdata;
1288   Image *ima = NULL;
1289   char filepath[FILE_MAX];
1290   int frame_seq_len = 0;
1291   int frame_ofs = 1;
1292
1293   const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1294   const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1295
1296   if (!op->customdata) {
1297     image_open_init(C, op);
1298   }
1299
1300   RNA_string_get(op->ptr, "filepath", filepath);
1301
1302   if (RNA_struct_property_is_set(op->ptr, "directory") &&
1303       RNA_struct_property_is_set(op->ptr, "files")) {
1304     bool was_relative = BLI_path_is_rel(filepath);
1305     ListBase frame_ranges_all;
1306
1307     BLI_listbase_clear(&frame_ranges_all);
1308     image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
1309     for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range;
1310          frame_range = frame_range->next) {
1311       int frame_range_ofs;
1312       int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
1313       BLI_freelistN(&frame_range->frames);
1314
1315       char filepath_range[FILE_MAX];
1316       BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
1317
1318       if (was_relative) {
1319         BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
1320       }
1321
1322       Image *ima_range = image_open_single(bmain,
1323                                            op,
1324                                            filepath_range,
1325                                            BKE_main_blendfile_path(bmain),
1326                                            is_relative_path,
1327                                            use_multiview,
1328                                            frame_range_seq_len);
1329
1330       /* take the first image */
1331       if ((ima == NULL) && ima_range) {
1332         ima = ima_range;
1333         frame_seq_len = frame_range_seq_len;
1334         frame_ofs = frame_range_ofs;
1335       }
1336     }
1337     BLI_freelistN(&frame_ranges_all);
1338   }
1339   else {
1340     /* for drag & drop etc. */
1341     ima = image_open_single(
1342         bmain, op, filepath, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview, 1);
1343   }
1344
1345   if (ima == NULL) {
1346     return OPERATOR_CANCELLED;
1347   }
1348
1349   /* hook into UI */
1350   iod = op->customdata;
1351
1352   if (iod->pprop.prop) {
1353     /* when creating new ID blocks, use is already 1, but RNA
1354      * pointer use also increases user, so this compensates it */
1355     id_us_min(&ima->id);
1356
1357     PointerRNA imaptr;
1358     RNA_id_pointer_create(&ima->id, &imaptr);
1359     RNA_property_pointer_set(NULL, &iod->pprop.ptr, iod->pprop.prop, imaptr);
1360     RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1361   }
1362
1363   if (iod->iuser) {
1364     iuser = iod->iuser;
1365   }
1366   else if (sa && sa->spacetype == SPACE_IMAGE) {
1367     SpaceImage *sima = sa->spacedata.first;
1368     ED_space_image_set(bmain, sima, obedit, ima, false);
1369     iuser = &sima->iuser;
1370   }
1371   else {
1372     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1373     if (tex && tex->type == TEX_IMAGE) {
1374       iuser = &tex->iuser;
1375     }
1376
1377     if (iuser == NULL) {
1378       Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
1379       if (cam) {
1380         for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
1381           if (bgpic->ima == ima) {
1382             iuser = &bgpic->iuser;
1383             break;
1384           }
1385         }
1386       }
1387     }
1388   }
1389
1390   /* initialize because of new image */
1391   if (iuser) {
1392     iuser->frames = frame_seq_len;
1393     iuser->sfra = 1;
1394     iuser->framenr = 1;
1395     if (ima->source == IMA_SRC_MOVIE) {
1396       iuser->offset = 0;
1397     }
1398     else {
1399       iuser->offset = frame_ofs - 1;
1400     }
1401     iuser->scene = scene;
1402     BKE_image_init_imageuser(ima, iuser);
1403   }
1404
1405   /* XXX unpackImage frees image buffers */
1406   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1407
1408   BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1409   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1410
1411   MEM_freeN(op->customdata);
1412
1413   return OPERATOR_FINISHED;
1414 }
1415
1416 static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1417 {
1418   SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1419   const char *path = U.textudir;
1420   Image *ima = NULL;
1421   Scene *scene = CTX_data_scene(C);
1422
1423   if (sima) {
1424     ima = sima->image;
1425   }
1426
1427   if (ima == NULL) {
1428     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1429     if (tex && tex->type == TEX_IMAGE) {
1430       ima = tex->ima;
1431     }
1432   }
1433
1434   if (ima == NULL) {
1435     PointerRNA ptr;
1436     PropertyRNA *prop;
1437
1438     /* hook into UI */
1439     UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
1440
1441     if (prop) {
1442       PointerRNA oldptr;
1443       Image *oldima;
1444
1445       oldptr = RNA_property_pointer_get(&ptr, prop);
1446       oldima = (Image *)oldptr.id.data;
1447       /* unlikely to fail but better avoid strange crash */
1448       if (oldima && GS(oldima->id.name) == ID_IM) {
1449         ima = oldima;
1450       }
1451     }
1452   }
1453
1454   if (ima) {
1455     path = ima->name;
1456   }
1457
1458   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1459     return image_open_exec(C, op);
1460   }
1461
1462   image_open_init(C, op);
1463
1464   /* show multiview save options only if scene has multiviews */
1465   PropertyRNA *prop;
1466   prop = RNA_struct_find_property(op->ptr, "show_multiview");
1467   RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1468
1469   image_filesel(C, op, path);
1470
1471   return OPERATOR_RUNNING_MODAL;
1472 }
1473
1474 static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr),
1475                                        PropertyRNA *prop,
1476                                        void *UNUSED(user_data))
1477 {
1478   const char *prop_id = RNA_property_identifier(prop);
1479
1480   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
1481            STREQ(prop_id, "filename"));
1482 }
1483
1484 static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
1485 {
1486   uiLayout *layout = op->layout;
1487   ImageOpenData *iod = op->customdata;
1488   ImageFormatData *imf = &iod->im_format;
1489   PointerRNA imf_ptr, ptr;
1490
1491   /* main draw call */
1492   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1493   uiDefAutoButsRNA(
1494       layout, &ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1495
1496   /* image template */
1497   RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1498
1499   /* multiview template */
1500   if (RNA_boolean_get(op->ptr, "show_multiview")) {
1501     uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1502   }
1503 }
1504
1505 /* called by other space types too */
1506 void IMAGE_OT_open(wmOperatorType *ot)
1507 {
1508   /* identifiers */
1509   ot->name = "Open Image";
1510   ot->description = "Open image";
1511   ot->idname = "IMAGE_OT_open";
1512
1513   /* api callbacks */
1514   ot->exec = image_open_exec;
1515   ot->invoke = image_open_invoke;
1516   ot->cancel = image_open_cancel;
1517   ot->ui = image_open_draw;
1518
1519   /* flags */
1520   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1521
1522   /* properties */
1523   WM_operator_properties_filesel(ot,
1524                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
1525                                  FILE_SPECIAL,
1526                                  FILE_OPENFILE,
1527                                  WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES |
1528                                      WM_FILESEL_RELPATH,
1529                                  FILE_DEFAULTDISPLAY,
1530                                  FILE_SORT_ALPHA);
1531
1532   RNA_def_boolean(
1533       ot->srna,
1534       "use_sequence_detection",
1535       true,
1536       "Detect Sequences",
1537       "Automatically detect animated sequences in selected images (based on file names)");
1538 }
1539
1540 /******************** Match movie length operator ********************/
1541 static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
1542 {
1543   Scene *scene = CTX_data_scene(C);
1544   Image *ima = image_from_context(C);
1545   ImageUser *iuser = image_user_from_context(C);
1546
1547   if (!ima || !iuser) {
1548     /* Try to get a Texture, or a SpaceImage from context... */
1549     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1550     if (tex && tex->type == TEX_IMAGE) {
1551       ima = tex->ima;
1552       iuser = &tex->iuser;
1553     }
1554   }
1555
1556   if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1557     return OPERATOR_CANCELLED;
1558   }
1559
1560   struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
1561   if (!anim) {
1562     return OPERATOR_CANCELLED;
1563   }
1564   iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
1565   BKE_image_user_frame_calc(iuser, scene->r.cfra);
1566
1567   return OPERATOR_FINISHED;
1568 }
1569
1570 /* called by other space types too */
1571 void IMAGE_OT_match_movie_length(wmOperatorType *ot)
1572 {
1573   /* identifiers */
1574   ot->name = "Match Movie Length";
1575   ot->description = "Set image's user's length to the one of this video";
1576   ot->idname = "IMAGE_OT_match_movie_length";
1577
1578   /* api callbacks */
1579   ot->exec = image_match_len_exec;
1580
1581   /* flags */
1582   /* Don't think we need undo for that. */
1583   ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
1584 }
1585
1586 /******************** replace image operator ********************/
1587
1588 static int image_replace_exec(bContext *C, wmOperator *op)
1589 {
1590   Main *bmain = CTX_data_main(C);
1591   SpaceImage *sima = CTX_wm_space_image(C);
1592   char str[FILE_MAX];
1593
1594   if (!sima->image) {
1595     return OPERATOR_CANCELLED;
1596   }
1597
1598   RNA_string_get(op->ptr, "filepath", str);
1599
1600   /* we cant do much if the str is longer then FILE_MAX :/ */
1601   BLI_strncpy(sima->image->name, str, sizeof(sima->image->name));
1602
1603   if (sima->image->source == IMA_SRC_GENERATED) {
1604     sima->image->source = IMA_SRC_FILE;
1605     BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1606   }
1607
1608   if (BLI_path_extension_check_array(str, imb_ext_movie)) {
1609     sima->image->source = IMA_SRC_MOVIE;
1610   }
1611   else {
1612     sima->image->source = IMA_SRC_FILE;
1613   }
1614
1615   /* XXX unpackImage frees image buffers */
1616   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1617
1618   BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
1619   BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1620   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1621
1622   return OPERATOR_FINISHED;
1623 }
1624
1625 static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1626 {
1627   SpaceImage *sima = CTX_wm_space_image(C);
1628
1629   if (!sima->image) {
1630     return OPERATOR_CANCELLED;
1631   }
1632
1633   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1634     return image_replace_exec(C, op);
1635   }
1636
1637   if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1638     RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name));
1639   }
1640
1641   image_filesel(C, op, sima->image->name);
1642
1643   return OPERATOR_RUNNING_MODAL;
1644 }
1645
1646 void IMAGE_OT_replace(wmOperatorType *ot)
1647 {
1648   /* identifiers */
1649   ot->name = "Replace Image";
1650   ot->idname = "IMAGE_OT_replace";
1651   ot->description = "Replace current image by another one from disk";
1652
1653   /* api callbacks */
1654   ot->exec = image_replace_exec;
1655   ot->invoke = image_replace_invoke;
1656   ot->poll = image_not_packed_poll;
1657
1658   /* flags */
1659   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1660
1661   /* properties */
1662   WM_operator_properties_filesel(ot,
1663                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
1664                                  FILE_SPECIAL,
1665                                  FILE_OPENFILE,
1666                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
1667                                  FILE_DEFAULTDISPLAY,
1668                                  FILE_SORT_ALPHA);
1669 }
1670
1671 /******************** save image as operator ********************/
1672
1673 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
1674 {
1675   const char depth_ok = BKE_imtype_valid_depths(imtype);
1676
1677   if (ibuf->rect_float) {
1678     if (depth_ok & R_IMF_CHAN_DEPTH_32) {
1679       return R_IMF_CHAN_DEPTH_32;
1680     }
1681     if (depth_ok & R_IMF_CHAN_DEPTH_24) {
1682       return R_IMF_CHAN_DEPTH_24;
1683     }
1684     if (depth_ok & R_IMF_CHAN_DEPTH_16) {
1685       return R_IMF_CHAN_DEPTH_16;
1686     }
1687     if (depth_ok & R_IMF_CHAN_DEPTH_12) {
1688       return R_IMF_CHAN_DEPTH_12;
1689     }
1690     return R_IMF_CHAN_DEPTH_8;
1691   }
1692   else {
1693     if (depth_ok & R_IMF_CHAN_DEPTH_8) {
1694       return R_IMF_CHAN_DEPTH_8;
1695     }
1696     if (depth_ok & R_IMF_CHAN_DEPTH_12) {
1697       return R_IMF_CHAN_DEPTH_12;
1698     }
1699     if (depth_ok & R_IMF_CHAN_DEPTH_16) {
1700       return R_IMF_CHAN_DEPTH_16;
1701     }
1702     if (depth_ok & R_IMF_CHAN_DEPTH_24) {
1703       return R_IMF_CHAN_DEPTH_24;
1704     }
1705     if (depth_ok & R_IMF_CHAN_DEPTH_32) {
1706       return R_IMF_CHAN_DEPTH_32;
1707     }
1708     return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
1709   }
1710 }
1711
1712 static int image_save_options_init(Main *bmain,
1713                                    ImageSaveOptions *opts,
1714                                    Image *ima,
1715                                    ImageUser *iuser,
1716                                    const bool guess_path,
1717                                    const bool save_as_render)
1718 {
1719   void *lock;
1720   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
1721
1722   if (ibuf) {
1723     Scene *scene = opts->scene;
1724     bool is_depth_set = false;
1725
1726     if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
1727       /* imtype */
1728       opts->im_format = scene->r.im_format;
1729       is_depth_set = true;
1730       if (!BKE_image_is_multiview(ima)) {
1731         /* In case multiview is disabled,
1732          * render settings would be invalid for render result in this area. */
1733         opts->im_format.stereo3d_format = *ima->stereo3d_format;
1734         opts->im_format.views_format = ima->views_format;
1735       }
1736     }
1737     else {
1738       if (ima->source == IMA_SRC_GENERATED) {
1739         opts->im_format.imtype = R_IMF_IMTYPE_PNG;
1740         opts->im_format.compress = ibuf->foptions.quality;
1741         opts->im_format.planes = ibuf->planes;
1742       }
1743       else {
1744         BKE_imbuf_to_image_format(&opts->im_format, ibuf);
1745       }
1746
1747       /* use the multiview image settings as the default */
1748       opts->im_format.stereo3d_format = *ima->stereo3d_format;
1749       opts->im_format.views_format = ima->views_format;
1750     }
1751
1752     ///* XXX - this is lame, we need to make these available too! */
1753     // opts->subimtype = scene->r.subimtype;
1754
1755     BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
1756
1757     /* sanitize all settings */
1758
1759     /* unlikely but just in case */
1760     if (ELEM(opts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
1761       opts->im_format.planes = R_IMF_PLANES_RGBA;
1762     }
1763
1764     /* depth, account for float buffer and format support */
1765     if (is_depth_set == false) {
1766       opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
1767     }
1768
1769     /* some formats don't use quality so fallback to scenes quality */
1770     if (opts->im_format.quality == 0) {
1771       opts->im_format.quality = scene->r.im_format.quality;
1772     }
1773
1774     /* check for empty path */
1775     if (guess_path && opts->filepath[0] == 0) {
1776       const bool is_prev_save = !STREQ(G.ima, "//");
1777       if (save_as_render) {
1778         if (is_prev_save) {
1779           BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
1780         }
1781         else {
1782           BLI_strncpy(opts->filepath, "//untitled", sizeof(opts->filepath));
1783           BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
1784         }
1785       }
1786       else {
1787         BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
1788         BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
1789       }
1790     }
1791
1792     /* color management */
1793     BKE_color_managed_display_settings_copy(&opts->im_format.display_settings,
1794                                             &scene->display_settings);
1795     BKE_color_managed_view_settings_copy(&opts->im_format.view_settings, &scene->view_settings);
1796   }
1797
1798   BKE_image_release_ibuf(ima, ibuf, lock);
1799
1800   return (ibuf != NULL);
1801 }
1802
1803 static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
1804 {
1805   if (op->customdata) {
1806     BKE_color_managed_view_settings_free(&opts->im_format.view_settings);
1807
1808     opts->im_format = *(ImageFormatData *)op->customdata;
1809   }
1810
1811   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1812     RNA_string_get(op->ptr, "filepath", opts->filepath);
1813     BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
1814   }
1815 }
1816
1817 static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op)
1818 {
1819   if (op->customdata) {
1820     BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
1821
1822     *(ImageFormatData *)op->customdata = opts->im_format;
1823   }
1824
1825   RNA_string_set(op->ptr, "filepath", opts->filepath);
1826 }
1827
1828 static bool save_image_op(const bContext *C, wmOperator *op, ImageSaveOptions *opts)
1829 {
1830   Main *bmain = CTX_data_main(C);
1831   Image *ima = image_from_context(C);
1832   ImageUser *iuser = image_user_from_context(C);
1833
1834   opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
1835                     RNA_boolean_get(op->ptr, "relative_path"));
1836   opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
1837                      RNA_boolean_get(op->ptr, "copy"));
1838   opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
1839                           RNA_boolean_get(op->ptr, "save_as_render"));
1840
1841   WM_cursor_wait(1);
1842
1843   bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
1844
1845   WM_cursor_wait(0);
1846
1847   /* Remember file path for next save. */
1848   BLI_strncpy(G.ima, opts->filepath, sizeof(G.ima));
1849
1850   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1851
1852   return ok;
1853 }
1854
1855 static void image_save_as_free(wmOperator *op)
1856 {
1857   if (op->customdata) {
1858     ImageFormatData *im_format = (ImageFormatData *)op->customdata;
1859     BKE_color_managed_view_settings_free(&im_format->view_settings);
1860
1861     MEM_freeN(op->customdata);
1862     op->customdata = NULL;
1863   }
1864 }
1865
1866 static int image_save_as_exec(bContext *C, wmOperator *op)
1867 {
1868   Main *bmain = CTX_data_main(C);
1869   Scene *scene = CTX_data_scene(C);
1870   Image *image = image_from_context(C);
1871   ImageUser *iuser = image_user_from_context(C);
1872   ImageSaveOptions opts;
1873
1874   BKE_image_save_options_init(&opts, bmain, scene);
1875
1876   /* just in case to initialize values,
1877    * these should be set on invoke or by the caller. */
1878   image_save_options_init(bmain, &opts, image, iuser, false, false);
1879
1880   image_save_options_from_op(bmain, &opts, op);
1881   opts.do_newpath = true;
1882
1883   save_image_op(C, op, &opts);
1884
1885   image_save_as_free(op);
1886   return OPERATOR_FINISHED;
1887 }
1888
1889 static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
1890 {
1891   ImageFormatData *imf = op->customdata;
1892   return WM_operator_filesel_ensure_ext_imtype(op, imf);
1893 }
1894
1895 static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1896 {
1897   Main *bmain = CTX_data_main(C);
1898   Image *ima = image_from_context(C);
1899   ImageUser *iuser = image_user_from_context(C);
1900   Scene *scene = CTX_data_scene(C);
1901   ImageSaveOptions opts;
1902   PropertyRNA *prop;
1903   const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) ||
1904                                (ima->flag & IMA_VIEW_AS_RENDER));
1905
1906   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1907     return image_save_as_exec(C, op);
1908   }
1909
1910   BKE_image_save_options_init(&opts, bmain, scene);
1911
1912   if (image_save_options_init(bmain, &opts, ima, iuser, true, save_as_render) == 0) {
1913     return OPERATOR_CANCELLED;
1914   }
1915   image_save_options_to_op(&opts, op);
1916
1917   /* enable save_copy by default for render results */
1918   if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) &&
1919       !RNA_struct_property_is_set(op->ptr, "copy")) {
1920     RNA_boolean_set(op->ptr, "copy", true);
1921   }
1922
1923   RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
1924
1925   op->customdata = MEM_mallocN(sizeof(opts.im_format), __func__);
1926   memcpy(op->customdata, &opts.im_format, sizeof(opts.im_format));
1927
1928   /* show multiview save options only if image has multiviews */
1929   prop = RNA_struct_find_property(op->ptr, "show_multiview");
1930   RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
1931   prop = RNA_struct_find_property(op->ptr, "use_multiview");
1932   RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
1933
1934   image_filesel(C, op, opts.filepath);
1935
1936   return OPERATOR_RUNNING_MODAL;
1937 }
1938
1939 static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op)
1940 {
1941   image_save_as_free(op);
1942 }
1943
1944 static bool image_save_as_draw_check_prop(PointerRNA *ptr,
1945                                           PropertyRNA *prop,
1946                                           void *UNUSED(user_data))
1947 {
1948   const char *prop_id = RNA_property_identifier(prop);
1949
1950   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
1951            STREQ(prop_id, "filename") ||
1952            /* when saving a copy, relative path has no effect */
1953            ((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy")));
1954 }
1955
1956 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
1957 {
1958   uiLayout *layout = op->layout;
1959   ImageFormatData *imf = op->customdata;
1960   PointerRNA imf_ptr, ptr;
1961   const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
1962
1963   /* image template */
1964   RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1965   uiTemplateImageSettings(layout, &imf_ptr, false);
1966
1967   /* main draw call */
1968   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1969   uiDefAutoButsRNA(
1970       layout, &ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1971
1972   /* multiview template */
1973   if (is_multiview) {
1974     uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1975   }
1976 }
1977
1978 static bool image_save_as_poll(bContext *C)
1979 {
1980   if (!image_buffer_exists_from_context(C)) {
1981     return false;
1982   }
1983
1984   if (G.is_rendering) {
1985     /* no need to NULL check here */
1986     Image *ima = image_from_context(C);
1987
1988     if (ima->source == IMA_SRC_VIEWER) {
1989       CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
1990       return false;
1991     }
1992   }
1993
1994   return true;
1995 }
1996
1997 void IMAGE_OT_save_as(wmOperatorType *ot)
1998 {
1999   /* identifiers */
2000   ot->name = "Save As Image";
2001   ot->idname = "IMAGE_OT_save_as";
2002   ot->description = "Save the image with another name and/or settings";
2003
2004   /* api callbacks */
2005   ot->exec = image_save_as_exec;
2006   ot->check = image_save_as_check;
2007   ot->invoke = image_save_as_invoke;
2008   ot->cancel = image_save_as_cancel;
2009   ot->ui = image_save_as_draw;
2010   ot->poll = image_save_as_poll;
2011
2012   /* flags */
2013   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2014
2015   /* properties */
2016   RNA_def_boolean(ot->srna,
2017                   "save_as_render",
2018                   0,
2019                   "Save As Render",
2020                   "Apply render part of display transform when saving byte image");
2021   RNA_def_boolean(ot->srna,
2022                   "copy",
2023                   0,
2024                   "Copy",
2025                   "Create a new image file without modifying the current image in blender");
2026
2027   WM_operator_properties_filesel(ot,
2028                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
2029                                  FILE_SPECIAL,
2030                                  FILE_SAVE,
2031                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
2032                                  FILE_DEFAULTDISPLAY,
2033                                  FILE_SORT_ALPHA);
2034 }
2035
2036 /******************** save image operator ********************/
2037
2038 static int image_save_exec(bContext *C, wmOperator *op)
2039 {
2040   Main *bmain = CTX_data_main(C);
2041   Image *image = image_from_context(C);
2042   ImageUser *iuser = image_user_from_context(C);
2043   Scene *scene = CTX_data_scene(C);
2044   ImageSaveOptions opts;
2045
2046   BKE_image_save_options_init(&opts, bmain, scene);
2047   if (image_save_options_init(bmain, &opts, image, iuser, false, false) == 0) {
2048     return OPERATOR_CANCELLED;
2049   }
2050   image_save_options_from_op(bmain, &opts, op);
2051
2052   if (BLI_exists(opts.filepath) && BLI_file_is_writable(opts.filepath)) {
2053     if (save_image_op(C, op, &opts)) {
2054       /* report since this can be called from key-shortcuts */
2055       BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", opts.filepath);
2056     }
2057   }
2058   else {
2059     BKE_reportf(
2060         op->reports, RPT_ERROR, "Cannot save image, path '%s' is not writable", opts.filepath);
2061     return OPERATOR_CANCELLED;
2062   }
2063
2064   return OPERATOR_FINISHED;
2065 }
2066
2067 void IMAGE_OT_save(wmOperatorType *ot)
2068 {
2069   /* identifiers */
2070   ot->name = "Save Image";
2071   ot->idname = "IMAGE_OT_save";
2072   ot->description = "Save the image with current name and settings";
2073
2074   /* api callbacks */
2075   ot->exec = image_save_exec;
2076   ot->poll = space_image_file_exists_poll;
2077
2078   /* flags */
2079   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2080 }
2081
2082 /******************* save sequence operator ********************/
2083
2084 static int image_save_sequence_exec(bContext *C, wmOperator *op)
2085 {
2086   Main *bmain = CTX_data_main(C);
2087   Image *image = image_from_context(C);
2088   ImBuf *ibuf, *first_ibuf = NULL;
2089   int tot = 0;
2090   char di[FILE_MAX];
2091   struct MovieCacheIter *iter;
2092
2093   if (image == NULL) {
2094     return OPERATOR_CANCELLED;
2095   }
2096
2097   if (image->source != IMA_SRC_SEQUENCE) {
2098     BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2099     return OPERATOR_CANCELLED;
2100   }
2101
2102   if (image->type == IMA_TYPE_MULTILAYER) {
2103     BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2104     return OPERATOR_CANCELLED;
2105   }
2106
2107   /* get total dirty buffers and first dirty buffer which is used for menu */
2108   ibuf = NULL;
2109   if (image->cache != NULL) {
2110     iter = IMB_moviecacheIter_new(image->cache);
2111     while (!IMB_moviecacheIter_done(iter)) {
2112       ibuf = IMB_moviecacheIter_getImBuf(iter);
2113       if (ibuf->userflags & IB_BITMAPDIRTY) {
2114         if (first_ibuf == NULL) {
2115           first_ibuf = ibuf;
2116         }
2117         tot++;
2118       }
2119       IMB_moviecacheIter_step(iter);
2120     }
2121     IMB_moviecacheIter_free(iter);
2122   }
2123
2124   if (tot == 0) {
2125     BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2126     return OPERATOR_CANCELLED;
2127   }
2128
2129   /* get a filename for menu */
2130   BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
2131   BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2132
2133   iter = IMB_moviecacheIter_new(image->cache);
2134   while (!IMB_moviecacheIter_done(iter)) {
2135     ibuf = IMB_moviecacheIter_getImBuf(iter);
2136
2137     if (ibuf->userflags & IB_BITMAPDIRTY) {
2138       char name[FILE_MAX];
2139       BLI_strncpy(name, ibuf->name, sizeof(name));
2140
2141       BLI_path_abs(name, BKE_main_blendfile_path(bmain));
2142
2143       if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
2144         BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2145         break;
2146       }
2147
2148       BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
2149       ibuf->userflags &= ~IB_BITMAPDIRTY;
2150     }
2151
2152     IMB_moviecacheIter_step(iter);
2153   }
2154   IMB_moviecacheIter_free(iter);
2155
2156   return OPERATOR_FINISHED;
2157 }
2158
2159 void IMAGE_OT_save_sequence(wmOperatorType *ot)
2160 {
2161   /* identifiers */
2162   ot->name = "Save Sequence";
2163   ot->idname = "IMAGE_OT_save_sequence";
2164   ot->description = "Save a sequence of images";
2165
2166   /* api callbacks */
2167   ot->exec = image_save_sequence_exec;
2168   ot->poll = image_buffer_exists_from_context;
2169
2170   /* flags */
2171   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2172 }
2173
2174 /********************** save all operator **********************/
2175
2176 static bool image_should_be_saved_when_modified(Image *ima)
2177 {
2178   return !ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE);
2179 }
2180
2181 static bool image_should_be_saved(Image *ima)
2182 {
2183   if (BKE_image_is_dirty(ima) && (ima->source == IMA_SRC_FILE)) {
2184     return image_should_be_saved_when_modified(ima);
2185   }
2186   else {
2187     return false;
2188   }
2189 }
2190
2191 static bool image_has_valid_path(Image *ima)
2192 {
2193   return strchr(ima->name, '\\') || strchr(ima->name, '/');
2194 }
2195
2196 bool ED_image_should_save_modified(const bContext *C)
2197 {
2198   return ED_image_save_all_modified_info(C, NULL) > 0;
2199 }
2200
2201 int ED_image_save_all_modified_info(const bContext *C, ReportList *reports)
2202 {
2203   Main *bmain = CTX_data_main(C);
2204   GSet *unique_paths = BLI_gset_str_new(__func__);
2205
2206   int num_saveable_images = 0;
2207
2208   for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
2209     if (image_should_be_saved(ima)) {
2210       if (BKE_image_has_packedfile(ima)) {
2211         if (ima->id.lib == NULL) {
2212           num_saveable_images++;
2213         }
2214         else {
2215           BKE_reportf(reports,
2216                       RPT_WARNING,
2217                       "Packed library image: %s from library %s can't be saved",
2218                       ima->id.name,
2219                       ima->id.lib->name);
2220         }
2221       }
2222       else {
2223         if (image_has_valid_path(ima)) {
2224           num_saveable_images++;
2225           if (BLI_gset_haskey(unique_paths, ima->name)) {
2226             BKE_reportf(reports,
2227                         RPT_WARNING,
2228                         "File path used by more than one saved image: %s",
2229                         ima->name);
2230           }
2231           else {
2232             BLI_gset_insert(unique_paths, BLI_strdup(ima->name));
2233           }
2234         }
2235         else {
2236           BKE_reportf(reports,
2237                       RPT_WARNING,
2238                       "Image %s can't be saved, no valid file path: %s",
2239                       ima->id.name,
2240                       ima->name);
2241         }
2242       }
2243     }
2244   }
2245
2246   BLI_gset_free(unique_paths, MEM_freeN);
2247   return num_saveable_images;
2248 }
2249
2250 bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
2251 {
2252   ED_image_save_all_modified_info(C, reports);
2253
2254   Main *bmain = CTX_data_main(C);
2255   bool ok = true;
2256
2257   for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
2258     if (image_should_be_saved(ima)) {
2259       if (BKE_image_has_packedfile(ima)) {
2260         BKE_image_memorypack(ima);
2261       }
2262       else {
2263         if (image_has_valid_path(ima)) {
2264           ImageSaveOptions opts;
2265           Scene *scene = CTX_data_scene(C);
2266           BKE_image_save_options_init(&opts, bmain, scene);
2267           if (image_save_options_init(bmain, &opts, ima, NULL, false, false)) {
2268             bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
2269             ok = ok && saved_successfully;
2270           }
2271         }
2272       }
2273     }
2274   }
2275   return ok;
2276 }
2277
2278 static bool image_save_all_modified_poll(bContext *C)
2279 {
2280   int num_files = ED_image_save_all_modified_info(C, NULL);
2281   return num_files > 0;
2282 }
2283
2284 static int image_save_all_modified_exec(bContext *C, wmOperator *op)
2285 {
2286   ED_image_save_all_modified(C, op->reports);
2287   return OPERATOR_FINISHED;
2288 }
2289
2290 void IMAGE_OT_save_all_modified(wmOperatorType *ot)
2291 {
2292   /* identifiers */
2293   ot->name = "Save All Modified";
2294   ot->idname = "IMAGE_OT_save_all_modified";
2295   ot->description = "Save all modified images";
2296
2297   /* api callbacks */
2298   ot->exec = image_save_all_modified_exec;
2299   ot->poll = image_save_all_modified_poll;
2300
2301   /* flags */
2302   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2303 }
2304
2305 /******************** reload image operator ********************/
2306
2307 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
2308 {
2309   Main *bmain = CTX_data_main(C);
2310   Image *ima = image_from_context(C);
2311   ImageUser *iuser = image_user_from_context(C);
2312
2313   if (!ima) {
2314     return OPERATOR_CANCELLED;
2315   }
2316
2317   /* XXX unpackImage frees image buffers */
2318   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2319
2320   BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
2321   DEG_id_tag_update(&ima->id, 0);
2322
2323   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2324
2325   return OPERATOR_FINISHED;
2326 }
2327
2328 void IMAGE_OT_reload(wmOperatorType *ot)
2329 {
2330   /* identifiers */
2331   ot->name = "Reload Image";
2332   ot->idname = "IMAGE_OT_reload";
2333   ot->description = "Reload current image from disk";
2334
2335   /* api callbacks */
2336   ot->exec = image_reload_exec;
2337
2338   /* flags */
2339   ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2340 }
2341
2342 /********************** new image operator *********************/
2343 #define IMA_DEF_NAME N_("Untitled")
2344
2345 enum {
2346   GEN_CONTEXT_NONE = 0,
2347   GEN_CONTEXT_PAINT_CANVAS = 1,
2348   GEN_CONTEXT_PAINT_STENCIL = 2,
2349 };
2350
2351 typedef struct ImageNewData {
2352   PropertyPointerRNA pprop;
2353 } ImageNewData;
2354
2355 static ImageNewData *image_new_init(bContext *C, wmOperator *op)
2356 {
2357   if (op->customdata) {
2358     return op->customdata;
2359   }
2360
2361   ImageNewData *data = MEM_callocN(sizeof(ImageNewData), __func__);
2362   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2363   op->customdata = data;
2364   return data;
2365 }
2366
2367 static void image_new_free(wmOperator *op)
2368 {
2369   if (op->customdata) {
2370     MEM_freeN(op->customdata);
2371     op->customdata = NULL;
2372   }
2373 }
2374
2375 static int image_new_exec(bContext *C, wmOperator *op)
2376 {
2377   SpaceImage *sima;
2378   Object *obedit;
2379   Image *ima;
2380   Main *bmain;
2381   PropertyRNA *prop;
2382   char name_buffer[MAX_ID_NAME - 2];
2383   const char *name;
2384   float color[4];
2385   int width, height, floatbuf, gen_type, alpha;
2386   int stereo3d;
2387
2388   /* retrieve state */
2389   sima = CTX_wm_space_image(C);
2390   obedit = CTX_data_edit_object(C);
2391   bmain = CTX_data_main(C);
2392
2393   prop = RNA_struct_find_property(op->ptr, "name");
2394   RNA_property_string_get(op->ptr, prop, name_buffer);
2395   if (!RNA_property_is_set(op->ptr, prop)) {
2396     /* Default value, we can translate! */
2397     name = DATA_(name_buffer);
2398   }
2399   else {
2400     name = name_buffer;
2401   }
2402   width = RNA_int_get(op->ptr, "width");
2403   height = RNA_int_get(op->ptr, "height");
2404   floatbuf = RNA_boolean_get(op->ptr, "float");
2405   gen_type = RNA_enum_get(op->ptr, "generated_type");
2406   RNA_float_get_array(op->ptr, "color", color);
2407   alpha = RNA_boolean_get(op->ptr, "alpha");
2408   stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2409
2410   if (!alpha) {
2411     color[3] = 1.0f;
2412   }
2413
2414   ima = BKE_image_add_generated(
2415       bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
2416
2417   if (!ima) {
2418     image_new_free(op);
2419     return OPERATOR_CANCELLED;
2420   }
2421
2422   /* hook into UI */
2423   ImageNewData *data = image_new_init(C, op);
2424
2425   if (data->pprop.prop) {
2426     /* when creating new ID blocks, use is already 1, but RNA
2427      * pointer use also increases user, so this compensates it */
2428     id_us_min(&ima->id);
2429
2430     PointerRNA imaptr;
2431     RNA_id_pointer_create(&ima->id, &imaptr);
2432     RNA_property_pointer_set(NULL, &data->pprop.ptr, data->pprop.prop, imaptr);
2433     RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2434   }
2435   else if (sima) {
2436     ED_space_image_set(bmain, sima, obedit, ima, false);
2437   }
2438
2439   BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2440
2441   WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2442
2443   image_new_free(op);
2444
2445   return OPERATOR_FINISHED;
2446 }
2447
2448 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2449 {
2450   /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2451   ImageNewData *data;
2452   op->customdata = data = MEM_callocN(sizeof(ImageNewData), __func__);
2453   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2454
2455   /* Better for user feedback. */
2456   RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2457   return WM_operator_props_dialog_popup(C, op, 300, 100);
2458 }
2459
2460 static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
2461 {
2462   uiLayout *split, *col[2];
2463   uiLayout *layout = op->layout;
2464   PointerRNA ptr;
2465 #if 0
2466   Scene *scene = CTX_data_scene(C);
2467   const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2468 #endif
2469
2470   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2471
2472   /* copy of WM_operator_props_dialog_popup() layout */
2473
2474   split = uiLayoutSplit(layout, 0.5f, false);
2475   col[0] = uiLayoutColumn(split, false);
2476   col[1] = uiLayoutColumn(split, false);
2477
2478   uiItemL(col[0], IFACE_("Name"), ICON_NONE);
2479   uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
2480
2481   uiItemL(col[0], IFACE_("Width"), ICON_NONE);
2482   uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
2483
2484   uiItemL(col[0], IFACE_("Height"), ICON_NONE);
2485   uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
2486
2487   uiItemL(col[0], IFACE_("Color"), ICON_NONE);
2488   uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
2489
2490   uiItemL(col[0], "", ICON_NONE);
2491   uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
2492
2493   uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
2494   uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
2495
2496   uiItemL(col[0], "", ICON_NONE);
2497   uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
2498
2499 #if 0
2500   if (is_multiview) {
2501     uiItemL(col[0], "", ICON_NONE);
2502     uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
2503   }
2504 #endif
2505 }
2506
2507 static void image_new_cancel(bContext *UNUSED(C), wmOperator *op)
2508 {
2509   image_new_free(op);
2510 }
2511
2512 void IMAGE_OT_new(wmOperatorType *ot)
2513 {
2514   PropertyRNA *prop;
2515   static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2516
2517   /* identifiers */
2518   ot->name = "New Image";
2519   ot->description = "Create a new image";
2520   ot->idname = "IMAGE_OT_new";
2521
2522   /* api callbacks */
2523   ot->exec = image_new_exec;
2524   ot->invoke = image_new_invoke;
2525   ot->ui = image_new_draw;
2526   ot->cancel = image_new_cancel;
2527
2528   /* flags */
2529   ot->flag = OPTYPE_UNDO;
2530
2531   /* properties */
2532   RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2533   prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2534   RNA_def_property_subtype(prop, PROP_PIXEL);
2535   prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2536   RNA_def_property_subtype(prop, PROP_PIXEL);
2537   prop = RNA_def_float_color(
2538       ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2539   RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2540   RNA_def_property_float_array_default(prop, default_color);
2541   RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2542   RNA_def_enum(ot->srna,
2543                "generated_type",
2544                rna_enum_image_generated_type_items,
2545                IMA_GENTYPE_BLANK,
2546                "Generated Type",
2547                "Fill the image with a grid for UV map testing");
2548   RNA_def_boolean(
2549       ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2550   RNA_def_property_flag(prop, PROP_HIDDEN);
2551   prop = RNA_def_boolean(
2552       ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
2553   RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2554 }
2555
2556 #undef IMA_DEF_NAME
2557
2558 /********************* invert operators *********************/
2559
2560 static bool image_invert_poll(bContext *C)
2561 {
2562   Image *ima = image_from_context(C);
2563
2564   return BKE_image_has_ibuf(ima, NULL);
2565 }
2566
2567 static int image_invert_exec(bContext *C, wmOperator *op)
2568 {
2569   Image *ima = image_from_context(C);
2570   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2571   SpaceImage *sima = CTX_wm_space_image(C);
2572   /* undo is supported only on image paint mode currently */
2573   bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2574
2575   /* flags indicate if this channel should be inverted */
2576   const bool r = RNA_boolean_get(op->ptr, "invert_r");
2577   const bool g = RNA_boolean_get(op->ptr, "invert_g");
2578   const bool b = RNA_boolean_get(op->ptr, "invert_b");
2579   const bool a = RNA_boolean_get(op->ptr, "invert_a");
2580
2581   size_t i;
2582
2583   if (ibuf == NULL) {
2584     /* TODO: this should actually never happen, but does for render-results -> cleanup */
2585     return OPERATOR_CANCELLED;
2586   }
2587
2588   if (support_undo) {
2589     ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
2590     /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
2591      * but better do this right in case someone copies this for a tool that uses partial
2592      * redraw better */
2593     ED_imapaint_clear_partial_redraw();
2594     ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
2595   }
2596   /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2597   if (ibuf->rect_float) {
2598
2599     float *fp = (float *)ibuf->rect_float;
2600     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
2601       if (r) {
2602         fp[0] = 1.0f - fp[0];
2603       }
2604       if (g) {
2605         fp[1] = 1.0f - fp[1];
2606       }
2607       if (b) {
2608         fp[2] = 1.0f - fp[2];
2609       }
2610       if (a) {
2611         fp[3] = 1.0f - fp[3];
2612       }
2613     }
2614
2615     if (ibuf->rect) {
2616       IMB_rect_from_float(ibuf);
2617     }
2618   }
2619   else if (ibuf->rect) {
2620
2621     char *cp = (char *)ibuf->rect;
2622     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
2623       if (r) {
2624         cp[0] = 255 - cp[0];
2625       }
2626       if (g) {
2627         cp[1] = 255 - cp[1];
2628       }
2629       if (b) {
2630         cp[2] = 255 - cp[2];
2631       }
2632       if (a) {
2633         cp[3] = 255 - cp[3];
2634       }
2635     }
2636   }
2637   else {
2638     BKE_image_release_ibuf(ima, ibuf, NULL);
2639     return OPERATOR_CANCELLED;
2640   }
2641
2642   ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
2643   BKE_image_mark_dirty(ima, ibuf);
2644
2645   if (ibuf->mipmap[0]) {
2646     ibuf->userflags |= IB_MIPMAP_INVALID;
2647   }
2648
2649   if (support_undo) {
2650     ED_image_undo_push_end();
2651   }
2652
2653   /* force GPU reupload, all image is invalid */
2654   GPU_free_image(ima);
2655
2656   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2657
2658   BKE_image_release_ibuf(ima, ibuf, NULL);
2659
2660   return OPERATOR_FINISHED;
2661 }
2662
2663 void IMAGE_OT_invert(wmOperatorType *ot)
2664 {
2665   PropertyRNA *prop;
2666
2667   /* identifiers */
2668   ot->name = "Invert Channels";
2669   ot->idname = "IMAGE_OT_invert";
2670   ot->description = "Invert image's channels";
2671
2672   /* api callbacks */
2673   ot->exec = image_invert_exec;
2674   ot->poll = image_invert_poll;
2675
2676   /* properties */
2677   prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2678   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2679   prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2680   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2681   prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2682   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2683   prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2684   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2685
2686   /* flags */
2687   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2688 }
2689
2690 /********************* pack operator *********************/
2691
2692 static bool image_pack_test(bContext *C, wmOperator *op)
2693 {
2694   Image *ima = image_from_context(C);
2695
2696   if (!ima) {
2697     return 0;
2698   }
2699
2700   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2701     BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
2702     return 0;
2703   }
2704
2705   return 1;
2706 }
2707
2708 static int image_pack_exec(bContext *C, wmOperator *op)
2709 {
2710   struct Main *bmain = CTX_data_main(C);
2711   Image *ima = image_from_context(C);
2712
2713   if (!image_pack_test(C, op)) {
2714     return OPERATOR_CANCELLED;
2715   }
2716
2717   if (BKE_image_is_dirty(ima)) {
2718     BKE_image_memorypack(ima);
2719   }
2720   else {
2721     BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
2722   }
2723
2724   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2725
2726   return OPERATOR_FINISHED;
2727 }
2728
2729 void IMAGE_OT_pack(wmOperatorType *ot)
2730 {
2731   /* identifiers */
2732   ot->name = "Pack Image";
2733   ot->description = "Pack an image as embedded data into the .blend file";
2734   ot->idname = "IMAGE_OT_pack";
2735
2736   /* api callbacks */
2737   ot->exec = image_pack_exec;
2738
2739   /* flags */
2740   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2741 }
2742
2743 /********************* unpack operator *********************/
2744
2745 static int image_unpack_exec(bContext *C, wmOperator *op)
2746 {
2747   Image *ima = image_from_context(C);
2748   int method = RNA_enum_get(op->ptr, "method");
2749
2750   /* find the suppplied image by name */
2751   if (RNA_struct_property_is_set(op->ptr, "id")) {
2752     char imaname[MAX_ID_NAME - 2];
2753     RNA_string_get(op->ptr, "id", imaname);
2754     ima = BLI_findstring(&CTX_data_main(C)->images, imaname, offsetof(ID, name) + 2);
2755     if (!ima) {
2756       ima = image_from_context(C);
2757     }
2758   }
2759
2760   if (!ima || !BKE_image_has_packedfile(ima)) {
2761     return OPERATOR_CANCELLED;
2762   }
2763
2764   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2765     BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2766     return OPERATOR_CANCELLED;
2767   }
2768
2769   if (G.fileflags & G_FILE_AUTOPACK) {
2770     BKE_report(op->reports,
2771                RPT_WARNING,
2772                "AutoPack is enabled, so image will be packed again on file save");
2773   }
2774
2775   /* XXX unpackImage frees image buffers */
2776   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2777
2778   unpackImage(CTX_data_main(C), op->reports, ima, method);
2779
2780   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2781
2782   return OPERATOR_FINISHED;
2783 }
2784
2785 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2786 {
2787   Image *ima = image_from_context(C);
2788
2789   if (RNA_struct_property_is_set(op->ptr, "id")) {
2790     return image_unpack_exec(C, op);
2791   }
2792
2793   if (!ima || !BKE_image_has_packedfile(ima)) {
2794     return OPERATOR_CANCELLED;
2795   }
2796
2797   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2798     BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2799     return OPERATOR_CANCELLED;
2800   }
2801
2802   if (G.fileflags & G_FILE_AUTOPACK) {
2803     BKE_report(op->reports,
2804                RPT_WARNING,
2805                "AutoPack is enabled, so image will be packed again on file save");
2806   }
2807
2808   unpack_menu(C,
2809               "IMAGE_OT_unpack",
2810               ima->id.name + 2,
2811               ima->name,
2812               "textures",
2813               BKE_image_has_packedfile(ima) ?
2814                   ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
2815                   NULL);
2816
2817   return OPERATOR_FINISHED;
2818 }
2819
2820 void IMAGE_OT_unpack(wmOperatorType *ot)
2821 {
2822   /* identifiers */
2823   ot->name = "Unpack Image";
2824   ot->description = "Save an image packed in the .blend file to disk";
2825   ot->idname = "IMAGE_OT_unpack";
2826
2827   /* api callbacks */
2828   ot->exec = image_unpack_exec;
2829   ot->invoke = image_unpack_invoke;
2830
2831   /* flags */
2832   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2833
2834   /* properties */
2835   RNA_def_enum(
2836       ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
2837   /* XXX, weak!, will fail with library, name collisions */
2838   RNA_def_string(
2839       ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
2840 }
2841
2842 /******************** sample image operator ********************/
2843
2844 typedef struct ImageSampleInfo {
2845   ARegionType *art;
2846   void *draw_handle;
2847   int x, y;
2848   int channels;
2849
2850   int width, height;
2851   int sample_size;
2852
2853   unsigned char col[4];
2854   float colf[4];
2855   float linearcol[4];
2856   int z;
2857   float zf;
2858
2859   unsigned char *colp;
2860   const float *colfp;
2861   int *zp;
2862   float *zfp;
2863
2864   bool draw;
2865   bool color_manage;
2866   int use_default_view;
2867 } ImageSampleInfo;
2868
2869 static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
2870 {
2871   ImageSampleInfo *info = arg_info;
2872   if (!info->draw) {
2873     return;
2874   }
2875
2876   Scene *scene = CTX_data_scene(C);
2877   ED_image_draw_info(scene,
2878                      ar,
2879                      info->color_manage,
2880                      info->use_default_view,
2881                      info->channels,
2882                      info->x,
2883                      info->y,
2884                      info->colp,
2885                      info->colfp,
2886                      info->linearcol,
2887                      info->zp,
2888                      info->zfp);
2889
2890   if (info->sample_size > 1) {
2891     const wmWindow *win = CTX_wm_window(C);
2892     const wmEvent *event = win->eventstate;
2893
2894     SpaceImage *sima = CTX_wm_space_image(C);
2895     GPUVertFormat *format = immVertexFormat();
2896     uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2897
2898     const float color[3] = {1, 1, 1};
2899     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2900     immUniformColor3fv(color);
2901
2902     /* TODO(campbell): lock to pixels. */
2903     rctf sample_rect_fl;
2904     BLI_rctf_init_pt_radius(&sample_rect_fl,
2905                             (float[2]){event->x - ar->winrct.xmin, event->y - ar->winrct.ymin},
2906                             (float)(info->sample_size / 2.0f) * sima->zoom);
2907
2908     glEnable(GL_COLOR_LOGIC_OP);
2909     glLogicOp(GL_XOR);
2910     GPU_line_width(1.0f);
2911     imm_draw_box_wire_2d(pos,
2912                          (float)sample_rect_fl.xmin,
2913                          (float)sample_rect_fl.ymin,
2914                          (float)sample_rect_fl.xmax,
2915                          (float)sample_rect_fl.ymax);
2916     glDisable(GL_COLOR_LOGIC_OP);
2917
2918     immUnbindProgram();
2919   }
2920 }
2921
2922 /* Returns color in linear space, matching ED_space_node_color_sample(). */
2923 bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
2924 {
2925   void *lock;
2926   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2927   float fx, fy;
2928   bool ret = false;
2929
2930   if (ibuf == NULL) {
2931     ED_space_image_release_buffer(sima, ibuf, lock);
2932     return false;
2933   }
2934
2935   UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
2936
2937   if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2938     const float *fp;
2939     unsigned char *cp;
2940     int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2941
2942     CLAMP(x, 0, ibuf->x - 1);
2943     CLAMP(y, 0, ibuf->y - 1);
2944
2945     if (ibuf->rect_float) {
2946       fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2947       copy_v3_v3(r_col, fp);
2948       ret = true;
2949     }
2950     else if (ibuf->rect) {
2951       cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2952       rgb_uchar_to_float(r_col, cp);
2953       IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
2954       ret = true;
2955     }
2956   }
2957
2958   ED_space_image_release_buffer(sima, ibuf, lock);
2959   return ret;
2960 }
2961
2962 /* -------------------------------------------------------------------- */
2963 /** \name Image Pixel Sample
2964  * \{ */
2965
2966 static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
2967                                            const int coord[2],
2968                                            uchar r_col[4],
2969                                            float r_col_linear[4])
2970 {
2971   const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
2972   copy_v4_v4_uchar(r_col, cp);
2973   rgba_uchar_to_float(r_col_linear, r_col);
2974   IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
2975 }
2976
2977 static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
2978 {
2979   const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
2980   copy_v4_v4(r_col, cp);
2981 }
2982
2983 /** \} */
2984
2985 /* -------------------------------------------------------------------- */
2986 /** \name Image Pixel Region Sample
2987  * \{ */
2988
2989 static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
2990                                           const rcti *rect,
2991                                           uchar r_col[4],
2992                                           float r_col_linear[4])
2993 {
2994   uint col_accum_ub[4] = {0, 0, 0, 0};
2995   zero_v4(r_col_linear);
2996   int col_tot = 0;
2997   int coord[2];
2998   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
2999     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
3000       float col_temp_fl[4];
3001       uchar col_temp_ub[4];
3002       image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
3003       add_v4_v4(r_col_linear, col_temp_fl);
3004       col_accum_ub[0] += (uint)col_temp_ub[0];
3005       col_accum_ub[1] += (uint)col_temp_ub[1];
3006       col_accum_ub[2] += (uint)col_temp_ub[2];
3007       col_accum_ub[3] += (uint)col_temp_ub[3];
3008       col_tot += 1;
3009     }
3010   }
3011   mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
3012
3013   r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
3014   r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
3015   r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
3016   r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
3017 }
3018
3019 static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
3020 {
3021   zero_v4(r_col);
3022   int col_tot = 0;
3023   int coord[2];
3024   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
3025     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
3026       float col_temp_fl[4];
3027       image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
3028       add_v4_v4(r_col, col_temp_fl);
3029       col_tot += 1;
3030     }
3031   }
3032   mul_v4_fl(r_col, 1.0 / (float)col_tot);
3033 }
3034
3035 /** \} */
3036
3037 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
3038 {
3039   SpaceImage *sima = CTX_wm_space_image(C);
3040   ARegion *ar = CTX_wm_region(C);
3041   void *lock;
3042   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3043   ImageSampleInfo *info = op->customdata;
3044   float fx, fy;
3045   Scene *scene = CTX_data_scene(C);
3046   CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
3047
3048   if (ibuf == NULL) {
3049     ED_space_image_release_buffer(sima, ibuf, lock);
3050     info->draw = false;
3051     return;
3052   }
3053
3054   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
3055
3056   if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
3057     int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
3058     Image *image = ED_space_image(sima);
3059
3060     CLAMP(x, 0, ibuf->x - 1);
3061     CLAMP(y, 0, ibuf->y - 1);
3062
3063     info->width = ibuf->x;
3064     info->height = ibuf->y;
3065     info->x = x;
3066     info->y = y;
3067
3068     info->draw = true;
3069     info->channels = ibuf->channels;
3070
3071     info->colp = NULL;
3072     info->colfp = NULL;
3073     info->zp = NULL;
3074     info->zfp = NULL;
3075
3076     info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
3077
3078     rcti sample_rect;
3079     sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
3080     sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
3081     sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
3082     sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
3083
3084     if (ibuf->rect) {
3085       image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
3086       rgba_uchar_to_float(info->colf, info->col);
3087
3088       info->colp = info->col;
3089       info->colfp = info->colf;
3090       info->color_manage = true;
3091     }
3092     if (ibuf->rect_float) {
3093       image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
3094
3095       if (ibuf->channels == 4) {
3096         /* pass */
3097       }
3098       else if (ibuf->channels == 3) {
3099         info->colf[3] = 1.0f;
3100       }
3101       else {
3102         info->colf[1] = info->colf[0];
3103         info->colf[2] = info->colf[0];
3104         info->colf[3] = 1.0f;
3105       }
3106       info->colfp = info->colf;
3107
3108       copy_v4_v4(info->linearcol, info->colf);
3109
3110       info->color_manage = true;
3111     }
3112
3113     if (ibuf->zbuf) {
3114       /* TODO, blend depth (not urgent). */
3115       info->z = ibuf->zbuf[y * ibuf->x + x];
3116       info->zp = &info->z;
3117       if (ibuf->zbuf == (int *)ibuf->rect) {
3118         info->colp = NULL;
3119       }
3120     }
3121     if (ibuf->zbuf_float) {
3122       /* TODO, blend depth (not urgent). */
3123       info->zf = ibuf->zbuf_float[y * ibuf->x + x];
3124       info->zfp = &info->zf;
3125       if (ibuf->zbuf_float == ibuf->rect_float) {
3126         info->colfp = NULL;
3127       }
3128     }
3129
3130     if (curve_mapping && ibuf->channels == 4) {
3131       /* we reuse this callback for set curves point operators */
3132       if (RNA_struct_find_property(op->ptr, "point")) {
3133         int point = RNA_enum_get(op->ptr, "point");
3134
3135         if (point == 1) {
3136           curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
3137         }
3138         else if (point == 0) {
3139           curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
3140         }
3141         WM_event_add_notifier(C, NC_WINDOW, NULL);
3142       }
3143     }
3144
3145     // XXX node curve integration ..
3146 #if 0
3147     {
3148       ScrArea *sa, *cur = curarea;
3149
3150       node_curvemap_sample(fp); /* sends global to node editor */
3151       for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
3152         if (sa->spacetype == SPACE_NODE) {
3153           areawinset(sa->win);
3154           scrarea_do_windraw(sa);
3155         }
3156       }
3157       node_curvemap_sample(NULL); /* clears global in node editor */
3158       curarea = cur;
3159     }
3160 #endif
3161   }
3162   else {
3163     info->draw = 0;
3164   }
3165
3166   ED_space_image_release_buffer(sima, ibuf, lock);
3167   ED_area_tag_redraw(CTX_wm_area(C));
3168 }
3169
3170 static void image_sample_exit(bContext *C, wmOperator *op)
3171 {
3172   ImageSampleInfo *info = op->customdata;
3173
3174   ED_region_draw_cb_exit(info->art, info->draw_handle);
3175   ED_area_tag_redraw(CTX_wm_area(C));
3176   MEM_freeN(info);
3177 }
3178
3179 static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3180 {
3181   SpaceImage *sima = CTX_wm_space_image(C);
3182   ARegion *ar = CTX_wm_region(C);
3183   ImageSampleInfo *info;
3184
3185   if (ar->regiontype == RGN_TYPE_WINDOW) {
3186     if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
3187       return OPERATOR_PASS_THROUGH;
3188     }
3189   }
3190
3191   if (!ED_space_image_has_buffer(sima)) {
3192     return OPERATOR_CANCELLED;
3193   }
3194
3195   info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
3196
3197   info->art = ar->type;
3198   info->draw_handle = ED_region_draw_cb_activate(
3199       ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
3200   info->sample_size = RNA_int_get(op->ptr, "size");
3201   op->customdata = info;
3202
3203   image_sample_apply(C, op, event);
3204
3205   WM_event_add_modal_handler(C, op);
3206
3207   return OPERATOR_RUNNING_MODAL;
3208 }
3209
3210 static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
3211 {
3212   switch (event->type) {
3213     case LEFTMOUSE:
3214     case RIGHTMOUSE:  // XXX hardcoded
3215       if (event->val == KM_RELEASE) {
3216         image_sample_exit(C, op);
3217         return OPERATOR_CANCELLED;
3218       }
3219       break;
3220     case MOUSEMOVE:
3221       image_sample_apply(C, op, event);
3222       break;
3223   }
3224
3225   return OPERATOR_RUNNING_MODAL;
3226 }
3227
3228 static void image_sample_cancel(bContext *C, wmOperator *op)
3229 {
3230   image_sample_exit(C, op);
3231 }
3232
3233 void IMAGE_OT_sample(wmOperatorType *ot)
3234 {
3235   /* identifiers */
3236   ot->name = "Sample Color";
3237   ot->idname = "IMAGE_OT_sample";
3238   ot->description = "Use mouse to sample a color in current image";
3239
3240   /* api callbacks */
3241   ot->invoke = image_sample_invoke;
3242   ot->modal = image_sample_modal;
3243   ot->cancel = image_sample_cancel;
3244   ot->poll = image_sample_poll;
3245
3246   /* flags */
3247   ot->flag = OPTYPE_BLOCKING;
3248
3249   PropertyRNA *prop;
3250   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3251   RNA_def_property_subtype(prop, PROP_PIXEL);
3252   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3253 }
3254
3255 /******************** sample line operator ********************/
3256 static int image_sample_line_exec(bContext *C, wmOperator *op)
3257 {
3258   SpaceImage *sima = CTX_wm_space_image(C);
3259   ARegion *ar = CTX_wm_region(C);
3260   Scene *scene = CTX_data_scene(C);
3261
3262   int x_start = RNA_int_get(op->ptr, "xstart");
3263   int y_start = RNA_int_get(op->ptr, "ystart");
3264   int x_end = RNA_int_get(op->ptr, "xend");
3265   int y_end = RNA_int_get(op->ptr, "yend");
3266
3267   void *lock;
3268   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3269   Histogram *hist = &sima->sample_line_hist;
3270
3271   float x1f, y1f, x2f, y2f;
3272
3273   if (ibuf == NULL) {
3274     ED_space_image_release_buffer(sima, ibuf, lock);
3275     return OPERATOR_CANCELLED;
3276   }
3277   /* hmmmm */
3278   if (ibuf->channels < 3) {
3279     ED_space_image_release_buffer(sima, ibuf, lock);
3280     return OPERATOR_CANCELLED;
3281   }
3282
3283   UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
3284   UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
3285
3286   hist->co[0][0] = x1f;
3287   hist->co[0][1] = y1f;
3288   hist->co[1][0] = x2f;
3289   hist->co[1][1] = y2f;
3290
3291   /* enable line drawing */
3292   hist->flag |= HISTO_FLAG_SAMPLELINE;
3293
3294   BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
3295
3296   /* reset y zoom */
3297   hist->ymax = 1.0f;
3298
3299   ED_space_image_release_buffer(sima, ibuf, lock);
3300
3301   ED_area_tag_redraw(CTX_wm_area(C));
3302
3303   return OPERATOR_FINISHED;
3304 }
3305
3306 static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3307 {
3308   SpaceImage *sima = CTX_wm_space_image(C);
3309
3310   Histogram *hist = &sima->sample_line_hist;
3311   hist->flag &= ~HISTO_FLAG_SAMPLELINE;
3312
3313   if (!ED_space_image_has_buffer(sima)) {
3314     return OPERATOR_CANCELLED;
3315   }
3316
3317   return WM_gesture_straightline_invoke(C, op, event);
3318 }
3319
3320 void IMAGE_OT_sample_line(wmOperatorType *ot)
3321 {
3322   /* identifiers */
3323   ot->name = "Sample Line";
3324   ot->idname = "IMAGE_OT_sample_line";
3325   ot->description = "Sample a line and show it in Scope panels";
3326
3327   /* api callbacks */
3328   ot->invoke = image_sample_line_invoke;
3329   ot->modal = WM_gesture_straightline_modal;
3330   ot->exec = image_sample_line_exec;
3331   ot->poll = space_image_main_region_poll;
3332   ot->cancel = WM_gesture_straightline_cancel;
3333
3334   /* flags */
3335   ot->flag = 0; /* no undo/register since this operates on the space */
3336
3337   WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
3338 }
3339
3340 /******************** set curve point operator ********************/
3341
3342 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
3343 {
3344   static const EnumPropertyItem point_items[] = {
3345       {0, "BLACK_POINT", 0, "Black Point", ""},
3346       {1, "WHITE_POINT", 0, "White Point", ""},
3347       {0, NULL, 0, NULL, NULL},
3348   };
3349
3350   /* identifiers */
3351   ot->name = "Set Curves Point";
3352   ot->idname = "IMAGE_OT_curves_point_set";
3353   ot->description = "Set black point or white point for curves";
3354
3355   /* flags */
3356   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3357
3358   /* api callbacks */
3359   ot->invoke = image_sample_invoke;
3360   ot->modal = image_sample_modal;
3361   ot->cancel = image_sample_cancel;
3362   ot->poll = space_image_main_area_not_uv_brush_poll;
3363
3364   /* properties */
3365   RNA_def_enum(
3366       ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3367
3368   PropertyRNA *prop;
3369   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3370   RNA_def_property_subtype(prop, PROP_PIXEL);
3371   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3372 }
3373
3374 /********************* cycle render slot operator *********************/
3375
3376 static bool image_cycle_render_slot_poll(bContext *C)
3377 {
3378   Image *ima = image_from_context(C);
3379
3380   return (ima && ima->type == IMA_TYPE_R_RESULT);
3381 }
3382
3383 static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
3384 {
3385   Image *ima = image_from_context(C);
3386   const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3387
3388   if (!ED_image_slot_cycle(ima, direction)) {
3389     return OPERATOR_CANCELLED;
3390   }
3391
3392   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3393
3394   /* no undo push for browsing existing */
3395   RenderSlot *slot = BKE_image_get_renderslot(ima, ima->render_slot);
3396   if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3397     return OPERATOR_CANCELLED;
3398   }
3399
3400   return OPERATOR_FINISHED;
3401 }
3402
3403 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
3404 {
3405   /* identifiers */
3406   ot->name = "Cycle Render Slot";
3407   ot->idname = "IMAGE_OT_cycle_render_slot";
3408   ot->description = "Cycle through all non-void render slots";
3409
3410   /* api callbacks */
3411   ot->exec = image_cycle_render_slot_exec;
3412   ot->poll = image_cycle_render_slot_poll;
3413
3414   /* flags */
3415   ot->flag = OPTYPE_REGISTER;
3416
3417   RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
3418 }
3419
3420 /********************* clear render slot operator *********************/
3421
3422 static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3423 {
3424   SpaceImage *sima = CTX_wm_space_image(C);
3425   Image *ima = image_from_context(C);
3426
3427   if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
3428     return OPERATOR_CANCELLED;
3429   }
3430
3431   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3432
3433   return OPERATOR_FINISHED;
3434 }
3435
3436 void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
3437 {
3438   /* identifiers */
3439   ot->name = "Clear Render Slot";
3440   ot->idname = "IMAGE_OT_clear_render_slot";
3441   ot->description = "Clear the currently selected render slot";
3442
3443   /* api callbacks */
3444   ot->exec = image_clear_render_slot_exec;
3445   ot->poll = image_cycle_render_slot_poll;
3446
3447   /* flags */
3448   ot->flag = OPTYPE_REGISTER;
3449 }
3450
3451 /********************* add render slot operator *********************/
3452
3453 static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3454 {
3455   Image *ima = image_from_context(C);
3456
3457   RenderSlot *slot = BKE_image_add_renderslot(ima, NULL);
3458   ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3459
3460   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3461
3462   return OPERATOR_FINISHED;
3463 }
3464
3465 void IMAGE_OT_add_render_slot(wmOperatorType *ot)
3466 {
3467   /* identifiers */
3468   ot->name = "Add Render Slot";
3469   ot->idname = "IMAGE_OT_add_render_slot";
3470   ot->description = "Add a new render slot";
3471
3472   /* api callbacks */
3473   ot->exec = image_add_render_slot_exec;
3474   ot->poll = image_cycle_render_slot_poll;
3475
3476   /* flags */
3477   ot->flag = OPTYPE_REGISTER;
3478 }
3479
3480 /********************* remove render slot operator *********************/
3481
3482 static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3483 {
3484   SpaceImage *sima = CTX_wm_space_image(C);
3485   Image *ima = image_from_context(C);
3486
3487   if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
3488     return OPERATOR_CANCELLED;
3489   }
3490
3491   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3492
3493   return OPERATOR_FINISHED;
3494 }
3495
3496 void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
3497 {
3498   /* identifiers */
3499   ot->name = "Remove Render Slot";
3500   ot->idname = "IMAGE_OT_remove_render_slot";
3501   ot->description = "Remove the current render slot";
3502
3503   /* api callbacks */
3504   ot->exec = image_remove_render_slot_exec;
3505   ot->poll = image_cycle_render_slot_poll;
3506
3507   /* flags */
3508   ot->flag = OPTYPE_REGISTER;
3509 }
3510
3511 /********************** change frame operator *********************/
3512
3513 static bool change_frame_poll(bContext *C)
3514 {
3515   /* prevent changes during render */
3516   if (G.is_rendering) {
3517     return 0;
3518   }
3519
3520   return space_image_main_region_poll(C);
3521 }
3522
3523 static void change_frame_apply(bContext *C, wmOperator *op)
3524 {
3525   Scene *scene = CTX_data_scene(C);
3526
3527   /* set the new frame number */
3528   CFRA = RNA_int_get(op->ptr, "frame");
3529   FRAMENUMBER_MIN_CLAMP(CFRA);
3530   SUBFRA = 0.0f;
3531
3532   /* do updates */
3533   BKE_sound_seek_scene(CTX_data_main(C), scene);
3534   WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
3535 }
3536
3537 static int change_frame_exec(bContext *C, wmOperator *op)
3538 {
3539   change_frame_apply(C, op);
3540
3541   return OPERATOR_FINISHED;
3542 }
3543
3544 static int frame_from_event(bContext *C, const wmEvent *event)
3545 {
3546   ARegion *ar = CTX_wm_region(C);
3547   Scene *scene = CTX_data_scene(C);
3548   int framenr = 0;
3549
3550   if (ar->regiontype == RGN_TYPE_WINDOW) {
3551     float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
3552
3553     framenr = sfra + event->mval[0] / framelen;
3554   }
3555   else {
3556     float viewx, viewy;
3557
3558     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3559
3560     framenr = round_fl_to_int(viewx);
3561   }
3562
3563   return framenr;
3564 }
3565
3566 static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3567 {
3568   ARegion *ar = CTX_wm_region(C);
3569
3570   if (ar->regiontype == RGN_TYPE_WINDOW) {
3571     SpaceImage *sima = CTX_wm_space_image(C);
3572     if (event->mval[1] > 16 || !ED_space_image_show_cache(sima)) {
3573       return OPERATOR_PASS_THROUGH;
3574     }
3575   }
3576
3577   RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3578
3579   change_frame_apply(C, op);
3580
3581   /* add temp handler */
3582   WM_event_add_modal_handler(C, op);
3583
3584   return OPERATOR_RUNNING_MODAL;
3585 }
3586
3587 static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
3588 {
3589   switch (event->type) {
3590     case ESCKEY:
3591       return OPERATOR_FINISHED;
3592
3593     case MOUSEMOVE:
3594       RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3595       change_frame_apply(C, op);
3596       break;
3597
3598     case LEFTMOUSE:
3599     case RIGHTMOUSE:
3600       if (event->val == KM_RELEASE) {
3601         return OPERATOR_FINISHED;
3602       }
3603       break;
3604   }
3605
3606   return OPERATOR_RUNNING_MODAL;
3607 }
3608
3609 void IMAGE_OT_change_frame(wmOperatorType *ot)
3610 {
3611   /* identifiers */
3612   ot->name = "Change Frame";
3613   ot->idname = "IMAGE_OT_change_frame";
3614   ot->description = "Interactively change the current frame number";
3615
3616   /* api callbacks */
3617   ot->exec = change_frame_exec;
3618   ot->invoke = change_frame_invoke;
3619   ot->modal = change_frame_modal;
3620   ot->poll = change_frame_poll;
3621
3622   /* flags */
3623   ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
3624
3625   /* rna */
3626   RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
3627 }
3628
3629 /* Reload cached render results... */
3630 /* goes over all scenes, reads render layers */
3631 static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
3632 {
3633   Main *bmain = CTX_data_main(C);
3634   Scene *scene = CTX_data_scene(C);
3635   SpaceImage *sima = CTX_wm_space_image(C);
3636   Image *ima;
3637
3638   ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
3639   if (sima->image == NULL) {
3640     ED_space_image_set(bmain, sima, NULL, ima, false);
3641   }
3642
3643   RE_ReadRenderResult(scene, scene);
3644
3645   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
3646   return OPERATOR_FINISHED;
3647 }
3648
3649 void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
3650 {
3651   ot->name = "Open Cached Render";
3652   ot->idname = "IMAGE_OT_read_viewlayers";
3653   ot->description = "Read all the current scene's view layers from cache, as needed";
3654
3655   ot->poll = space_image_main_region_poll;
3656   ot->exec = image_read_viewlayers_exec;
3657
3658   /* flags */
3659   ot->flag = 0;
3660 }
3661
3662 /* ********************* Render border operator ****************** */
3663
3664 static int render_border_exec(bContext *C, wmOperator *op)
3665 {
3666   ARegion *ar = CTX_wm_region(C);
3667   Scene *scene = CTX_data_scene(C);
3668   Render *re = RE_GetSceneRender(scene);
3669   RenderData *rd;
3670   rctf border;
3671
3672   if (re == NULL) {
3673     /* Shouldn't happen, but better be safe close to the release. */
3674     return OPERATOR_CANCELLED;
3675   }
3676
3677   rd = RE_engine_get_render_data(re);
3678   if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
3679     BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
3680     return OPERATOR_CANCELLED;
3681   }
3682
3683   /* get rectangle from operator */
3684   WM_operator_properties_border_to_rctf(op, &border);
3685   UI_view2d_region_to_view_rctf(&ar->v2d, &border, &border);
3686
3687   /* actually set border */
3688   CLAMP(border.xmin, 0.0f, 1.0f);
3689   CLAMP(border.ymin, 0.0f, 1.0f);
3690   CLAMP(border.xmax, 0.0f, 1.0f);
3691   CLAMP(border.ymax, 0.0f, 1.0f);
3692   scene->r.border = border;
3693
3694   /* drawing a border surrounding the entire camera view switches off border rendering
3695    * or the border covers no pixels */
3696   if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
3697       (border.xmin == border.xmax || border.ymin == border.ymax)) {
3698     scene->r.mode &= ~R_BORDER;
3699   }
3700   else {
3701     scene->r.mode |= R_BORDER;
3702   }
3703
3704   DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
3705   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3706
3707   return OPERATOR_FINISHED;
3708 }
3709
3710 void IMAGE_OT_render_border(wmOperatorType *ot)
3711 {
3712   /* identifiers */
3713   ot->name = "Render Region";
3714   ot->description = "Set the boundaries of the render region and enable render region";
3715   ot->idname = "IMAGE_OT_render_border";
3716
3717   /* api callbacks */
3718   ot->invoke = WM_gesture_box_invoke;
3719   ot->exec = render_border_exec;
3720   ot->modal = WM_gesture_box_modal;
3721   ot->cancel = WM_gesture_box_cancel;
3722   ot->poll = image_cycle_render_slot_poll;
3723
3724   /* flags */
3725   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3726
3727   /* rna */
3728   WM_operator_properties_border(ot);
3729 }
3730
3731 /* ********************* Clear render border operator ****************** */
3732
3733 static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
3734 {
3735   Scene *scene = CTX_data_scene(C);
3736   scene->r.mode &= ~R_BORDER;
3737   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3738   BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
3739   return OPERATOR_FINISHED;
3740 }
3741
3742 void IMAGE_OT_clear_render_border(wmOperatorType *ot)
3743 {
3744   /* identifiers */
3745   ot->name = "Clear Render Region";
3746   ot->description = "Clear the boundaries of the render region and disable render region";
3747   ot->idname = "IMAGE_OT_clear_render_border";
3748
3749   /* api callbacks */
3750   ot->exec = clear_render_border_exec;
3751   ot->poll = image_cycle_render_slot_poll;
3752
3753   /* flags */
3754   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3755 }