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