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