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