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