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