d69c34ad2596a979220ee1495a1544a0d29405b7
[blender.git] / source / blender / editors / space_image / image_ops.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2009, Xavier Thomas
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_object_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_packedFile_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "BKE_colortools.h"
41 #include "BKE_context.h"
42 #include "BKE_image.h"
43 #include "BKE_global.h"
44 #include "BKE_image.h"
45 #include "BKE_library.h"
46 #include "BKE_main.h"
47 #include "BKE_node.h"
48 #include "BKE_packedFile.h"
49 #include "BKE_report.h"
50 #include "BKE_screen.h"
51
52 #include "BLI_math.h"
53 #include "BLI_blenlib.h"
54
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "RE_pipeline.h"
59
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 #include "RNA_enum_types.h"
63
64 #include "ED_image.h"
65 #include "ED_screen.h"
66 #include "ED_space_api.h"
67 #include "ED_uvedit.h"
68
69 #include "UI_interface.h"
70 #include "UI_resources.h"
71 #include "UI_view2d.h"
72
73 #include "WM_api.h"
74 #include "WM_types.h"
75
76 #include "image_intern.h"
77
78 /******************** view navigation utilities *********************/
79
80 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom)
81 {
82         float oldzoom= sima->zoom;
83         int width, height;
84
85         sima->zoom= zoom;
86
87         if (sima->zoom > 0.1f && sima->zoom < 4.0f)
88                 return;
89
90         /* check zoom limits */
91         ED_space_image_size(sima, &width, &height);
92
93         width *= sima->zoom;
94         height *= sima->zoom;
95
96         if((width < 4) && (height < 4))
97                 sima->zoom= oldzoom;
98         else if((ar->winrct.xmax - ar->winrct.xmin) <= sima->zoom)
99                 sima->zoom= oldzoom;
100         else if((ar->winrct.ymax - ar->winrct.ymin) <= sima->zoom)
101                 sima->zoom= oldzoom;
102 }
103
104 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac)
105 {
106         sima_zoom_set(sima, ar, sima->zoom*zoomfac);
107 }
108
109 #if 0 // currently unused
110 static int image_poll(bContext *C)
111 {
112         return (CTX_data_edit_image(C) != NULL);
113 }
114 #endif
115
116 static int space_image_buffer_exists_poll(bContext *C)
117 {
118         SpaceImage *sima= CTX_wm_space_image(C);
119         if(sima && sima->spacetype==SPACE_IMAGE)
120                 if(ED_space_image_has_buffer(sima))
121                         return 1;
122         return 0;
123 }
124
125 static int space_image_file_exists_poll(bContext *C)
126 {
127         if(space_image_buffer_exists_poll(C)) {
128                 SpaceImage *sima= CTX_wm_space_image(C);
129                 ImBuf *ibuf;
130                 void *lock;
131                 int poll= 0;
132                 char name[FILE_MAX];
133
134                 ibuf= ED_space_image_acquire_buffer(sima, &lock);
135                 if(ibuf) {
136                         BLI_strncpy(name, ibuf->name, FILE_MAX);
137                         BLI_path_abs(name, G.sce);
138                         poll= (BLI_exists(name) && BLI_is_writable(name));
139                 }
140                 ED_space_image_release_buffer(sima, lock);
141
142                 return poll;
143         }
144         return 0;
145 }
146
147 static int space_image_poll(bContext *C)
148 {
149         SpaceImage *sima= CTX_wm_space_image(C);
150         if(sima && sima->spacetype==SPACE_IMAGE && sima->image)
151                 return 1;
152         return 0;
153 }
154
155 int space_image_main_area_poll(bContext *C)
156 {
157         SpaceImage *sima= CTX_wm_space_image(C);
158         // XXX ARegion *ar= CTX_wm_region(C);
159
160         if(sima)
161                 return 1; // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW);
162         
163         return 0;
164 }
165
166 /********************** view pan operator *********************/
167
168 typedef struct ViewPanData {
169         float x, y;
170         float xof, yof;
171 } ViewPanData;
172
173 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
174 {
175         SpaceImage *sima= CTX_wm_space_image(C);
176         ViewPanData *vpd;
177
178         op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
179         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
180
181         vpd->x= event->x;
182         vpd->y= event->y;
183         vpd->xof= sima->xof;
184         vpd->yof= sima->yof;
185
186         WM_event_add_modal_handler(C, op);
187 }
188
189 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
190 {
191         SpaceImage *sima= CTX_wm_space_image(C);
192         ViewPanData *vpd= op->customdata;
193
194         if(cancel) {
195                 sima->xof= vpd->xof;
196                 sima->yof= vpd->yof;
197                 ED_region_tag_redraw(CTX_wm_region(C));
198         }
199
200         WM_cursor_restore(CTX_wm_window(C));
201         MEM_freeN(op->customdata);
202 }
203
204 static int view_pan_exec(bContext *C, wmOperator *op)
205 {
206         SpaceImage *sima= CTX_wm_space_image(C);
207         float offset[2];
208
209         RNA_float_get_array(op->ptr, "offset", offset);
210         sima->xof += offset[0];
211         sima->yof += offset[1];
212
213         ED_region_tag_redraw(CTX_wm_region(C));
214
215         /* XXX notifier? */
216 #if 0
217         if(image_preview_active(curarea, NULL, NULL)) {
218                 /* recalculates new preview rect */
219                 scrarea_do_windraw(curarea);
220                 image_preview_event(2);
221         }
222 #endif
223         
224         return OPERATOR_FINISHED;
225 }
226
227 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
228 {
229         if (event->type == MOUSEPAN) {
230                 SpaceImage *sima= CTX_wm_space_image(C);
231                 float offset[2];
232                 
233                 offset[0]= (event->x - event->prevx)/sima->zoom;
234                 offset[1]= (event->y - event->prevy)/sima->zoom;
235                 RNA_float_set_array(op->ptr, "offset", offset);
236
237                 view_pan_exec(C, op);
238                 return OPERATOR_FINISHED;
239         }
240         else {
241                 view_pan_init(C, op, event);
242                 return OPERATOR_RUNNING_MODAL;
243         }
244 }
245
246 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
247 {
248         SpaceImage *sima= CTX_wm_space_image(C);
249         ViewPanData *vpd= op->customdata;
250         float offset[2];
251
252         switch(event->type) {
253                 case MOUSEMOVE:
254                         sima->xof= vpd->xof;
255                         sima->yof= vpd->yof;
256                         offset[0]= (vpd->x - event->x)/sima->zoom;
257                         offset[1]= (vpd->y - event->y)/sima->zoom;
258                         RNA_float_set_array(op->ptr, "offset", offset);
259                         view_pan_exec(C, op);
260                         break;
261                 case MIDDLEMOUSE:
262                 case LEFTMOUSE:
263                         if(event->val==KM_RELEASE) {
264                                 view_pan_exit(C, op, 0);
265                                 return OPERATOR_FINISHED;
266                         }
267                         break;
268         }
269
270         return OPERATOR_RUNNING_MODAL;
271 }
272
273 static int view_pan_cancel(bContext *C, wmOperator *op)
274 {
275         view_pan_exit(C, op, 1);
276         return OPERATOR_CANCELLED;
277 }
278
279 void IMAGE_OT_view_pan(wmOperatorType *ot)
280 {
281         /* identifiers */
282         ot->name= "View Pan";
283         ot->idname= "IMAGE_OT_view_pan";
284         
285         /* api callbacks */
286         ot->exec= view_pan_exec;
287         ot->invoke= view_pan_invoke;
288         ot->modal= view_pan_modal;
289         ot->cancel= view_pan_cancel;
290         ot->poll= space_image_main_area_poll;
291
292         /* flags */
293         ot->flag= OPTYPE_BLOCKING;
294         
295         /* properties */
296         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
297                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
298 }
299
300 /********************** view zoom operator *********************/
301
302 typedef struct ViewZoomData {
303         float x, y;
304         float zoom;
305 } ViewZoomData;
306
307 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
308 {
309         SpaceImage *sima= CTX_wm_space_image(C);
310         ViewZoomData *vpd;
311
312         op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
313         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
314
315         vpd->x= event->x;
316         vpd->y= event->y;
317         vpd->zoom= sima->zoom;
318
319         WM_event_add_modal_handler(C, op);
320 }
321
322 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
323 {
324         SpaceImage *sima= CTX_wm_space_image(C);
325         ViewZoomData *vpd= op->customdata;
326
327         if(cancel) {
328                 sima->zoom= vpd->zoom;
329                 ED_region_tag_redraw(CTX_wm_region(C));
330         }
331
332         WM_cursor_restore(CTX_wm_window(C));
333         MEM_freeN(op->customdata);
334 }
335
336 static int view_zoom_exec(bContext *C, wmOperator *op)
337 {
338         SpaceImage *sima= CTX_wm_space_image(C);
339         ARegion *ar= CTX_wm_region(C);
340
341         sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"));
342
343         ED_region_tag_redraw(CTX_wm_region(C));
344
345         /* XXX notifier? */
346 #if 0
347         if(image_preview_active(curarea, NULL, NULL)) {
348                 /* recalculates new preview rect */
349                 scrarea_do_windraw(curarea);
350                 image_preview_event(2);
351         }
352 #endif
353         
354         return OPERATOR_FINISHED;
355 }
356
357 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
358 {
359         if (event->type == MOUSEZOOM) {
360                 SpaceImage *sima= CTX_wm_space_image(C);
361                 ARegion *ar= CTX_wm_region(C);
362                 float factor;
363                 
364                 factor= 1.0 + (event->x-event->prevx+event->y-event->prevy)/300.0f;
365                 RNA_float_set(op->ptr, "factor", factor);
366                 sima_zoom_set(sima, ar, sima->zoom*factor);
367                 ED_region_tag_redraw(CTX_wm_region(C));
368                 
369                 return OPERATOR_FINISHED;
370         }
371         else {
372                 view_zoom_init(C, op, event);
373                 return OPERATOR_RUNNING_MODAL;
374         }
375 }
376
377 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
378 {
379         SpaceImage *sima= CTX_wm_space_image(C);
380         ARegion *ar= CTX_wm_region(C);
381         ViewZoomData *vpd= op->customdata;
382         float factor;
383
384         switch(event->type) {
385                 case MOUSEMOVE:
386                         factor= 1.0 + (vpd->x-event->x+vpd->y-event->y)/300.0f;
387                         RNA_float_set(op->ptr, "factor", factor);
388                         sima_zoom_set(sima, ar, vpd->zoom*factor);
389                         ED_region_tag_redraw(CTX_wm_region(C));
390                         break;
391                 case MIDDLEMOUSE:
392                 case LEFTMOUSE:
393                         if(event->val==KM_RELEASE) {
394                                 view_zoom_exit(C, op, 0);
395                                 return OPERATOR_FINISHED;
396                         }
397                         break;
398         }
399
400         return OPERATOR_RUNNING_MODAL;
401 }
402
403 static int view_zoom_cancel(bContext *C, wmOperator *op)
404 {
405         view_zoom_exit(C, op, 1);
406         return OPERATOR_CANCELLED;
407 }
408
409 void IMAGE_OT_view_zoom(wmOperatorType *ot)
410 {
411         /* identifiers */
412         ot->name= "View Zoom";
413         ot->idname= "IMAGE_OT_view_zoom";
414         
415         /* api callbacks */
416         ot->exec= view_zoom_exec;
417         ot->invoke= view_zoom_invoke;
418         ot->modal= view_zoom_modal;
419         ot->cancel= view_zoom_cancel;
420         ot->poll= space_image_main_area_poll;
421
422         /* flags */
423         ot->flag= OPTYPE_BLOCKING;
424         
425         /* properties */
426         RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
427                 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
428 }
429
430 /********************** view all operator *********************/
431
432 /* Updates the fields of the View2D member of the SpaceImage struct.
433  * Default behavior is to reset the position of the image and set the zoom to 1
434  * If the image will not fit within the window rectangle, the zoom is adjusted */
435
436 static int view_all_exec(bContext *C, wmOperator *op)
437 {
438         SpaceImage *sima;
439         ARegion *ar;
440         Scene *scene;
441         Object *obedit;
442         float aspx, aspy, zoomx, zoomy, w, h;
443         int width, height;
444
445         /* retrieve state */
446         sima= CTX_wm_space_image(C);
447         ar= CTX_wm_region(C);
448         scene= (Scene*)CTX_data_scene(C);
449         obedit= CTX_data_edit_object(C);
450
451         ED_space_image_size(sima, &width, &height);
452         ED_space_image_aspect(sima, &aspx, &aspy);
453
454         w= width*aspx;
455         h= height*aspy;
456         
457         /* check if the image will fit in the image with zoom==1 */
458         width = ar->winrct.xmax - ar->winrct.xmin + 1;
459         height = ar->winrct.ymax - ar->winrct.ymin + 1;
460
461         if((w >= width || h >= height) && (width > 0 && height > 0)) {
462                 /* find the zoom value that will fit the image in the image space */
463                 zoomx= width/w;
464                 zoomy= height/h;
465                 sima_zoom_set(sima, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
466         }
467         else
468                 sima_zoom_set(sima, ar, 1.0f);
469
470         sima->xof= sima->yof= 0.0f;
471
472         ED_region_tag_redraw(CTX_wm_region(C));
473         
474         return OPERATOR_FINISHED;
475 }
476
477 void IMAGE_OT_view_all(wmOperatorType *ot)
478 {
479         /* identifiers */
480         ot->name= "View All";
481         ot->idname= "IMAGE_OT_view_all";
482         
483         /* api callbacks */
484         ot->exec= view_all_exec;
485         ot->poll= space_image_main_area_poll;
486 }
487
488 /********************** view selected operator *********************/
489
490 static int view_selected_exec(bContext *C, wmOperator *op)
491 {
492         SpaceImage *sima;
493         ARegion *ar;
494         Scene *scene;
495         Object *obedit;
496         Image *ima;
497         float size, min[2], max[2], d[2];
498         int width, height;
499
500         /* retrieve state */
501         sima= CTX_wm_space_image(C);
502         ar= CTX_wm_region(C);
503         scene= (Scene*)CTX_data_scene(C);
504         obedit= CTX_data_edit_object(C);
505
506         ima= ED_space_image(sima);
507         ED_space_image_size(sima, &width, &height);
508
509         /* get bounds */
510         if(!ED_uvedit_minmax(scene, ima, obedit, min, max))
511                 return OPERATOR_CANCELLED;
512
513         /* adjust offset and zoom */
514         sima->xof= (int)(((min[0] + max[0])*0.5f - 0.5f)*width);
515         sima->yof= (int)(((min[1] + max[1])*0.5f - 0.5f)*height);
516
517         d[0]= max[0] - min[0];
518         d[1]= max[1] - min[1];
519         size= 0.5*MAX2(d[0], d[1])*MAX2(width, height)/256.0f;
520         
521         if(size<=0.01) size= 0.01;
522         sima_zoom_set(sima, ar, 0.7/size);
523
524         ED_region_tag_redraw(CTX_wm_region(C));
525         
526         return OPERATOR_FINISHED;
527 }
528
529 static int view_selected_poll(bContext *C)
530 {
531         return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
532 }
533
534 void IMAGE_OT_view_selected(wmOperatorType *ot)
535 {
536         /* identifiers */
537         ot->name= "View Center";
538         ot->idname= "IMAGE_OT_view_selected";
539         
540         /* api callbacks */
541         ot->exec= view_selected_exec;
542         ot->poll= view_selected_poll;
543 }
544
545 /********************** view zoom in/out operator *********************/
546
547 static int view_zoom_in_exec(bContext *C, wmOperator *op)
548 {
549         SpaceImage *sima= CTX_wm_space_image(C);
550         ARegion *ar= CTX_wm_region(C);
551
552         sima_zoom_set_factor(sima, ar, 1.25f);
553
554         ED_region_tag_redraw(CTX_wm_region(C));
555         
556         return OPERATOR_FINISHED;
557 }
558
559 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
560 {
561         /* identifiers */
562         ot->name= "View Zoom In";
563         ot->idname= "IMAGE_OT_view_zoom_in";
564         
565         /* api callbacks */
566         ot->exec= view_zoom_in_exec;
567         ot->poll= space_image_main_area_poll;
568 }
569
570 static int view_zoom_out_exec(bContext *C, wmOperator *op)
571 {
572         SpaceImage *sima= CTX_wm_space_image(C);
573         ARegion *ar= CTX_wm_region(C);
574
575         sima_zoom_set_factor(sima, ar, 0.8f);
576
577         ED_region_tag_redraw(CTX_wm_region(C));
578         
579         return OPERATOR_FINISHED;
580 }
581
582 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
583 {
584         /* identifiers */
585         ot->name= "View Zoom Out";
586         ot->idname= "IMAGE_OT_view_zoom_out";
587         
588         /* api callbacks */
589         ot->exec= view_zoom_out_exec;
590         ot->poll= space_image_main_area_poll;
591 }
592
593 /********************** view zoom ratio operator *********************/
594
595 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
596 {
597         SpaceImage *sima= CTX_wm_space_image(C);
598         ARegion *ar= CTX_wm_region(C);
599
600         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"));
601         
602         /* ensure pixel exact locations for draw */
603         sima->xof= (int)sima->xof;
604         sima->yof= (int)sima->yof;
605
606         /* XXX notifier? */
607 #if 0
608         if(image_preview_active(curarea, NULL, NULL)) {
609                 /* recalculates new preview rect */
610                 scrarea_do_windraw(curarea);
611                 image_preview_event(2);
612         }
613 #endif
614
615         ED_region_tag_redraw(CTX_wm_region(C));
616         
617         return OPERATOR_FINISHED;
618 }
619
620 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
621 {
622         /* identifiers */
623         ot->name= "View Zoom Ratio";
624         ot->idname= "IMAGE_OT_view_zoom_ratio";
625         
626         /* api callbacks */
627         ot->exec= view_zoom_ratio_exec;
628         ot->poll= space_image_main_area_poll;
629         
630         /* properties */
631         RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
632                 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out.", -FLT_MAX, FLT_MAX);
633 }
634
635 /**************** load/replace/save callbacks ******************/
636
637 /* XXX make dynamic */
638 static const EnumPropertyItem image_file_type_items[] = {
639                 {R_TARGA, "TARGA", 0, "Targa", ""},
640                 {R_RAWTGA, "TARGA RAW", 0, "Targa Raw", ""},
641                 {R_PNG, "PNG", 0, "PNG", ""},
642                 {R_BMP, "BMP", 0, "BMP", ""},
643                 {R_JPEG90, "JPEG", 0, "Jpeg", ""},
644 #ifdef WITH_OPENJPEG
645                 {R_JP2, "JPEG_2000", 0, "Jpeg 2000", ""},
646 #endif
647                 {R_IRIS, "IRIS", 0, "Iris", ""},
648 #ifdef WITH_TIFF
649                 {R_TIFF, "TIFF", 0, "Tiff", ""},
650 #endif
651                 {R_RADHDR, "RADIANCE_HDR", 0, "Radiance HDR", ""},
652                 {R_CINEON, "CINEON", 0, "Cineon", ""},
653                 {R_DPX, "DPX", 0, "DPX", ""},
654 #ifdef WITH_OPENEXR
655                 {R_OPENEXR, "OPENEXR", 0, "OpenEXR", ""},
656         /* saving sequences of multilayer won't work, they copy buffers  */
657         /*if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
658         else*/
659                 {R_MULTILAYER, "MULTILAYER", 0, "MultiLayer", ""},
660 #endif  
661                 {0, NULL, 0, NULL, NULL}};
662
663 static void image_filesel(bContext *C, wmOperator *op, const char *path)
664 {
665         RNA_string_set(op->ptr, "filepath", path);
666         WM_event_add_fileselect(C, op); 
667 }
668
669 /******************** open image operator ********************/
670
671 static void open_init(bContext *C, wmOperator *op)
672 {
673         PropertyPointerRNA *pprop;
674
675         op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
676         uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
677 }
678
679 static int open_cancel(bContext *C, wmOperator *op)
680 {
681         MEM_freeN(op->customdata);
682         op->customdata= NULL;
683         return OPERATOR_CANCELLED;
684 }
685
686 static int open_exec(bContext *C, wmOperator *op)
687 {
688         SpaceImage *sima= CTX_wm_space_image(C);
689         Scene *scene= CTX_data_scene(C);
690         Object *obedit= CTX_data_edit_object(C);
691         PropertyPointerRNA *pprop;
692         PointerRNA idptr;
693         Image *ima= NULL;
694         char str[FILE_MAX];
695
696         RNA_string_get(op->ptr, "filepath", str);
697         /* default to frame 1 if there's no scene in context */
698
699         errno= 0;
700
701         ima= BKE_add_image_file(str, scene ? scene->r.cfra : 1);
702
703         if(!ima) {
704                 if(op->customdata) MEM_freeN(op->customdata);
705                 BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", str, errno ? strerror(errno) : "Unsupported image format");
706                 return OPERATOR_CANCELLED;
707         }
708         
709         if(!op->customdata)
710                 open_init(C, op);
711
712         /* hook into UI */
713         pprop= op->customdata;
714
715         if(pprop->prop) {
716                 /* when creating new ID blocks, use is already 1, but RNA
717                  * pointer se also increases user, so this compensates it */
718                 ima->id.us--;
719
720                 RNA_id_pointer_create(&ima->id, &idptr);
721                 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
722                 RNA_property_update(C, &pprop->ptr, pprop->prop);
723         }
724         else if(sima)
725                 ED_space_image_set(C, sima, scene, obedit, ima);
726
727         // XXX other users?
728         BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD);
729         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
730         
731         MEM_freeN(op->customdata);
732
733         return OPERATOR_FINISHED;
734 }
735
736 static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
737 {
738         SpaceImage *sima= CTX_wm_space_image(C);
739         char *path= (sima && sima->image)? sima->image->name: U.textudir;
740
741         if(!RNA_property_is_set(op->ptr, "relative_path"))
742                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
743
744         if(RNA_property_is_set(op->ptr, "filepath"))
745                 return open_exec(C, op);
746         
747         open_init(C, op);
748
749         image_filesel(C, op, path);
750
751         return OPERATOR_RUNNING_MODAL;
752 }
753
754 void IMAGE_OT_open(wmOperatorType *ot)
755 {
756         /* identifiers */
757         ot->name= "Open";
758         ot->idname= "IMAGE_OT_open";
759         
760         /* api callbacks */
761         ot->exec= open_exec;
762         ot->invoke= open_invoke;
763         ot->cancel= open_cancel;
764
765         /* flags */
766         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
767
768         /* properties */
769         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
770 }
771
772 /******************** replace image operator ********************/
773
774 static int replace_exec(bContext *C, wmOperator *op)
775 {
776         SpaceImage *sima= CTX_wm_space_image(C);
777         char str[FILE_MAX];
778
779         if(!sima->image)
780                 return OPERATOR_CANCELLED;
781         
782         RNA_string_get(op->ptr, "filepath", str);
783         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
784
785         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
786         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
787
788         return OPERATOR_FINISHED;
789 }
790
791 static int replace_invoke(bContext *C, wmOperator *op, wmEvent *event)
792 {
793         SpaceImage *sima= CTX_wm_space_image(C);
794
795         if(!sima->image)
796                 return OPERATOR_CANCELLED;
797
798         if(RNA_property_is_set(op->ptr, "filepath"))
799                 return replace_exec(C, op);
800
801         if(!RNA_property_is_set(op->ptr, "relative_path"))
802                 RNA_boolean_set(op->ptr, "relative_path", (strncmp(sima->image->name, "//", 2))==0);
803
804         image_filesel(C, op, sima->image->name);
805
806         return OPERATOR_RUNNING_MODAL;
807 }
808
809 void IMAGE_OT_replace(wmOperatorType *ot)
810 {
811         /* identifiers */
812         ot->name= "Replace";
813         ot->idname= "IMAGE_OT_replace";
814         
815         /* api callbacks */
816         ot->exec= replace_exec;
817         ot->invoke= replace_invoke;
818         ot->poll= space_image_poll;
819
820         /* flags */
821         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
822
823         /* properties */
824         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
825 }
826
827 /******************** save image as operator ********************/
828
829 /* assumes name is FILE_MAX */
830 /* ima->name and ibuf->name should end up the same */
831 static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOperator *op, char *path)
832 {
833         Image *ima= ED_space_image(sima);
834         void *lock;
835         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
836
837         if (ibuf) {
838                 int relative= RNA_boolean_get(op->ptr, "relative_path");
839                 int save_copy= (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
840
841                 BLI_path_abs(path, G.sce);
842                 
843                 if(scene->r.scemode & R_EXTENSION)  {
844                         BKE_add_image_extension(path, sima->imtypenr);
845                 }
846                 
847                 /* enforce user setting for RGB or RGBA, but skip BW */
848                 if(scene->r.planes==32)
849                         ibuf->depth= 32;
850                 else if(scene->r.planes==24)
851                         ibuf->depth= 24;
852                 
853                 WM_cursor_wait(1);
854
855                 if(sima->imtypenr==R_MULTILAYER) {
856                         RenderResult *rr= BKE_image_acquire_renderresult(scene, ima);
857                         if(rr) {
858                                 RE_WriteRenderResult(rr, path, scene->r.quality);
859
860                                 if(relative)
861                                         BLI_path_rel(path, G.sce); /* only after saving */
862
863                                 if(!save_copy) {
864                                         BLI_strncpy(ima->name, path, sizeof(ima->name));
865                                         BLI_strncpy(ibuf->name, path, sizeof(ibuf->name));
866
867                                         /* should be function? nevertheless, saving only happens here */
868                                         for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
869                                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
870                                 }
871                         }
872                         else
873                                 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
874                         BKE_image_release_renderresult(scene, ima);
875                 }
876                 else if (BKE_write_ibuf(scene, ibuf, path, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
877
878                         if(relative)
879                                 BLI_path_rel(path, G.sce); /* only after saving */
880
881                         if(!save_copy) {
882
883                                 BLI_strncpy(ima->name, path, sizeof(ima->name));
884                                 BLI_strncpy(ibuf->name, path, sizeof(ibuf->name));
885
886                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
887
888                                 /* change type? */
889                                 if(ima->type==IMA_TYPE_R_RESULT) {
890                                         ima->type= IMA_TYPE_IMAGE;
891
892                                         /* workaround to ensure the render result buffer is no longer used
893                                          * by this image, otherwise can crash when a new render result is
894                                          * created. */
895                                         if(ibuf->rect && !(ibuf->mall & IB_rect))
896                                                 imb_freerectImBuf(ibuf);
897                                         if(ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
898                                                 imb_freerectfloatImBuf(ibuf);
899                                         if(ibuf->zbuf && !(ibuf->mall & IB_zbuf))
900                                                 IMB_freezbufImBuf(ibuf);
901                                         if(ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
902                                                 IMB_freezbuffloatImBuf(ibuf);
903                                 }
904                                 if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
905                                         ima->source= IMA_SRC_FILE;
906                                         ima->type= IMA_TYPE_IMAGE;
907                                 }
908
909                                 /* name image as how we saved it */
910                                 rename_id(&ima->id, BLI_path_basename(path));
911                         }
912                 } 
913                 else
914                         BKE_reportf(op->reports, RPT_ERROR, "Couldn't write image: %s", path);
915
916                 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
917
918                 WM_cursor_wait(0);
919         }
920
921         ED_space_image_release_buffer(sima, lock);
922 }
923
924 static int save_as_exec(bContext *C, wmOperator *op)
925 {
926         SpaceImage *sima= CTX_wm_space_image(C);
927         Scene *scene= CTX_data_scene(C);
928         Image *ima = ED_space_image(sima);
929         char str[FILE_MAX];
930
931         if(!ima)
932                 return OPERATOR_CANCELLED;
933
934         sima->imtypenr= RNA_enum_get(op->ptr, "file_type");
935         RNA_string_get(op->ptr, "filepath", str);
936
937         save_image_doit(C, sima, scene, op, str);
938
939         return OPERATOR_FINISHED;
940 }
941
942 static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
943 {
944         SpaceImage *sima= CTX_wm_space_image(C);
945         Image *ima = ED_space_image(sima);
946         Scene *scene= CTX_data_scene(C);
947         ImBuf *ibuf;
948         void *lock;
949
950         if(!RNA_property_is_set(op->ptr, "relative_path"))
951                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
952
953         if(RNA_property_is_set(op->ptr, "filepath"))
954                 return save_as_exec(C, op);
955         
956         if(!ima)
957                 return OPERATOR_CANCELLED;
958
959         /* always opens fileselect */
960         ibuf= ED_space_image_acquire_buffer(sima, &lock);
961
962         if(ibuf) {
963                 /* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
964                 if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
965                         sima->imtypenr= R_MULTILAYER;
966                 else if(ima->type==IMA_TYPE_R_RESULT)
967                         sima->imtypenr= scene->r.imtype;
968                 else if (ima->source == IMA_SRC_GENERATED)
969                         sima->imtypenr= R_PNG;
970                 else
971                         sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
972
973                 RNA_enum_set(op->ptr, "file_type", sima->imtypenr);
974                 
975                 if(ibuf->name[0]==0)
976                         BLI_strncpy(ibuf->name, G.ima, FILE_MAX);
977
978                 /* enable save_copy by default for render results */
979                 if(ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_property_is_set(op->ptr, "copy")) {
980                         RNA_boolean_set(op->ptr, "copy", TRUE);
981                 }
982
983                 // XXX note: we can give default menu enums to operator for this 
984                 image_filesel(C, op, ibuf->name);
985
986                 ED_space_image_release_buffer(sima, lock);
987                 
988                 return OPERATOR_RUNNING_MODAL;
989         }
990
991         ED_space_image_release_buffer(sima, lock);
992
993         return OPERATOR_CANCELLED;
994 }
995
996 void IMAGE_OT_save_as(wmOperatorType *ot)
997 {
998         /* identifiers */
999         ot->name= "Save As";
1000         ot->idname= "IMAGE_OT_save_as";
1001         
1002         /* api callbacks */
1003         ot->exec= save_as_exec;
1004         ot->invoke= save_as_invoke;
1005         ot->poll= space_image_buffer_exists_poll;
1006
1007         /* flags */
1008         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1009
1010         /* properties */
1011         RNA_def_enum(ot->srna, "file_type", image_file_type_items, R_PNG, "File Type", "File type to save image as.");
1012         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
1013
1014         RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
1015 }
1016
1017 /******************** save image operator ********************/
1018
1019 static int save_exec(bContext *C, wmOperator *op)
1020 {
1021         SpaceImage *sima= CTX_wm_space_image(C);
1022         Image *ima = ED_space_image(sima);
1023         void *lock;
1024         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
1025         Scene *scene= CTX_data_scene(C);
1026         RenderResult *rr;
1027         char name[FILE_MAX];
1028
1029         if(!ima || !ibuf) {
1030                 ED_space_image_release_buffer(sima, lock);
1031                 return OPERATOR_CANCELLED;
1032         }
1033
1034         /* if exists, saves over without fileselect */
1035         
1036         BLI_strncpy(name, ibuf->name, FILE_MAX);
1037         if(name[0]==0)
1038                 BLI_strncpy(name, G.ima, FILE_MAX);
1039         else
1040                 BLI_path_abs(name, G.sce);
1041         
1042         if(BLI_exists(name) && BLI_is_writable(name)) {
1043                 rr= BKE_image_acquire_renderresult(scene, ima);
1044
1045                 if(rr)
1046                         sima->imtypenr= R_MULTILAYER;
1047                 else 
1048                         sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
1049
1050                 BKE_image_release_renderresult(scene, ima);
1051                 ED_space_image_release_buffer(sima, lock);
1052                 
1053                 save_image_doit(C, sima, scene, op, name);
1054         }
1055         else {
1056                 ED_space_image_release_buffer(sima, lock);
1057
1058                 BKE_report(op->reports, RPT_ERROR, "Can not save image.");
1059                 return OPERATOR_CANCELLED;
1060         }
1061
1062         return OPERATOR_FINISHED;
1063 }
1064
1065 void IMAGE_OT_save(wmOperatorType *ot)
1066 {
1067         /* identifiers */
1068         ot->name= "Save";
1069         ot->idname= "IMAGE_OT_save";
1070         
1071         /* api callbacks */
1072         ot->exec= save_exec;
1073         ot->poll= space_image_file_exists_poll;
1074
1075         /* flags */
1076         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1077 }
1078
1079 /******************* save sequence operator ********************/
1080
1081 static int save_sequence_exec(bContext *C, wmOperator *op)
1082 {
1083         SpaceImage *sima= CTX_wm_space_image(C);
1084         ImBuf *ibuf;
1085         int tot= 0;
1086         char di[FILE_MAX], fi[FILE_MAX];
1087         
1088         if(sima->image==NULL)
1089                 return OPERATOR_CANCELLED;
1090
1091         if(sima->image->source!=IMA_SRC_SEQUENCE) {
1092                 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences.");
1093                 return OPERATOR_CANCELLED;
1094         }
1095
1096         if(sima->image->type==IMA_TYPE_MULTILAYER) {
1097                 BKE_report(op->reports, RPT_ERROR, "Can't save multilayer sequences.");
1098                 return OPERATOR_CANCELLED;
1099         }
1100         
1101         /* get total */
1102         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
1103                 if(ibuf->userflags & IB_BITMAPDIRTY)
1104                         tot++;
1105         
1106         if(tot==0) {
1107                 BKE_report(op->reports, RPT_WARNING, "No images have been changed.");
1108                 return OPERATOR_CANCELLED;
1109         }
1110
1111         /* get a filename for menu */
1112         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
1113                 if(ibuf->userflags & IB_BITMAPDIRTY)
1114                         break;
1115         
1116         BLI_strncpy(di, ibuf->name, FILE_MAX);
1117         BLI_splitdirstring(di, fi);
1118         
1119         BKE_reportf(op->reports, RPT_INFO, "%d Image(s) will be saved in %s", tot, di);
1120
1121         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
1122                 if(ibuf->userflags & IB_BITMAPDIRTY) {
1123                         char name[FILE_MAX];
1124                         BLI_strncpy(name, ibuf->name, sizeof(name));
1125                         
1126                         BLI_path_abs(name, G.sce);
1127
1128                         if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
1129                                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s.", name);
1130                                 break;
1131                         }
1132
1133                         BKE_reportf(op->reports, RPT_INFO, "Saved: %s\n", ibuf->name);
1134                         ibuf->userflags &= ~IB_BITMAPDIRTY;
1135                 }
1136         }
1137
1138         return OPERATOR_FINISHED;
1139 }
1140
1141 void IMAGE_OT_save_sequence(wmOperatorType *ot)
1142 {
1143         /* identifiers */
1144         ot->name= "Save Sequence";
1145         ot->idname= "IMAGE_OT_save_sequence";
1146         
1147         /* api callbacks */
1148         ot->exec= save_sequence_exec;
1149         ot->poll= space_image_buffer_exists_poll;
1150
1151         /* flags */
1152         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1153 }
1154
1155 /******************** reload image operator ********************/
1156
1157 static int reload_exec(bContext *C, wmOperator *op)
1158 {
1159         Image *ima= CTX_data_edit_image(C);
1160         SpaceImage *sima= CTX_wm_space_image(C);
1161
1162         if(!ima)
1163                 return OPERATOR_CANCELLED;
1164
1165         // XXX other users?
1166         BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD);
1167
1168         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
1169         
1170         return OPERATOR_FINISHED;
1171 }
1172
1173 void IMAGE_OT_reload(wmOperatorType *ot)
1174 {
1175         /* identifiers */
1176         ot->name= "Reload";
1177         ot->idname= "IMAGE_OT_reload";
1178         
1179         /* api callbacks */
1180         ot->exec= reload_exec;
1181
1182         /* flags */
1183         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1184 }
1185
1186 /********************** new image operator *********************/
1187
1188 static int new_exec(bContext *C, wmOperator *op)
1189 {
1190         SpaceImage *sima;
1191         Scene *scene;
1192         Object *obedit;
1193         Image *ima;
1194         PointerRNA ptr, idptr;
1195         PropertyRNA *prop;
1196         char name[22];
1197         float color[4];
1198         int width, height, floatbuf, uvtestgrid, alpha;
1199
1200         /* retrieve state */
1201         sima= CTX_wm_space_image(C);
1202         scene= (Scene*)CTX_data_scene(C);
1203         obedit= CTX_data_edit_object(C);
1204
1205         RNA_string_get(op->ptr, "name", name);
1206         width= RNA_int_get(op->ptr, "width");
1207         height= RNA_int_get(op->ptr, "height");
1208         floatbuf= RNA_boolean_get(op->ptr, "float");
1209         uvtestgrid= RNA_boolean_get(op->ptr, "uv_test_grid");
1210         RNA_float_get_array(op->ptr, "color", color);
1211         alpha= RNA_boolean_get(op->ptr, "alpha");
1212         
1213         if (!floatbuf && scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
1214                 linearrgb_to_srgb_v3_v3(color, color);
1215
1216         if(!alpha)
1217                 color[3]= 1.0f;
1218
1219         ima = BKE_add_image_size(width, height, name, alpha ? 32 : 24, floatbuf, uvtestgrid, color);
1220
1221         if(!ima)
1222                 return OPERATOR_CANCELLED;
1223
1224         /* hook into UI */
1225         uiIDContextProperty(C, &ptr, &prop);
1226
1227         if(prop) {
1228                 /* when creating new ID blocks, use is already 1, but RNA
1229                  * pointer se also increases user, so this compensates it */
1230                 ima->id.us--;
1231
1232                 RNA_id_pointer_create(&ima->id, &idptr);
1233                 RNA_property_pointer_set(&ptr, prop, idptr);
1234                 RNA_property_update(C, &ptr, prop);
1235         }
1236         else if(sima)
1237                 ED_space_image_set(C, sima, scene, obedit, ima);
1238
1239         // XXX other users?
1240         BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_USER_NEW_IMAGE);
1241         
1242         return OPERATOR_FINISHED;
1243 }
1244
1245 void IMAGE_OT_new(wmOperatorType *ot)
1246 {
1247         PropertyRNA *prop;
1248         static float default_color[4]= {0.0f, 0.0f, 0.0f, 1.0f};
1249         
1250         /* identifiers */
1251         ot->name= "New";
1252         ot->idname= "IMAGE_OT_new";
1253         
1254         /* api callbacks */
1255         ot->exec= new_exec;
1256         ot->invoke= WM_operator_props_popup;
1257
1258         /* flags */
1259         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1260
1261         /* properties */
1262         RNA_def_string(ot->srna, "name", "Untitled", 21, "Name", "Image datablock name.");
1263         RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width.", 1, 16384);
1264         RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height.", 1, 16384);
1265         prop= RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color.", 0.0f, 1.0f);
1266         RNA_def_property_float_array_default(prop, default_color);
1267         RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel.");
1268         RNA_def_boolean(ot->srna, "uv_test_grid", 0, "UV Test Grid", "Fill the image with a grid for UV map testing.");
1269         RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth.");
1270 }
1271
1272 /********************* pack operator *********************/
1273
1274 static int pack_test(bContext *C, wmOperator *op)
1275 {
1276         Image *ima= CTX_data_edit_image(C);
1277         int as_png= RNA_boolean_get(op->ptr, "as_png");
1278
1279         if(!ima)
1280                 return 0;
1281         if(!as_png && ima->packedfile)
1282                 return 0;
1283
1284         if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1285                 BKE_report(op->reports, RPT_ERROR, "Can't pack movie or image sequence.");
1286                 return 0;
1287         }
1288
1289         return 1;
1290 }
1291
1292 static int pack_exec(bContext *C, wmOperator *op)
1293 {
1294         Image *ima= CTX_data_edit_image(C);
1295         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
1296         int as_png= RNA_boolean_get(op->ptr, "as_png");
1297
1298         if(!pack_test(C, op))
1299                 return OPERATOR_CANCELLED;
1300         
1301         if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
1302                 BKE_report(op->reports, RPT_ERROR, "Can't pack edited image from disk, only as internal PNG.");
1303                 return OPERATOR_CANCELLED;
1304         }
1305
1306         if(as_png)
1307                 BKE_image_memorypack(ima);
1308         else
1309                 ima->packedfile= newPackedFile(op->reports, ima->name);
1310
1311         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
1312         
1313         return OPERATOR_FINISHED;
1314 }
1315
1316 static int pack_invoke(bContext *C, wmOperator *op, wmEvent *event)
1317 {
1318         Image *ima= CTX_data_edit_image(C);
1319         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
1320         uiPopupMenu *pup;
1321         uiLayout *layout;
1322         int as_png= RNA_boolean_get(op->ptr, "as_png");
1323
1324         if(!pack_test(C, op))
1325                 return OPERATOR_CANCELLED;
1326         
1327         if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
1328                 pup= uiPupMenuBegin(C, "OK", ICON_QUESTION);
1329                 layout= uiPupMenuLayout(pup);
1330                 uiItemBooleanO(layout, "Can't pack edited image from disk. Pack as internal PNG?", 0, op->idname, "as_png", 1);
1331                 uiPupMenuEnd(C, pup);
1332
1333                 return OPERATOR_CANCELLED;
1334         }
1335
1336         return pack_exec(C, op);
1337 }
1338
1339 void IMAGE_OT_pack(wmOperatorType *ot)
1340 {
1341         /* identifiers */
1342         ot->name= "Pack";
1343         ot->description= "Pack an image as embedded data into the .blend file"; 
1344         ot->idname= "IMAGE_OT_pack";
1345         
1346         /* api callbacks */
1347         ot->exec= pack_exec;
1348         ot->invoke= pack_invoke;
1349
1350         /* flags */
1351         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1352
1353         /* properties */
1354         RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG.");
1355 }
1356
1357 /********************* unpack operator *********************/
1358
1359 void unpack_menu(bContext *C, char *opname, Image *ima, char *folder, PackedFile *pf)
1360 {
1361         PointerRNA props_ptr;
1362         uiPopupMenu *pup;
1363         uiLayout *layout;
1364         char line[FILE_MAXDIR + FILE_MAXFILE + 100];
1365         char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
1366         char *abs_name = ima->name;
1367         
1368         strcpy(local_name, abs_name);
1369         BLI_splitdirstring(local_name, fi);
1370         sprintf(local_name, "//%s/%s", folder, fi);
1371
1372         pup= uiPupMenuBegin(C, "Unpack file", 0);
1373         layout= uiPupMenuLayout(pup);
1374
1375         uiItemEnumO(layout, opname, "Remove Pack", 0, "method", PF_REMOVE);
1376
1377         if(strcmp(abs_name, local_name)) {
1378                 switch(checkPackedFile(local_name, pf)) {
1379                         case PF_NOFILE:
1380                                 sprintf(line, "Create %s", local_name);
1381                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1382                                 RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
1383                                 RNA_string_set(&props_ptr, "image", ima->id.name+2);
1384         
1385                                 break;
1386                         case PF_EQUAL:
1387                                 sprintf(line, "Use %s (identical)", local_name);
1388                                 //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
1389                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1390                                 RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
1391                                 RNA_string_set(&props_ptr, "image", ima->id.name+2);
1392                                 
1393                                 break;
1394                         case PF_DIFFERS:
1395                                 sprintf(line, "Use %s (differs)", local_name);
1396                                 //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
1397                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1398                                 RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
1399                                 RNA_string_set(&props_ptr, "image", ima->id.name);
1400                                 
1401                                 sprintf(line, "Overwrite %s", local_name);
1402                                 //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_LOCAL);
1403                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1404                                 RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
1405                                 RNA_string_set(&props_ptr, "image", ima->id.name+2);
1406                                 
1407                                 
1408                                 break;
1409                 }
1410         }
1411         
1412         switch(checkPackedFile(abs_name, pf)) {
1413                 case PF_NOFILE:
1414                         sprintf(line, "Create %s", abs_name);
1415                         //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
1416                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1417                         RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
1418                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1419                         break;
1420                 case PF_EQUAL:
1421                         sprintf(line, "Use %s (identical)", abs_name);
1422                         //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
1423                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1424                         RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
1425                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1426                         break;
1427                 case PF_DIFFERS:
1428                         sprintf(line, "Use %s (differs)", local_name);
1429                         //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
1430                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1431                         RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
1432                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1433                         
1434                         sprintf(line, "Overwrite %s", local_name);
1435                         //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
1436                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1437                         RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
1438                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1439                         break;
1440         }
1441
1442         uiPupMenuEnd(C, pup);
1443 }
1444
1445 static int unpack_exec(bContext *C, wmOperator *op)
1446 {
1447         Image *ima= CTX_data_edit_image(C);
1448         int method= RNA_enum_get(op->ptr, "method");
1449
1450         /* find the suppplied image by name */
1451         if (RNA_property_is_set(op->ptr, "image")) {
1452                 char imaname[22];
1453                 RNA_string_get(op->ptr, "image", imaname);
1454                 ima = BLI_findstring(&CTX_data_main(C)->image, imaname, offsetof(ID, name) + 2);
1455                 if (!ima) ima = CTX_data_edit_image(C);
1456         }
1457         
1458         if(!ima || !ima->packedfile)
1459                 return OPERATOR_CANCELLED;
1460
1461         if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1462                 BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
1463                 return OPERATOR_CANCELLED;
1464         }
1465
1466         if(G.fileflags & G_AUTOPACK)
1467                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
1468                 
1469         unpackImage(op->reports, ima, method);
1470         
1471         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
1472
1473         return OPERATOR_FINISHED;
1474 }
1475
1476 static int unpack_invoke(bContext *C, wmOperator *op, wmEvent *event)
1477 {
1478         Image *ima= CTX_data_edit_image(C);
1479
1480         if(RNA_property_is_set(op->ptr, "image"))
1481                 return unpack_exec(C, op);
1482                 
1483         if(!ima || !ima->packedfile)
1484                 return OPERATOR_CANCELLED;
1485
1486         if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1487                 BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
1488                 return OPERATOR_CANCELLED;
1489         }
1490
1491         if(G.fileflags & G_AUTOPACK)
1492                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
1493         
1494         unpack_menu(C, "IMAGE_OT_unpack", ima, "textures", ima->packedfile);
1495
1496         return OPERATOR_FINISHED;
1497 }
1498
1499 void IMAGE_OT_unpack(wmOperatorType *ot)
1500 {
1501         /* identifiers */
1502         ot->name= "Unpack";
1503         ot->description= "Save an image packed in the .blend file to disk"; 
1504         ot->idname= "IMAGE_OT_unpack";
1505         
1506         /* api callbacks */
1507         ot->exec= unpack_exec;
1508         ot->invoke= unpack_invoke;
1509
1510         /* flags */
1511         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1512
1513         /* properties */
1514         RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack.");
1515         RNA_def_string(ot->srna, "image", "", 21, "Image Name", "Image datablock name to unpack.");
1516 }
1517
1518 /******************** sample image operator ********************/
1519
1520 typedef struct ImageSampleInfo {
1521         ARegionType *art;
1522         void *draw_handle;
1523         int x, y;
1524         int channels;
1525
1526         char col[4];
1527         float colf[4];
1528         int z;
1529         float zf;
1530
1531         char *colp;
1532         float *colfp;
1533         int *zp;
1534         float *zfp;
1535
1536         int draw;
1537 } ImageSampleInfo;
1538
1539 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
1540 {
1541         ImageSampleInfo *info= arg_info;
1542
1543         draw_image_info(ar, info->channels, info->x, info->y, info->colp,
1544                 info->colfp, info->zp, info->zfp);
1545 }
1546
1547 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
1548 {
1549         SpaceImage *sima= CTX_wm_space_image(C);
1550         ARegion *ar= CTX_wm_region(C);
1551         void *lock;
1552         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
1553         ImageSampleInfo *info= op->customdata;
1554         float fx, fy;
1555         int x, y;
1556         
1557         if(ibuf == NULL) {
1558                 ED_space_image_release_buffer(sima, lock);
1559                 return;
1560         }
1561
1562         x= event->x - ar->winrct.xmin;
1563         y= event->y - ar->winrct.ymin;
1564         UI_view2d_region_to_view(&ar->v2d, x, y, &fx, &fy);
1565
1566         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1567                 float *fp;
1568                 char *cp;
1569                 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y);
1570
1571                 CLAMP(x, 0, ibuf->x-1);
1572                 CLAMP(y, 0, ibuf->y-1);
1573
1574                 info->x= x;
1575                 info->y= y;
1576                 info->draw= 1;
1577                 info->channels= ibuf->channels;
1578
1579                 info->colp= NULL;
1580                 info->colfp= NULL;
1581                 info->zp= NULL;
1582                 info->zfp= NULL;
1583                 
1584                 if(ibuf->rect) {
1585                         cp= (char *)(ibuf->rect + y*ibuf->x + x);
1586
1587                         info->col[0]= cp[0];
1588                         info->col[1]= cp[1];
1589                         info->col[2]= cp[2];
1590                         info->col[3]= cp[3];
1591                         info->colp= info->col;
1592
1593                         info->colf[0]= (float)cp[0]/255.0f;
1594                         info->colf[1]= (float)cp[1]/255.0f;
1595                         info->colf[2]= (float)cp[2]/255.0f;
1596                         info->colf[3]= (float)cp[3]/255.0f;
1597                         info->colfp= info->colf;
1598                 }
1599                 if(ibuf->rect_float) {
1600                         fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1601
1602                         info->colf[0]= fp[0];
1603                         info->colf[1]= fp[1];
1604                         info->colf[2]= fp[2];
1605                         info->colf[3]= fp[3];
1606                         info->colfp= info->colf;
1607                 }
1608
1609                 if(ibuf->zbuf) {
1610                         info->z= ibuf->zbuf[y*ibuf->x + x];
1611                         info->zp= &info->z;
1612                 }
1613                 if(ibuf->zbuf_float) {
1614                         info->zf= ibuf->zbuf_float[y*ibuf->x + x];
1615                         info->zfp= &info->zf;
1616                 }
1617                 
1618                 if(sima->cumap && ibuf->channels==4) {
1619                         /* we reuse this callback for set curves point operators */
1620                         if(RNA_struct_find_property(op->ptr, "point")) {
1621                                 int point= RNA_enum_get(op->ptr, "point");
1622
1623                                 if(point == 1) {
1624                                         curvemapping_set_black_white(sima->cumap, NULL, info->colfp);
1625                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1626                                 }
1627                                 else if(point == 0) {
1628                                         curvemapping_set_black_white(sima->cumap, info->colfp, NULL);
1629                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1630                                 }
1631                         }
1632                 }
1633                                 
1634                 // XXX node curve integration ..
1635 #if 0
1636                 {
1637                         ScrArea *sa, *cur= curarea;
1638                         
1639                         node_curvemap_sample(fp);       /* sends global to node editor */
1640                         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1641                                 if(sa->spacetype==SPACE_NODE) {
1642                                         areawinset(sa->win);
1643                                         scrarea_do_windraw(sa);
1644                                 }
1645                         }
1646                         node_curvemap_sample(NULL);             /* clears global in node editor */
1647                         curarea= cur;
1648                 }
1649 #endif
1650         }
1651         else
1652                 info->draw= 0;
1653
1654         ED_space_image_release_buffer(sima, lock);
1655         ED_area_tag_redraw(CTX_wm_area(C));
1656 }
1657
1658 static void sample_exit(bContext *C, wmOperator *op)
1659 {
1660         ImageSampleInfo *info= op->customdata;
1661
1662         ED_region_draw_cb_exit(info->art, info->draw_handle);
1663         ED_area_tag_redraw(CTX_wm_area(C));
1664         MEM_freeN(info);
1665 }
1666
1667 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
1668 {
1669         SpaceImage *sima= CTX_wm_space_image(C);
1670         ARegion *ar= CTX_wm_region(C);
1671         ImageSampleInfo *info;
1672
1673         if(!ED_space_image_has_buffer(sima))
1674                 return OPERATOR_CANCELLED;
1675         
1676         info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
1677         info->art= ar->type;
1678         info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
1679         op->customdata= info;
1680
1681         sample_apply(C, op, event);
1682
1683         WM_event_add_modal_handler(C, op);
1684
1685         return OPERATOR_RUNNING_MODAL;
1686 }
1687
1688 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
1689 {
1690         switch(event->type) {
1691                 case LEFTMOUSE:
1692                 case RIGHTMOUSE: // XXX hardcoded
1693                         sample_exit(C, op);
1694                         return OPERATOR_CANCELLED;
1695                 case MOUSEMOVE:
1696                         sample_apply(C, op, event);
1697                         break;
1698         }
1699
1700         return OPERATOR_RUNNING_MODAL;
1701 }
1702
1703 static int sample_cancel(bContext *C, wmOperator *op)
1704 {
1705         sample_exit(C, op);
1706         return OPERATOR_CANCELLED;
1707 }
1708
1709 void IMAGE_OT_sample(wmOperatorType *ot)
1710 {
1711         /* identifiers */
1712         ot->name= "Sample";
1713         ot->idname= "IMAGE_OT_sample";
1714         
1715         /* api callbacks */
1716         ot->invoke= sample_invoke;
1717         ot->modal= sample_modal;
1718         ot->cancel= sample_cancel;
1719         ot->poll= space_image_main_area_poll;
1720
1721         /* flags */
1722         ot->flag= OPTYPE_BLOCKING;
1723 }
1724
1725 /******************** sample line operator ********************/
1726 static int sample_line_exec(bContext *C, wmOperator *op)
1727 {
1728         SpaceImage *sima= CTX_wm_space_image(C);
1729         ARegion *ar= CTX_wm_region(C);
1730         Scene *scene= CTX_data_scene(C);
1731         
1732         int x_start= RNA_int_get(op->ptr, "xstart");
1733         int y_start= RNA_int_get(op->ptr, "ystart");
1734         int x_end= RNA_int_get(op->ptr, "xend");
1735         int y_end= RNA_int_get(op->ptr, "yend");
1736         
1737         void *lock;
1738         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
1739         Histogram *hist= &sima->sample_line_hist;
1740         
1741         float x1f, y1f, x2f, y2f;
1742         int x1, y1, x2, y2;
1743         int i, x, y;
1744         float *fp;
1745         float rgb[3];
1746         unsigned char *cp;
1747         
1748         if (ibuf == NULL) {
1749                 ED_space_image_release_buffer(sima, lock);
1750                 return OPERATOR_CANCELLED;
1751         }
1752         /* hmmmm */
1753         if (ibuf->channels < 3) {
1754                 ED_space_image_release_buffer(sima, lock);
1755                 return OPERATOR_CANCELLED;
1756         }
1757         
1758         UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
1759         UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
1760         x1= 0.5f+ x1f*ibuf->x;
1761         x2= 0.5f+ x2f*ibuf->x;
1762         y1= 0.5f+ y1f*ibuf->y;
1763         y2= 0.5f+ y2f*ibuf->y;
1764         
1765         hist->channels = 3;
1766         hist->x_resolution = 256;
1767         hist->xmax = 1.0f;
1768         hist->ymax = 1.0f;
1769         
1770         for (i=0; i<256; i++) {
1771                 x= (int)(0.5f + x1 + (float)i*(x2-x1)/255.0f);
1772                 y= (int)(0.5f + y1 + (float)i*(y2-y1)/255.0f);
1773                 
1774                 if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
1775                         hist->data_luma[i] = hist->data_r[i] = hist->data_g[i]= hist->data_b[i] = 0.0f;
1776                 } else {
1777                         if (ibuf->rect_float) {
1778                                 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1779
1780                                 if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
1781                                         linearrgb_to_srgb_v3_v3(rgb, fp);
1782                                 else
1783                                         copy_v3_v3(rgb, fp);
1784
1785                                 hist->data_r[i] = rgb[0];
1786                                 hist->data_g[i] = rgb[1];
1787                                 hist->data_b[i] = rgb[2];
1788                                 hist->data_luma[i] = (0.299f*rgb[0] + 0.587f*rgb[1] + 0.114f*rgb[2]);
1789                         }
1790                         else if (ibuf->rect) {
1791                                 cp= (unsigned char *)(ibuf->rect + y*ibuf->x + x);
1792                                 hist->data_r[i] = (float)cp[0]/255.0f;
1793                                 hist->data_g[i] = (float)cp[1]/255.0f;
1794                                 hist->data_b[i] = (float)cp[2]/255.0f;
1795                                 hist->data_luma[i] = (0.299f*cp[0] + 0.587f*cp[1] + 0.114f*cp[2])/255;
1796                         }
1797                 }
1798         }
1799         
1800         ED_space_image_release_buffer(sima, lock);
1801         
1802         ED_area_tag_redraw(CTX_wm_area(C));
1803         
1804         return OPERATOR_FINISHED;
1805 }
1806
1807 static int sample_line_invoke(bContext *C, wmOperator *op, wmEvent *event)
1808 {
1809         SpaceImage *sima= CTX_wm_space_image(C);
1810         
1811         if(!ED_space_image_has_buffer(sima))
1812                 return OPERATOR_CANCELLED;
1813         
1814         return WM_gesture_straightline_invoke(C, op, event);
1815 }
1816
1817 void IMAGE_OT_sample_line(wmOperatorType *ot)
1818 {
1819         /* identifiers */
1820         ot->name= "Sample Line";
1821         ot->idname= "IMAGE_OT_sample_line";
1822         
1823         /* api callbacks */
1824         ot->invoke= sample_line_invoke;
1825         ot->modal= WM_gesture_straightline_modal;
1826         ot->exec= sample_line_exec;
1827         ot->poll= space_image_main_area_poll;
1828         
1829         /* flags */
1830         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1831         
1832         WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
1833 }
1834
1835 /******************** set curve point operator ********************/
1836
1837 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
1838 {
1839         static EnumPropertyItem point_items[]= {
1840                 {0, "BLACK_POINT", 0, "Black Point", ""},
1841                 {1, "WHITE_POINT", 0, "White Point", ""},
1842                 {0, NULL, 0, NULL, NULL}};
1843
1844         /* identifiers */
1845         ot->name= "Set Curves Point";
1846         ot->idname= "IMAGE_OT_curves_point_set";
1847
1848         /* flags */
1849         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1850         
1851         /* api callbacks */
1852         ot->invoke= sample_invoke;
1853         ot->modal= sample_modal;
1854         ot->cancel= sample_cancel;
1855         ot->poll= space_image_main_area_poll;
1856
1857         /* properties */
1858         RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves.");
1859 }
1860
1861 /******************** record composite operator *********************/
1862
1863 typedef struct RecordCompositeData {
1864         wmTimer *timer;
1865         int old_cfra;
1866         int sfra, efra;
1867 } RecordCompositeData;
1868
1869 int record_composite_apply(bContext *C, wmOperator *op)
1870 {
1871         SpaceImage *sima= CTX_wm_space_image(C);
1872         RecordCompositeData *rcd= op->customdata;
1873         Scene *scene= CTX_data_scene(C);
1874         ImBuf *ibuf;
1875         
1876         WM_timecursor(CTX_wm_window(C), scene->r.cfra);
1877
1878         // XXX scene->nodetree->test_break= blender_test_break;
1879         // XXX scene->nodetree->test_break= NULL;
1880         
1881         BKE_image_all_free_anim_ibufs(scene->r.cfra);
1882         ntreeCompositTagAnimated(scene->nodetree);
1883         ntreeCompositExecTree(scene->nodetree, &scene->r, scene->r.cfra != rcd->old_cfra);      /* 1 is no previews */
1884
1885         ED_area_tag_redraw(CTX_wm_area(C));
1886         
1887         ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1888         /* save memory in flipbooks */
1889         if(ibuf)
1890                 imb_freerectfloatImBuf(ibuf);
1891         
1892         scene->r.cfra++;
1893
1894         return (scene->r.cfra <= rcd->efra);
1895 }
1896
1897 static int record_composite_init(bContext *C, wmOperator *op)
1898 {
1899         SpaceImage *sima= CTX_wm_space_image(C);
1900         Scene *scene= CTX_data_scene(C);
1901         RecordCompositeData *rcd;
1902
1903         if(sima->iuser.frames < 2)
1904                 return 0;
1905         if(scene->nodetree == NULL)
1906                 return 0;
1907         
1908         op->customdata= rcd= MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData");
1909
1910         rcd->old_cfra= scene->r.cfra;
1911         rcd->sfra= sima->iuser.sfra;
1912         rcd->efra= sima->iuser.sfra + sima->iuser.frames-1;
1913         scene->r.cfra= rcd->sfra;
1914
1915         return 1;
1916 }
1917
1918 static void record_composite_exit(bContext *C, wmOperator *op)
1919 {
1920         Scene *scene= CTX_data_scene(C);
1921         SpaceImage *sima= CTX_wm_space_image(C);
1922         RecordCompositeData *rcd= op->customdata;
1923
1924         scene->r.cfra= rcd->old_cfra;
1925
1926         WM_cursor_restore(CTX_wm_window(C));
1927
1928         if(rcd->timer)
1929                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer);
1930
1931         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
1932
1933         // XXX play_anim(0);
1934         // XXX allqueue(REDRAWNODE, 1);
1935
1936         MEM_freeN(rcd);
1937 }
1938
1939 static int record_composite_exec(bContext *C, wmOperator *op)
1940 {
1941         if(!record_composite_init(C, op))
1942                 return OPERATOR_CANCELLED;
1943         
1944         while(record_composite_apply(C, op))
1945                 ;
1946         
1947         record_composite_exit(C, op);
1948         
1949         return OPERATOR_FINISHED;
1950 }
1951
1952 static int record_composite_invoke(bContext *C, wmOperator *op, wmEvent *event)
1953 {
1954         RecordCompositeData *rcd= op->customdata;
1955         
1956         if(!record_composite_init(C, op))
1957                 return OPERATOR_CANCELLED;
1958
1959         rcd= op->customdata;
1960         rcd->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f);
1961         WM_event_add_modal_handler(C, op);
1962
1963         if(!record_composite_apply(C, op))
1964                 return OPERATOR_FINISHED;
1965
1966         return OPERATOR_RUNNING_MODAL;
1967 }
1968
1969 static int record_composite_modal(bContext *C, wmOperator *op, wmEvent *event)
1970 {
1971         RecordCompositeData *rcd= op->customdata;
1972
1973         switch(event->type) {
1974                 case TIMER:
1975                         if(rcd->timer == event->customdata) {
1976                                 if(!record_composite_apply(C, op)) {
1977                                         record_composite_exit(C, op);
1978                                         return OPERATOR_FINISHED;
1979                                 }
1980                         }
1981                         break;
1982                 case ESCKEY:
1983                         record_composite_exit(C, op);
1984                         return OPERATOR_FINISHED;
1985         }
1986
1987         return OPERATOR_RUNNING_MODAL;
1988 }
1989
1990 static int record_composite_cancel(bContext *C, wmOperator *op)
1991 {
1992         record_composite_exit(C, op);
1993         return OPERATOR_CANCELLED;
1994 }
1995
1996 void IMAGE_OT_record_composite(wmOperatorType *ot)
1997 {
1998         /* identifiers */
1999         ot->name= "Record Composite";
2000         ot->idname= "IMAGE_OT_record_composite";
2001         
2002         /* api callbacks */
2003         ot->exec= record_composite_exec;
2004         ot->invoke= record_composite_invoke;
2005         ot->modal= record_composite_modal;
2006         ot->cancel= record_composite_cancel;
2007         ot->poll= space_image_buffer_exists_poll;
2008 }
2009
2010 /********************* cycle render slot operator *********************/
2011
2012 static int cycle_render_slot_poll(bContext *C)
2013 {
2014         Image *ima= CTX_data_edit_image(C);
2015
2016         return (ima && ima->type == IMA_TYPE_R_RESULT);
2017 }
2018
2019 static int cycle_render_slot_exec(bContext *C, wmOperator *op)
2020 {
2021         Image *ima= CTX_data_edit_image(C);
2022         int a, slot, cur= ima->render_slot;
2023
2024         for(a=1; a<IMA_MAX_RENDER_SLOT; a++) {
2025                 slot= (cur+a)%IMA_MAX_RENDER_SLOT;
2026
2027                 if(ima->renders[slot] || slot == ima->last_render_slot) {
2028                         ima->render_slot= slot;
2029                         break;
2030                 }
2031         }
2032
2033         if(a == IMA_MAX_RENDER_SLOT)
2034                 ima->render_slot= ((cur == 1)? 0: 1);
2035         
2036         WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
2037
2038         return OPERATOR_FINISHED;
2039 }
2040
2041 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
2042 {
2043         /* identifiers */
2044         ot->name= "Cycle Render Slot";
2045         ot->idname= "IMAGE_OT_cycle_render_slot";
2046         
2047         /* api callbacks */
2048         ot->exec= cycle_render_slot_exec;
2049         ot->poll= cycle_render_slot_poll;
2050
2051         /* flags */
2052         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2053 }
2054
2055 /******************** TODO ********************/
2056
2057 /* XXX notifier? */
2058
2059 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
2060
2061 void ED_image_update_frame(const bContext *C)
2062 {
2063         Main *mainp= CTX_data_main(C);
2064         Scene *scene= CTX_data_scene(C);
2065         wmWindowManager *wm= CTX_wm_manager(C);
2066         wmWindow *win;
2067         Tex *tex;
2068         
2069         /* texture users */
2070         for(tex= mainp->tex.first; tex; tex= tex->id.next) {
2071                 if(tex->type==TEX_IMAGE && tex->ima) {
2072                         if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
2073                                 if(tex->iuser.flag & IMA_ANIM_ALWAYS)
2074                                         BKE_image_user_calc_frame(&tex->iuser, scene->r.cfra, 0);
2075                         }
2076                 }
2077         }
2078         
2079         /* image window, compo node users */
2080         if(wm) {
2081                 for(win= wm->windows.first; win; win= win->next) {
2082                         ScrArea *sa;
2083                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
2084                                 if(sa->spacetype==SPACE_VIEW3D) {
2085                                         View3D *v3d= sa->spacedata.first;
2086                                         BGpic *bgpic;
2087                                         for(bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next)
2088                                                 if(bgpic->iuser.flag & IMA_ANIM_ALWAYS)
2089                                                         BKE_image_user_calc_frame(&bgpic->iuser, scene->r.cfra, 0);
2090                                 }
2091                                 else if(sa->spacetype==SPACE_IMAGE) {
2092                                         SpaceImage *sima= sa->spacedata.first;
2093                                         if(sima->iuser.flag & IMA_ANIM_ALWAYS)
2094                                                 BKE_image_user_calc_frame(&sima->iuser, scene->r.cfra, 0);
2095                                 }
2096                                 else if(sa->spacetype==SPACE_NODE) {
2097                                         SpaceNode *snode= sa->spacedata.first;
2098                                         if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
2099                                                 bNode *node;
2100                                                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
2101                                                         if(node->id && node->type==CMP_NODE_IMAGE) {
2102                                                                 Image *ima= (Image *)node->id;
2103                                                                 ImageUser *iuser= node->storage;
2104                                                                 if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
2105                                                                         if(iuser->flag & IMA_ANIM_ALWAYS)
2106                                                                                 BKE_image_user_calc_frame(iuser, scene->r.cfra, 0);
2107                                                         }
2108                                                 }
2109                                         }
2110                                 }
2111                         }
2112                 }
2113         }
2114 }
2115