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