Cleanup: rename 'name' to 'filepath' for DNA types
[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->filepath, 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->filepath;
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->filepath, str, sizeof(sima->image->filepath));
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->filepath));
1618   }
1619
1620   image_filesel(C, op, sima->image->filepath);
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->filepath, 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->filepath, '\\') || strchr(ima->filepath, '/');
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->filepath);
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->filepath)) {
2352             BKE_reportf(reports,
2353                         RPT_WARNING,
2354                         "Multiple images can't be saved to an identical path: \"%s\"",
2355                         ima->filepath);
2356           }
2357           else {
2358             BLI_gset_insert(unique_paths, BLI_strdup(ima->filepath));
2359           }
2360         }
2361         else {
2362           BKE_reportf(reports,
2363                       RPT_WARNING,
2364                       "Image can't be saved, no valid file path: \"%s\"",
2365                       ima->filepath);
2366         }
2367       }
2368     }
2369   }
2370
2371   BLI_gset_free(unique_paths, MEM_freeN);
2372   return num_saveable_images;
2373 }
2374
2375 bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
2376 {
2377   Main *bmain = CTX_data_main(C);
2378
2379   ED_image_save_all_modified_info(bmain, reports);
2380
2381   bool ok = true;
2382
2383   for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
2384     bool is_format_writable;
2385
2386     if (image_should_be_saved(ima, &is_format_writable)) {
2387       if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) {
2388         BKE_image_memorypack(ima);
2389       }
2390       else if (is_format_writable) {
2391         if (image_has_valid_path(ima)) {
2392           ImageSaveOptions opts;
2393           Scene *scene = CTX_data_scene(C);
2394           BKE_image_save_options_init(&opts, bmain, scene);
2395           if (image_save_options_init(bmain, &opts, ima, NULL, false, false)) {
2396             bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
2397             ok = ok && saved_successfully;
2398           }
2399         }
2400       }
2401     }
2402   }
2403   return ok;
2404 }
2405
2406 static bool image_save_all_modified_poll(bContext *C)
2407 {
2408   int num_files = ED_image_save_all_modified_info(CTX_data_main(C), NULL);
2409   return num_files > 0;
2410 }
2411
2412 static int image_save_all_modified_exec(bContext *C, wmOperator *op)
2413 {
2414   ED_image_save_all_modified(C, op->reports);
2415   return OPERATOR_FINISHED;
2416 }
2417
2418 void IMAGE_OT_save_all_modified(wmOperatorType *ot)
2419 {
2420   /* identifiers */
2421   ot->name = "Save All Modified";
2422   ot->idname = "IMAGE_OT_save_all_modified";
2423   ot->description = "Save all modified images";
2424
2425   /* api callbacks */
2426   ot->exec = image_save_all_modified_exec;
2427   ot->poll = image_save_all_modified_poll;
2428
2429   /* flags */
2430   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2431 }
2432
2433 /** \} */
2434
2435 /* -------------------------------------------------------------------- */
2436 /** \name Reload Image Operator
2437  * \{ */
2438
2439 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
2440 {
2441   Main *bmain = CTX_data_main(C);
2442   Image *ima = image_from_context(C);
2443   ImageUser *iuser = image_user_from_context(C);
2444
2445   if (!ima) {
2446     return OPERATOR_CANCELLED;
2447   }
2448
2449   /* XXX BKE_packedfile_unpack_image frees image buffers */
2450   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2451
2452   BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
2453   DEG_id_tag_update(&ima->id, 0);
2454
2455   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2456
2457   return OPERATOR_FINISHED;
2458 }
2459
2460 void IMAGE_OT_reload(wmOperatorType *ot)
2461 {
2462   /* identifiers */
2463   ot->name = "Reload Image";
2464   ot->idname = "IMAGE_OT_reload";
2465   ot->description = "Reload current image from disk";
2466
2467   /* api callbacks */
2468   ot->exec = image_reload_exec;
2469
2470   /* flags */
2471   ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2472 }
2473
2474 /** \} */
2475
2476 /* -------------------------------------------------------------------- */
2477 /** \name New Image Operator
2478  * \{ */
2479
2480 #define IMA_DEF_NAME N_("Untitled")
2481
2482 enum {
2483   GEN_CONTEXT_NONE = 0,
2484   GEN_CONTEXT_PAINT_CANVAS = 1,
2485   GEN_CONTEXT_PAINT_STENCIL = 2,
2486 };
2487
2488 typedef struct ImageNewData {
2489   PropertyPointerRNA pprop;
2490 } ImageNewData;
2491
2492 static ImageNewData *image_new_init(bContext *C, wmOperator *op)
2493 {
2494   if (op->customdata) {
2495     return op->customdata;
2496   }
2497
2498   ImageNewData *data = MEM_callocN(sizeof(ImageNewData), __func__);
2499   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2500   op->customdata = data;
2501   return data;
2502 }
2503
2504 static void image_new_free(wmOperator *op)
2505 {
2506   if (op->customdata) {
2507     MEM_freeN(op->customdata);
2508     op->customdata = NULL;
2509   }
2510 }
2511
2512 static int image_new_exec(bContext *C, wmOperator *op)
2513 {
2514   SpaceImage *sima;
2515   Object *obedit;
2516   Image *ima;
2517   Main *bmain;
2518   PropertyRNA *prop;
2519   char name_buffer[MAX_ID_NAME - 2];
2520   const char *name;
2521   float color[4];
2522   int width, height, floatbuf, gen_type, alpha;
2523   int stereo3d;
2524
2525   /* retrieve state */
2526   sima = CTX_wm_space_image(C);
2527   obedit = CTX_data_edit_object(C);
2528   bmain = CTX_data_main(C);
2529
2530   prop = RNA_struct_find_property(op->ptr, "name");
2531   RNA_property_string_get(op->ptr, prop, name_buffer);
2532   if (!RNA_property_is_set(op->ptr, prop)) {
2533     /* Default value, we can translate! */
2534     name = DATA_(name_buffer);
2535   }
2536   else {
2537     name = name_buffer;
2538   }
2539   width = RNA_int_get(op->ptr, "width");
2540   height = RNA_int_get(op->ptr, "height");
2541   floatbuf = RNA_boolean_get(op->ptr, "float");
2542   gen_type = RNA_enum_get(op->ptr, "generated_type");
2543   RNA_float_get_array(op->ptr, "color", color);
2544   alpha = RNA_boolean_get(op->ptr, "alpha");
2545   stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2546   bool tiled = RNA_boolean_get(op->ptr, "tiled");
2547
2548   if (!alpha) {
2549     color[3] = 1.0f;
2550   }
2551
2552   ima = BKE_image_add_generated(bmain,
2553                                 width,
2554                                 height,
2555                                 name,
2556                                 alpha ? 32 : 24,
2557                                 floatbuf,
2558                                 gen_type,
2559                                 color,
2560                                 stereo3d,
2561                                 false,
2562                                 tiled);
2563
2564   if (!ima) {
2565     image_new_free(op);
2566     return OPERATOR_CANCELLED;
2567   }
2568
2569   /* hook into UI */
2570   ImageNewData *data = image_new_init(C, op);
2571
2572   if (data->pprop.prop) {
2573     /* when creating new ID blocks, use is already 1, but RNA
2574      * pointer use also increases user, so this compensates it */
2575     id_us_min(&ima->id);
2576
2577     PointerRNA imaptr;
2578     RNA_id_pointer_create(&ima->id, &imaptr);
2579     RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr, NULL);
2580     RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2581   }
2582   else if (sima) {
2583     ED_space_image_set(bmain, sima, obedit, ima, false);
2584   }
2585
2586   BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2587
2588   WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2589
2590   image_new_free(op);
2591
2592   return OPERATOR_FINISHED;
2593 }
2594
2595 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2596 {
2597   /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2598   ImageNewData *data;
2599   op->customdata = data = MEM_callocN(sizeof(ImageNewData), __func__);
2600   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2601
2602   /* Better for user feedback. */
2603   RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2604   return WM_operator_props_dialog_popup(C, op, 300);
2605 }
2606
2607 static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
2608 {
2609   uiLayout *split, *col[2];
2610   uiLayout *layout = op->layout;
2611   PointerRNA ptr;
2612 #if 0
2613   Scene *scene = CTX_data_scene(C);
2614   const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2615 #endif
2616
2617   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2618
2619   /* copy of WM_operator_props_dialog_popup() layout */
2620
2621   split = uiLayoutSplit(layout, 0.5f, false);
2622   col[0] = uiLayoutColumn(split, false);
2623   col[1] = uiLayoutColumn(split, false);
2624
2625   uiItemL(col[0], IFACE_("Name"), ICON_NONE);
2626   uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
2627
2628   uiItemL(col[0], IFACE_("Width"), ICON_NONE);
2629   uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
2630
2631   uiItemL(col[0], IFACE_("Height"), ICON_NONE);
2632   uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
2633
2634   uiItemL(col[0], IFACE_("Color"), ICON_NONE);
2635   uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
2636
2637   uiItemL(col[0], "", ICON_NONE);
2638   uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
2639
2640   uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
2641   uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
2642
2643   uiItemL(col[0], "", ICON_NONE);
2644   uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
2645
2646   uiItemL(col[0], "", ICON_NONE);
2647   uiItemR(col[1], &ptr, "tiled", 0, NULL, ICON_NONE);
2648
2649 #if 0
2650   if (is_multiview) {
2651     uiItemL(col[0], "", ICON_NONE);
2652     uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
2653   }
2654 #endif
2655 }
2656
2657 static void image_new_cancel(bContext *UNUSED(C), wmOperator *op)
2658 {
2659   image_new_free(op);
2660 }
2661
2662 void IMAGE_OT_new(wmOperatorType *ot)
2663 {
2664   PropertyRNA *prop;
2665   static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2666
2667   /* identifiers */
2668   ot->name = "New Image";
2669   ot->description = "Create a new image";
2670   ot->idname = "IMAGE_OT_new";
2671
2672   /* api callbacks */
2673   ot->exec = image_new_exec;
2674   ot->invoke = image_new_invoke;
2675   ot->ui = image_new_draw;
2676   ot->cancel = image_new_cancel;
2677
2678   /* flags */
2679   ot->flag = OPTYPE_UNDO;
2680
2681   /* properties */
2682   RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2683   prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2684   RNA_def_property_subtype(prop, PROP_PIXEL);
2685   prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2686   RNA_def_property_subtype(prop, PROP_PIXEL);
2687   prop = RNA_def_float_color(
2688       ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2689   RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2690   RNA_def_property_float_array_default(prop, default_color);
2691   RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2692   RNA_def_enum(ot->srna,
2693                "generated_type",
2694                rna_enum_image_generated_type_items,
2695                IMA_GENTYPE_BLANK,
2696                "Generated Type",
2697                "Fill the image with a grid for UV map testing");
2698   RNA_def_boolean(
2699       ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2700   RNA_def_property_flag(prop, PROP_HIDDEN);
2701   prop = RNA_def_boolean(
2702       ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
2703   RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2704   prop = RNA_def_boolean(ot->srna, "tiled", 0, "Tiled", "Create a tiled image");
2705   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2706 }
2707
2708 #undef IMA_DEF_NAME
2709
2710 /** \} */
2711
2712 /* -------------------------------------------------------------------- */
2713 /** \name Invert Operators
2714  * \{ */
2715
2716 static int image_invert_exec(bContext *C, wmOperator *op)
2717 {
2718   Image *ima = image_from_context(C);
2719   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2720   SpaceImage *sima = CTX_wm_space_image(C);
2721   const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2722
2723   /* flags indicate if this channel should be inverted */
2724   const bool r = RNA_boolean_get(op->ptr, "invert_r");
2725   const bool g = RNA_boolean_get(op->ptr, "invert_g");
2726   const bool b = RNA_boolean_get(op->ptr, "invert_b");
2727   const bool a = RNA_boolean_get(op->ptr, "invert_a");
2728
2729   size_t i;
2730
2731   if (ibuf == NULL) {
2732     /* TODO: this should actually never happen, but does for render-results -> cleanup */
2733     return OPERATOR_CANCELLED;
2734   }
2735
2736   ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
2737
2738   if (is_paint) {
2739     ED_imapaint_clear_partial_redraw();
2740   }
2741
2742   /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2743   if (ibuf->rect_float) {
2744
2745     float *fp = (float *)ibuf->rect_float;
2746     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
2747       if (r) {
2748         fp[0] = 1.0f - fp[0];
2749       }
2750       if (g) {
2751         fp[1] = 1.0f - fp[1];
2752       }
2753       if (b) {
2754         fp[2] = 1.0f - fp[2];
2755       }
2756       if (a) {
2757         fp[3] = 1.0f - fp[3];
2758       }
2759     }
2760
2761     if (ibuf->rect) {
2762       IMB_rect_from_float(ibuf);
2763     }
2764   }
2765   else if (ibuf->rect) {
2766
2767     char *cp = (char *)ibuf->rect;
2768     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
2769       if (r) {
2770         cp[0] = 255 - cp[0];
2771       }
2772       if (g) {
2773         cp[1] = 255 - cp[1];
2774       }
2775       if (b) {
2776         cp[2] = 255 - cp[2];
2777       }
2778       if (a) {
2779         cp[3] = 255 - cp[3];
2780       }
2781     }
2782   }
2783   else {
2784     BKE_image_release_ibuf(ima, ibuf, NULL);
2785     return OPERATOR_CANCELLED;
2786   }
2787
2788   ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
2789   BKE_image_mark_dirty(ima, ibuf);
2790
2791   if (ibuf->mipmap[0]) {
2792     ibuf->userflags |= IB_MIPMAP_INVALID;
2793   }
2794
2795   ED_image_undo_push_end();
2796
2797   /* force GPU reupload, all image is invalid */
2798   GPU_free_image(ima);
2799
2800   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2801
2802   BKE_image_release_ibuf(ima, ibuf, NULL);
2803
2804   return OPERATOR_FINISHED;
2805 }
2806
2807 void IMAGE_OT_invert(wmOperatorType *ot)
2808 {
2809   PropertyRNA *prop;
2810
2811   /* identifiers */
2812   ot->name = "Invert Channels";
2813   ot->idname = "IMAGE_OT_invert";
2814   ot->description = "Invert image's channels";
2815
2816   /* api callbacks */
2817   ot->exec = image_invert_exec;
2818   ot->poll = image_from_context_has_data_poll_no_image_user;
2819
2820   /* properties */
2821   prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2822   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2823   prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2824   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2825   prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2826   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2827   prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2828   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2829
2830   /* flags */
2831   ot->flag = OPTYPE_REGISTER;
2832 }
2833
2834 /** \} */
2835
2836 /* -------------------------------------------------------------------- */
2837 /** \name Scale Operator
2838  * \{ */
2839
2840 static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2841 {
2842   Image *ima = image_from_context(C);
2843   PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
2844   if (!RNA_property_is_set(op->ptr, prop)) {
2845     ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2846     const int size[2] = {ibuf->x, ibuf->y};
2847     RNA_property_int_set_array(op->ptr, prop, size);
2848     BKE_image_release_ibuf(ima, ibuf, NULL);
2849   }
2850   return WM_operator_props_dialog_popup(C, op, 200);
2851 }
2852
2853 static int image_scale_exec(bContext *C, wmOperator *op)
2854 {
2855   Image *ima = image_from_context(C);
2856   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2857   SpaceImage *sima = CTX_wm_space_image(C);
2858   const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2859
2860   if (ibuf == NULL) {
2861     /* TODO: this should actually never happen, but does for render-results -> cleanup */
2862     return OPERATOR_CANCELLED;
2863   }
2864
2865   if (is_paint) {
2866     ED_imapaint_clear_partial_redraw();
2867   }
2868
2869   PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
2870   int size[2];
2871   if (RNA_property_is_set(op->ptr, prop)) {
2872     RNA_property_int_get_array(op->ptr, prop, size);
2873   }
2874   else {
2875     size[0] = ibuf->x;
2876     size[1] = ibuf->y;
2877     RNA_property_int_set_array(op->ptr, prop, size);
2878   }
2879
2880   ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
2881
2882   ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
2883   IMB_scaleImBuf(ibuf, size[0], size[1]);
2884   BKE_image_release_ibuf(ima, ibuf, NULL);
2885
2886   ED_image_undo_push_end();
2887
2888   /* force GPU reupload, all image is invalid */
2889   GPU_free_image(ima);
2890
2891   DEG_id_tag_update(&ima->id, 0);
2892   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2893
2894   return OPERATOR_FINISHED;
2895 }
2896
2897 void IMAGE_OT_resize(wmOperatorType *ot)
2898 {
2899   /* identifiers */
2900   ot->name = "Resize Image";
2901   ot->idname = "IMAGE_OT_resize";
2902   ot->description = "Resize the image";
2903
2904   /* api callbacks */
2905   ot->invoke = image_scale_invoke;
2906   ot->exec = image_scale_exec;
2907   ot->poll = image_from_context_has_data_poll_no_image_user;
2908
2909   /* properties */
2910   RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
2911
2912   /* flags */
2913   ot->flag = OPTYPE_REGISTER;
2914 }
2915
2916 /** \} */
2917
2918 /* -------------------------------------------------------------------- */
2919 /** \name Pack Operator
2920  * \{ */
2921
2922 static bool image_pack_test(bContext *C, wmOperator *op)
2923 {
2924   Image *ima = image_from_context(C);
2925
2926   if (!ima) {
2927     return 0;
2928   }
2929
2930   if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
2931     BKE_report(
2932         op->reports, RPT_ERROR, "Packing movies, image sequences or tiled images not supported");
2933     return 0;
2934   }
2935
2936   return 1;
2937 }
2938
2939 static int image_pack_exec(bContext *C, wmOperator *op)
2940 {
2941   struct Main *bmain = CTX_data_main(C);
2942   Image *ima = image_from_context(C);
2943
2944   if (!image_pack_test(C, op)) {
2945     return OPERATOR_CANCELLED;
2946   }
2947
2948   if (BKE_image_is_dirty(ima)) {
2949     BKE_image_memorypack(ima);
2950   }
2951   else {
2952     BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
2953   }
2954
2955   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2956
2957   return OPERATOR_FINISHED;
2958 }
2959
2960 void IMAGE_OT_pack(wmOperatorType *ot)
2961 {
2962   /* identifiers */
2963   ot->name = "Pack Image";
2964   ot->description = "Pack an image as embedded data into the .blend file";
2965   ot->idname = "IMAGE_OT_pack";
2966
2967   /* api callbacks */
2968   ot->exec = image_pack_exec;
2969
2970   /* flags */
2971   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2972 }
2973
2974 /** \} */
2975
2976 /* -------------------------------------------------------------------- */
2977 /** \name Unpack Operator
2978  * \{ */
2979
2980 static int image_unpack_exec(bContext *C, wmOperator *op)
2981 {
2982   Main *bmain = CTX_data_main(C);
2983   Image *ima = image_from_context(C);
2984   int method = RNA_enum_get(op->ptr, "method");
2985
2986   /* find the supplied image by name */
2987   if (RNA_struct_property_is_set(op->ptr, "id")) {
2988     char imaname[MAX_ID_NAME - 2];
2989     RNA_string_get(op->ptr, "id", imaname);
2990     ima = BLI_findstring(&bmain->images, imaname, offsetof(ID, name) + 2);
2991     if (!ima) {
2992       ima = image_from_context(C);
2993     }
2994   }
2995
2996   if (!ima || !BKE_image_has_packedfile(ima)) {
2997     return OPERATOR_CANCELLED;
2998   }
2999
3000   if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
3001     BKE_report(
3002         op->reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
3003     return OPERATOR_CANCELLED;
3004   }
3005
3006   if (G.fileflags & G_FILE_AUTOPACK) {
3007     BKE_report(op->reports,
3008                RPT_WARNING,
3009                "AutoPack is enabled, so image will be packed again on file save");
3010   }
3011
3012   /* XXX BKE_packedfile_unpack_image frees image buffers */
3013   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
3014
3015   BKE_packedfile_unpack_image(CTX_data_main(C), op->reports, ima, method);
3016
3017   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
3018
3019   return OPERATOR_FINISHED;
3020 }
3021
3022 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
3023 {
3024   Image *ima = image_from_context(C);
3025
3026   if (RNA_struct_property_is_set(op->ptr, "id")) {
3027     return image_unpack_exec(C, op);
3028   }
3029
3030   if (!ima || !BKE_image_has_packedfile(ima)) {
3031     return OPERATOR_CANCELLED;
3032   }
3033
3034   if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
3035     BKE_report(
3036         op->reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
3037     return OPERATOR_CANCELLED;
3038   }
3039
3040   if (G.fileflags & G_FILE_AUTOPACK) {
3041     BKE_report(op->reports,
3042                RPT_WARNING,
3043                "AutoPack is enabled, so image will be packed again on file save");
3044   }
3045
3046   unpack_menu(C,
3047               "IMAGE_OT_unpack",
3048               ima->id.name + 2,
3049               ima->filepath,
3050               "textures",
3051               BKE_image_has_packedfile(ima) ?
3052                   ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
3053                   NULL);
3054
3055   return OPERATOR_FINISHED;
3056 }
3057
3058 void IMAGE_OT_unpack(wmOperatorType *ot)
3059 {
3060   /* identifiers */
3061   ot->name = "Unpack Image";
3062   ot->description = "Save an image packed in the .blend file to disk";
3063   ot->idname = "IMAGE_OT_unpack";
3064
3065   /* api callbacks */
3066   ot->exec = image_unpack_exec;
3067   ot->invoke = image_unpack_invoke;
3068
3069   /* flags */
3070   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3071
3072   /* properties */
3073   RNA_def_enum(
3074       ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
3075   /* XXX, weak!, will fail with library, name collisions */
3076   RNA_def_string(
3077       ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
3078 }
3079
3080 /** \} */
3081
3082 /* -------------------------------------------------------------------- */
3083 /** \name Sample Image Operator
3084  * \{ */
3085
3086 /* Returns color in linear space, matching ED_space_node_color_sample(). */
3087 bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2], float r_col[3])
3088 {
3089   if (sima->image == NULL) {
3090     return false;
3091   }
3092   float uv[2];
3093   UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &uv[0], &uv[1]);
3094   int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
3095
3096   void *lock;
3097   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
3098   bool ret = false;
3099
3100   if (ibuf == NULL) {
3101     ED_space_image_release_buffer(sima, ibuf, lock);
3102     return false;
3103   }
3104
3105   if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
3106     const float *fp;
3107     uchar *cp;
3108     int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
3109
3110     CLAMP(x, 0, ibuf->x - 1);
3111     CLAMP(y, 0, ibuf->y - 1);
3112
3113     if (ibuf->rect_float) {
3114       fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
3115       copy_v3_v3(r_col, fp);
3116       ret = true;
3117     }
3118     else if (ibuf->rect) {
3119       cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
3120       rgb_uchar_to_float(r_col, cp);
3121       IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
3122       ret = true;
3123     }
3124   }
3125
3126   ED_space_image_release_buffer(sima, ibuf, lock);
3127   return ret;
3128 }
3129
3130 void IMAGE_OT_sample(wmOperatorType *ot)
3131 {
3132   /* identifiers */
3133   ot->name = "Sample Color";
3134   ot->idname = "IMAGE_OT_sample";
3135   ot->description = "Use mouse to sample a color in current image";
3136
3137   /* api callbacks */
3138   ot->invoke = ED_imbuf_sample_invoke;
3139   ot->modal = ED_imbuf_sample_modal;
3140   ot->cancel = ED_imbuf_sample_cancel;
3141   ot->poll = ED_imbuf_sample_poll;
3142
3143   /* flags */
3144   ot->flag = OPTYPE_BLOCKING;
3145
3146   PropertyRNA *prop;
3147   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3148   RNA_def_property_subtype(prop, PROP_PIXEL);
3149   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3150 }
3151
3152 /** \} */
3153
3154 /* -------------------------------------------------------------------- */
3155 /** \name Sample Line Operator
3156  * \{ */
3157
3158 static int image_sample_line_exec(bContext *C, wmOperator *op)
3159 {
3160   SpaceImage *sima = CTX_wm_space_image(C);
3161   ARegion *region = CTX_wm_region(C);
3162   Scene *scene = CTX_data_scene(C);
3163   Image *ima = ED_space_image(sima);
3164
3165   int x_start = RNA_int_get(op->ptr, "xstart");
3166   int y_start = RNA_int_get(op->ptr, "ystart");
3167   int x_end = RNA_int_get(op->ptr, "xend");
3168   int y_end = RNA_int_get(op->ptr, "yend");
3169
3170   float uv1[2], uv2[2], ofs[2];
3171   UI_view2d_region_to_view(&region->v2d, x_start, y_start, &uv1[0], &uv1[1]);
3172   UI_view2d_region_to_view(&region->v2d, x_end, y_end, &uv2[0], &uv2[1]);
3173
3174   /* If the image has tiles, shift the positions accordingly. */
3175   int tile = BKE_image_get_tile_from_pos(ima, uv1, uv1, ofs);
3176   sub_v2_v2(uv2, ofs);
3177
3178   void *lock;
3179   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
3180   Histogram *hist = &sima->sample_line_hist;
3181
3182   if (ibuf == NULL) {
3183     ED_space_image_release_buffer(sima, ibuf, lock);
3184     return OPERATOR_CANCELLED;
3185   }
3186   /* hmmmm */
3187   if (ibuf->channels < 3) {
3188     ED_space_image_release_buffer(sima, ibuf, lock);
3189     return OPERATOR_CANCELLED;
3190   }
3191
3192   copy_v2_v2(hist->co[0], uv1);
3193   copy_v2_v2(hist->co[1], uv2);
3194
3195   /* enable line drawing */
3196   hist->flag |= HISTO_FLAG_SAMPLELINE;
3197
3198   BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
3199
3200   /* reset y zoom */
3201   hist->ymax = 1.0f;
3202
3203   ED_space_image_release_buffer(sima, ibuf, lock);
3204
3205   ED_area_tag_redraw(CTX_wm_area(C));
3206
3207   return OPERATOR_FINISHED;
3208 }
3209
3210 static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3211 {
3212   SpaceImage *sima = CTX_wm_space_image(C);
3213
3214   Histogram *hist = &sima->sample_line_hist;
3215   hist->flag &= ~HISTO_FLAG_SAMPLELINE;
3216
3217   if (!ED_space_image_has_buffer(sima)) {
3218     return OPERATOR_CANCELLED;
3219   }
3220
3221   return WM_gesture_straightline_invoke(C, op, event);
3222 }
3223
3224 void IMAGE_OT_sample_line(wmOperatorType *ot)
3225 {
3226   /* identifiers */
3227   ot->name = "Sample Line";
3228   ot->idname = "IMAGE_OT_sample_line";
3229   ot->description = "Sample a line and show it in Scope panels";
3230
3231   /* api callbacks */
3232   ot->invoke = image_sample_line_invoke;
3233   ot->modal = WM_gesture_straightline_modal;
3234   ot->exec = image_sample_line_exec;
3235   ot->poll = space_image_main_region_poll;
3236   ot->cancel = WM_gesture_straightline_cancel;
3237
3238   /* flags */
3239   ot->flag = 0; /* no undo/register since this operates on the space */
3240
3241   WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
3242 }
3243
3244 /** \} */
3245
3246 /* -------------------------------------------------------------------- */
3247 /** \name Set Curve Point Operator
3248  * \{ */
3249
3250 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
3251 {
3252   static const EnumPropertyItem point_items[] = {
3253       {0, "BLACK_POINT", 0, "Black Point", ""},
3254       {1, "WHITE_POINT", 0, "White Point", ""},
3255       {0, NULL, 0, NULL, NULL},
3256   };
3257
3258   /* identifiers */
3259   ot->name = "Set Curves Point";
3260   ot->idname = "IMAGE_OT_curves_point_set";
3261   ot->description = "Set black point or white point for curves";
3262
3263   /* flags */
3264   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3265
3266   /* api callbacks */
3267   ot->invoke = ED_imbuf_sample_invoke;
3268   ot->modal = ED_imbuf_sample_modal;
3269   ot->cancel = ED_imbuf_sample_cancel;
3270   ot->poll = space_image_main_area_not_uv_brush_poll;
3271
3272   /* properties */
3273   RNA_def_enum(
3274       ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3275
3276   PropertyRNA *prop;
3277   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3278   RNA_def_property_subtype(prop, PROP_PIXEL);
3279   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3280 }
3281
3282 /** \} */
3283
3284 /* -------------------------------------------------------------------- */
3285 /** \name Cycle Render Slot Operator
3286  * \{ */
3287
3288 static bool image_cycle_render_slot_poll(bContext *C)
3289 {
3290   Image *ima = image_from_context(C);
3291
3292   return (ima && ima->type == IMA_TYPE_R_RESULT);
3293 }
3294
3295 static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
3296 {
3297   Image *ima = image_from_context(C);
3298   const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3299
3300   if (!ED_image_slot_cycle(ima, direction)) {
3301     return OPERATOR_CANCELLED;
3302   }
3303
3304   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3305
3306   /* no undo push for browsing existing */
3307   RenderSlot *slot = BKE_image_get_renderslot(ima, ima->render_slot);
3308   if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3309     return OPERATOR_CANCELLED;
3310   }
3311
3312   return OPERATOR_FINISHED;
3313 }
3314
3315 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
3316 {
3317   /* identifiers */
3318   ot->name = "Cycle Render Slot";
3319   ot->idname = "IMAGE_OT_cycle_render_slot";
3320   ot->description = "Cycle through all non-void render slots";
3321
3322   /* api callbacks */
3323   ot->exec = image_cycle_render_slot_exec;
3324   ot->poll = image_cycle_render_slot_poll;
3325
3326   /* flags */
3327   ot->flag = OPTYPE_REGISTER;
3328
3329   RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
3330 }
3331
3332 /** \} */
3333
3334 /* -------------------------------------------------------------------- */
3335 /** \name Clear Render Slot Operator
3336  * \{ */
3337
3338 static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3339 {
3340   SpaceImage *sima = CTX_wm_space_image(C);
3341   Image *ima = image_from_context(C);
3342
3343   if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
3344     return OPERATOR_CANCELLED;
3345   }
3346
3347   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3348
3349   return OPERATOR_FINISHED;
3350 }
3351
3352 void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
3353 {
3354   /* identifiers */
3355   ot->name = "Clear Render Slot";
3356   ot->idname = "IMAGE_OT_clear_render_slot";
3357   ot->description = "Clear the currently selected render slot";
3358
3359   /* api callbacks */
3360   ot->exec = image_clear_render_slot_exec;
3361   ot->poll = image_cycle_render_slot_poll;
3362
3363   /* flags */
3364   ot->flag = OPTYPE_REGISTER;
3365 }
3366
3367 /** \} */
3368
3369 /* -------------------------------------------------------------------- */
3370 /** \name Add Render Slot Operator
3371  * \{ */
3372
3373 static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3374 {
3375   Image *ima = image_from_context(C);
3376
3377   RenderSlot *slot = BKE_image_add_renderslot(ima, NULL);
3378   ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3379
3380   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3381
3382   return OPERATOR_FINISHED;
3383 }
3384
3385 void IMAGE_OT_add_render_slot(wmOperatorType *ot)
3386 {
3387   /* identifiers */
3388   ot->name = "Add Render Slot";
3389   ot->idname = "IMAGE_OT_add_render_slot";
3390   ot->description = "Add a new render slot";
3391
3392   /* api callbacks */
3393   ot->exec = image_add_render_slot_exec;
3394   ot->poll = image_cycle_render_slot_poll;
3395
3396   /* flags */
3397   ot->flag = OPTYPE_REGISTER;
3398 }
3399
3400 /** \} */
3401
3402 /* -------------------------------------------------------------------- */
3403 /** \name Remove Render Slot Operator
3404  * \{ */
3405
3406 static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3407 {
3408   SpaceImage *sima = CTX_wm_space_image(C);
3409   Image *ima = image_from_context(C);
3410
3411   if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
3412     return OPERATOR_CANCELLED;
3413   }
3414
3415   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3416
3417   return OPERATOR_FINISHED;
3418 }
3419
3420 void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
3421 {
3422   /* identifiers */
3423   ot->name = "Remove Render Slot";
3424   ot->idname = "IMAGE_OT_remove_render_slot";
3425   ot->description = "Remove the current render slot";
3426
3427   /* api callbacks */
3428   ot->exec = image_remove_render_slot_exec;
3429   ot->poll = image_cycle_render_slot_poll;
3430
3431   /* flags */
3432   ot->flag = OPTYPE_REGISTER;
3433 }
3434
3435 /** \} */
3436
3437 /* -------------------------------------------------------------------- */
3438 /** \name Change Frame Operator
3439  * \{ */
3440
3441 static bool change_frame_poll(bContext *C)
3442 {
3443   /* prevent changes during render */
3444   if (G.is_rendering) {
3445     return 0;
3446   }
3447
3448   return space_image_main_region_poll(C);
3449 }
3450
3451 static void change_frame_apply(bContext *C, wmOperator *op)
3452 {
3453   Scene *scene = CTX_data_scene(C);
3454
3455   /* set the new frame number */
3456   CFRA = RNA_int_get(op->ptr, "frame");
3457   FRAMENUMBER_MIN_CLAMP(CFRA);
3458   SUBFRA = 0.0f;
3459
3460   /* do updates */
3461   DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
3462   WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
3463 }
3464
3465 static int change_frame_exec(bContext *C, wmOperator *op)
3466 {
3467   change_frame_apply(C, op);
3468
3469   return OPERATOR_FINISHED;
3470 }
3471
3472 static int frame_from_event(bContext *C, const wmEvent *event)
3473 {
3474   ARegion *region = CTX_wm_region(C);
3475   Scene *scene = CTX_data_scene(C);
3476   int framenr = 0;
3477
3478   if (region->regiontype == RGN_TYPE_WINDOW) {
3479     float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
3480
3481     framenr = sfra + event->mval[0] / framelen;
3482   }
3483   else {
3484     float viewx, viewy;
3485
3486     UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3487
3488     framenr = round_fl_to_int(viewx);
3489   }
3490
3491   return framenr;
3492 }
3493
3494 static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3495 {
3496   ARegion *region = CTX_wm_region(C);
3497
3498   if (region->regiontype == RGN_TYPE_WINDOW) {
3499     SpaceImage *sima = CTX_wm_space_image(C);
3500
3501     /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
3502     const rcti *rect_visible = ED_region_visible_rect(region);
3503     const int region_bottom = rect_visible->ymin;
3504
3505     if (event->mval[1] > (region_bottom + 16 * UI_DPI_FAC) || !ED_space_image_show_cache(sima)) {
3506       return OPERATOR_PASS_THROUGH;
3507     }
3508   }
3509
3510   RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3511
3512   change_frame_apply(C, op);
3513
3514   /* add temp handler */
3515   WM_event_add_modal_handler(C, op);
3516
3517   return OPERATOR_RUNNING_MODAL;
3518 }
3519
3520 static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
3521 {
3522   switch (event->type) {
3523     case EVT_ESCKEY:
3524       return OPERATOR_FINISHED;
3525
3526     case MOUSEMOVE:
3527       RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3528       change_frame_apply(C, op);
3529       break;
3530
3531     case LEFTMOUSE:
3532     case RIGHTMOUSE:
3533       if (event->val == KM_RELEASE) {
3534         return OPERATOR_FINISHED;
3535       }
3536       break;
3537   }
3538
3539   return OPERATOR_RUNNING_MODAL;
3540 }
3541
3542 void IMAGE_OT_change_frame(wmOperatorType *ot)
3543 {
3544   /* identifiers */
3545   ot->name = "Change Frame";
3546   ot->idname = "IMAGE_OT_change_frame";
3547   ot->description = "Interactively change the current frame number";
3548
3549   /* api callbacks */
3550   ot->exec = change_frame_exec;
3551   ot->invoke = change_frame_invoke;
3552   ot->modal = change_frame_modal;
3553   ot->poll = change_frame_poll;
3554
3555   /* flags */
3556   ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
3557
3558   /* rna */
3559   RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
3560 }
3561
3562 /* Reload cached render results... */
3563 /* goes over all scenes, reads render layers */
3564 static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
3565 {
3566   Main *bmain = CTX_data_main(C);
3567   Scene *scene = CTX_data_scene(C);
3568   SpaceImage *sima = CTX_wm_space_image(C);
3569   Image *ima;
3570
3571   ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
3572   if (sima->image == NULL) {
3573     ED_space_image_set(bmain, sima, NULL, ima, false);
3574   }
3575
3576   RE_ReadRenderResult(scene, scene);
3577
3578   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
3579   return OPERATOR_FINISHED;
3580 }
3581
3582 void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
3583 {
3584   ot->name = "Open Cached Render";
3585   ot->idname = "IMAGE_OT_read_viewlayers";
3586   ot->description = "Read all the current scene's view layers from cache, as needed";
3587
3588   ot->poll = space_image_main_region_poll;
3589   ot->exec = image_read_viewlayers_exec;
3590
3591   /* flags */
3592   ot->flag = 0;
3593 }
3594
3595 /** \} */
3596
3597 /* -------------------------------------------------------------------- */
3598 /** \name Render Border Operator
3599  * \{ */
3600
3601 static int render_border_exec(bContext *C, wmOperator *op)
3602 {
3603   ARegion *region = CTX_wm_region(C);
3604   Scene *scene = CTX_data_scene(C);
3605   Render *re = RE_GetSceneRender(scene);
3606   RenderData *rd;
3607   rctf border;
3608
3609   if (re == NULL) {
3610     /* Shouldn't happen, but better be safe close to the release. */
3611     return OPERATOR_CANCELLED;
3612   }
3613
3614   rd = RE_engine_get_render_data(re);
3615   if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
3616     BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
3617     return OPERATOR_CANCELLED;
3618   }
3619
3620   /* get rectangle from operator */
3621   WM_operator_properties_border_to_rctf(op, &border);
3622   UI_view2d_region_to_view_rctf(&region->v2d, &border, &border);
3623
3624   /* actually set border */
3625   CLAMP(border.xmin, 0.0f, 1.0f);
3626   CLAMP(border.ymin, 0.0f, 1.0f);
3627   CLAMP(border.xmax, 0.0f, 1.0f);
3628   CLAMP(border.ymax, 0.0f, 1.0f);
3629   scene->r.border = border;
3630
3631   /* drawing a border surrounding the entire camera view switches off border rendering
3632    * or the border covers no pixels */
3633   if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
3634       (border.xmin == border.xmax || border.ymin == border.ymax)) {
3635     scene->r.mode &= ~R_BORDER;
3636   }
3637   else {
3638     scene->r.mode |= R_BORDER;
3639   }
3640
3641   DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
3642   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3643
3644   return OPERATOR_FINISHED;
3645 }
3646
3647 void IMAGE_OT_render_border(wmOperatorType *ot)
3648 {
3649   /* identifiers */
3650   ot->name = "Render Region";
3651   ot->description = "Set the boundaries of the render region and enable render region";
3652   ot->idname = "IMAGE_OT_render_border";
3653
3654   /* api callbacks */
3655   ot->invoke = WM_gesture_box_invoke;
3656   ot->exec = render_border_exec;
3657   ot->modal = WM_gesture_box_modal;
3658   ot->cancel = WM_gesture_box_cancel;
3659   ot->poll = image_cycle_render_slot_poll;
3660
3661   /* flags */
3662   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3663
3664   /* rna */
3665   WM_operator_properties_border(ot);
3666 }
3667
3668 /** \} */
3669
3670 /* -------------------------------------------------------------------- */
3671 /** \name Clear Render Border Operator
3672  * \{ */
3673
3674 static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
3675 {
3676   Scene *scene = CTX_data_scene(C);
3677   scene->r.mode &= ~R_BORDER;
3678   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3679   BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
3680   return OPERATOR_FINISHED;
3681 }
3682
3683 void IMAGE_OT_clear_render_border(wmOperatorType *ot)
3684 {
3685   /* identifiers */
3686   ot->name = "Clear Render Region";
3687   ot->description = "Clear the boundaries of the render region and disable render region";
3688   ot->idname = "IMAGE_OT_clear_render_border";
3689
3690   /* api callbacks */
3691   ot->exec = clear_render_border_exec;
3692   ot->poll = image_cycle_render_slot_poll;
3693
3694   /* flags */
3695   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3696 }
3697
3698 /** \} */
3699
3700 /* -------------------------------------------------------------------- */
3701 /** \name Add Tile Operator
3702  * \{ */
3703
3704 static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
3705 {
3706   float color[4];
3707   RNA_float_get_array(ptr, "color", color);
3708   int gen_type = RNA_enum_get(ptr, "generated_type");
3709   int width = RNA_int_get(ptr, "width");
3710   int height = RNA_int_get(ptr, "height");
3711   bool is_float = RNA_boolean_get(ptr, "float");
3712   int planes = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
3713
3714   return BKE_image_fill_tile(ima, tile, width, height, color, gen_type, planes, is_float);
3715 }
3716
3717 static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
3718 {
3719   uiLayout *split, *col[2];
3720
3721   split = uiLayoutSplit(layout, 0.5f, false);
3722   col[0] = uiLayoutColumn(split, false);
3723   col[1] = uiLayoutColumn(split, false);
3724
3725   uiItemL(col[0], IFACE_("Color"), ICON_NONE);
3726   uiItemR(col[1], ptr, "color", 0, "", ICON_NONE);
3727
3728   uiItemL(col[0], IFACE_("Width"), ICON_NONE);
3729   uiItemR(col[1], ptr, "width", 0, "", ICON_NONE);
3730
3731   uiItemL(col[0], IFACE_("Height"), ICON_NONE);
3732   uiItemR(col[1], ptr, "height", 0, "", ICON_NONE);
3733
3734   uiItemL(col[0], "", ICON_NONE);
3735   uiItemR(col[1], ptr, "alpha", 0, NULL, ICON_NONE);
3736
3737   uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
3738   uiItemR(col[1], ptr, "generated_type", 0, "", ICON_NONE);
3739
3740   uiItemL(col[0], "", ICON_NONE);
3741   uiItemR(col[1], ptr, "float", 0, NULL, ICON_NONE);
3742 }
3743
3744 static void initialize_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
3745 {
3746   ImageUser iuser;
3747   BKE_imageuser_default(&iuser);
3748   if (tile != NULL) {
3749     iuser.tile = tile->tile_number;
3750   }
3751
3752   /* Acquire ibuf to get the default values.
3753    * If the specified tile has no ibuf, try acquiring the main tile instead
3754    * (unless the specified tile already was the main tile).*/
3755   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
3756   if (ibuf == NULL && (tile != NULL) && (tile->tile_number != 1001)) {
3757     ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
3758   }
3759
3760   if (ibuf != NULL) {
3761     /* Initialize properties from reference tile. */
3762     RNA_int_set(ptr, "width", ibuf->x);
3763     RNA_int_set(ptr, "height", ibuf->y);
3764     RNA_boolean_set(ptr, "float", ibuf->rect_float != NULL);
3765     RNA_boolean_set(ptr, "alpha", ibuf->planes > 24);
3766
3767     BKE_image_release_ibuf(ima, ibuf, NULL);
3768   }
3769 }
3770
3771 static void def_fill_tile(StructOrFunctionRNA *srna)
3772 {
3773   PropertyRNA *prop;
3774   static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3775   prop = RNA_def_float_color(
3776       srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
3777   RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
3778   RNA_def_property_float_array_default(prop, default_color);
3779   RNA_def_enum(srna,
3780                "generated_type",
3781                rna_enum_image_generated_type_items,
3782                IMA_GENTYPE_BLANK,
3783                "Generated Type",
3784                "Fill the image with a grid for UV map testing");
3785   prop = RNA_def_int(srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
3786   RNA_de