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