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