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