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