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