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