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