fix [#27285] Renderslot missing
[blender.git] / source / blender / editors / space_image / image_buttons.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/editors/space_image/image_buttons.c
29  *  \ingroup spimage
30  */
31
32
33
34 #include <string.h>
35 #include <stdio.h>
36
37 #include "DNA_meshdata_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_node_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_math.h"
46 #include "BLI_editVert.h"
47 #include "BLI_rand.h"
48 #include "BLI_utildefines.h"
49
50 #include "BKE_colortools.h"
51 #include "BKE_context.h"
52 #include "BKE_customdata.h"
53 #include "BKE_image.h"
54 #include "BKE_mesh.h"
55 #include "BKE_node.h"
56 #include "BKE_screen.h"
57
58 #include "RE_pipeline.h"
59
60 #include "IMB_imbuf.h"
61 #include "IMB_imbuf_types.h"
62
63 #include "ED_gpencil.h"
64 #include "ED_image.h"
65 #include "ED_screen.h"
66
67 #include "RNA_access.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71
72 #include "UI_interface.h"
73 #include "UI_resources.h"
74
75 #include "image_intern.h"
76
77 #define B_REDR                          1
78 #define B_IMAGECHANGED          2
79 #define B_NOP                           0
80 #define B_TWINANIM                      5
81 #define B_SIMAGETILE            6
82 #define B_IDNAME                        10
83 #define B_FACESEL_PAINT_TEST    11
84 #define B_SIMA_RECORD           12
85 #define B_SIMA_PLAY                     13
86
87 #define B_SIMANOTHING           16
88 #define B_SIMABRUSHCHANGE       17      
89 #define B_SIMABRUSHBROWSE       18
90 #define B_SIMABRUSHLOCAL        19
91 #define B_SIMABRUSHDELETE       20
92 #define B_KEEPDATA                      21
93 #define B_SIMABTEXBROWSE        22
94 #define B_SIMABTEXDELETE        23
95 #define B_VPCOLSLI                      24
96 #define B_SIMACLONEBROWSE       25
97 #define B_SIMACLONEDELETE       26
98
99 /* proto */
100
101 static void do_image_panel_events(bContext *C, void *UNUSED(arg), int event)
102 {
103         SpaceImage *sima= CTX_wm_space_image(C);
104         
105         switch(event) {
106                 case B_REDR:
107                         break;
108         }
109
110         /* all events now */
111         WM_event_add_notifier(C, NC_IMAGE, sima->image);
112 }
113
114 static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str)
115 {
116         int ofs= 0;
117
118         str[0]= 0;
119         
120         if(ima==NULL) return;
121
122         if(ibuf==NULL) {
123                 ofs+= sprintf(str, "Can't Load Image");
124         }
125         else {
126                 if(ima->source==IMA_SRC_MOVIE) {
127                         ofs+= sprintf(str, "Movie");
128                         if(ima->anim)
129                                 ofs+= sprintf(str+ofs, "%d frs", IMB_anim_get_duration(ima->anim));
130                 }
131                 else
132                         ofs+= sprintf(str, "Image");
133
134                 ofs+= sprintf(str+ofs, ": size %d x %d,", ibuf->x, ibuf->y);
135
136                 if(ibuf->rect_float) {
137                         if(ibuf->channels!=4) {
138                                 ofs+= sprintf(str+ofs, "%d float channel(s)", ibuf->channels);
139                         }
140                         else if(ibuf->depth==32)
141                                 ofs+= sprintf(str+ofs, " RGBA float");
142                         else
143                                 ofs+= sprintf(str+ofs, " RGB float");
144                 }
145                 else {
146                         if(ibuf->depth==32)
147                                 ofs+= sprintf(str+ofs, " RGBA byte");
148                         else
149                                 ofs+= sprintf(str+ofs, " RGB byte");
150                 }
151                 if(ibuf->zbuf || ibuf->zbuf_float)
152                         ofs+= sprintf(str+ofs, " + Z");
153
154                 if(ima->source==IMA_SRC_SEQUENCE) {
155                         char *file= BLI_last_slash(ibuf->name);
156                         if(file==NULL)  file= ibuf->name;
157                         else                    file++;
158                         ofs+= sprintf(str+ofs, ", %s", file);
159                 }
160         }
161
162         /* the frame number, even if we cant */
163         if(ima->source==IMA_SRC_SEQUENCE) {
164                 /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
165                 const int framenr= BKE_image_user_get_frame(iuser, CFRA, 0);
166                 ofs+= sprintf(str+ofs, ", Frame: %d", framenr);
167         }
168
169         (void)ofs;
170 }
171
172 /* gets active viewer user */
173 struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
174 {
175         bNode *node;
176         
177         if(ntree)
178                 for(node= ntree->nodes.first; node; node= node->next)
179                         if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
180                                 if(node->flag & NODE_DO_OUTPUT)
181                                         return node->storage;
182         return NULL;
183 }
184
185
186 /* ************ panel stuff ************* */
187
188 /* is used for both read and write... */
189
190 static int image_panel_poll(const bContext *C, PanelType *UNUSED(pt))
191 {
192         SpaceImage *sima= CTX_wm_space_image(C);
193         ImBuf *ibuf;
194         void *lock;
195         int result;
196
197         ibuf= ED_space_image_acquire_buffer(sima, &lock);
198         result= ibuf && ibuf->rect_float;
199         ED_space_image_release_buffer(sima, lock);
200         
201         return result;
202 }
203
204 static void image_panel_curves(const bContext *C, Panel *pa)
205 {
206         bScreen *sc= CTX_wm_screen(C);
207         SpaceImage *sima= CTX_wm_space_image(C);
208         ImBuf *ibuf;
209         PointerRNA simaptr;
210         int levels;
211         void *lock;
212         
213         ibuf= ED_space_image_acquire_buffer(sima, &lock);
214         
215         if(ibuf) {
216                 if(sima->cumap==NULL)
217                         sima->cumap= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
218
219                 /* curvemap black/white levels only works for RGBA */
220                 levels= (ibuf->channels==4);
221
222                 RNA_pointer_create(&sc->id, &RNA_SpaceImageEditor, sima, &simaptr);
223                 uiTemplateCurveMapping(pa->layout, &simaptr, "curve", 'c', levels, 0);
224         }
225
226         ED_space_image_release_buffer(sima, lock);
227 }
228
229 #if 0
230 /* 0: disable preview 
231    otherwise refresh preview
232  
233    XXX if you put this back, also check XXX in image_main_area_draw() */
234 */
235 void image_preview_event(int event)
236 {
237         int exec= 0;
238         
239         if(event==0) {
240                 G.scene->r.scemode &= ~R_COMP_CROP;
241                 exec= 1;
242         }
243         else {
244                 if(image_preview_active(curarea, NULL, NULL)) {
245                         G.scene->r.scemode |= R_COMP_CROP;
246                         exec= 1;
247                 }
248                 else
249                         G.scene->r.scemode &= ~R_COMP_CROP;
250         }
251         
252         if(exec && G.scene->nodetree) {
253                 /* should work when no node editor in screen..., so we execute right away */
254                 
255                 ntreeCompositTagGenerators(G.scene->nodetree);
256
257                 G.afbreek= 0;
258                 G.scene->nodetree->timecursor= set_timecursor;
259                 G.scene->nodetree->test_break= blender_test_break;
260                 
261                 BIF_store_spare();
262                 
263                 ntreeCompositExecTree(G.scene->nodetree, &G.scene->r, 1);       /* 1 is do_previews */
264                 
265                 G.scene->nodetree->timecursor= NULL;
266                 G.scene->nodetree->test_break= NULL;
267                 
268                 scrarea_do_windraw(curarea);
269                 waitcursor(0);
270                 
271                 WM_event_add_notifier(C, NC_IMAGE, ima_v);
272         }       
273 }
274
275
276 /* nothing drawn here, we use it to store values */
277 static void preview_cb(struct ScrArea *sa, struct uiBlock *block)
278 {
279         SpaceImage *sima= sa->spacedata.first;
280         rctf dispf;
281         rcti *disprect= &G.scene->r.disprect;
282         int winx= (G.scene->r.size*G.scene->r.xsch)/100;
283         int winy= (G.scene->r.size*G.scene->r.ysch)/100;
284         short mval[2];
285         
286         if(G.scene->r.mode & R_BORDER) {
287                 winx*= (G.scene->r.border.xmax - G.scene->r.border.xmin);
288                 winy*= (G.scene->r.border.ymax - G.scene->r.border.ymin);
289         }
290         
291         /* while dragging we need to update the rects, otherwise it doesn't end with correct one */
292
293         BLI_init_rctf(&dispf, 15.0f, (block->maxx - block->minx)-15.0f, 15.0f, (block->maxy - block->miny)-15.0f);
294         ui_graphics_to_window_rct(sa->win, &dispf, disprect);
295         
296         /* correction for gla draw */
297         BLI_translate_rcti(disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
298         
299         calc_image_view(sima, 'p');
300 //      printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax);
301         /* map to image space coordinates */
302         mval[0]= disprect->xmin; mval[1]= disprect->ymin;
303         areamouseco_to_ipoco(v2d, mval, &dispf.xmin, &dispf.ymin);
304         mval[0]= disprect->xmax; mval[1]= disprect->ymax;
305         areamouseco_to_ipoco(v2d, mval, &dispf.xmax, &dispf.ymax);
306         
307         /* map to render coordinates */
308         disprect->xmin= dispf.xmin;
309         disprect->xmax= dispf.xmax;
310         disprect->ymin= dispf.ymin;
311         disprect->ymax= dispf.ymax;
312         
313         CLAMP(disprect->xmin, 0, winx);
314         CLAMP(disprect->xmax, 0, winx);
315         CLAMP(disprect->ymin, 0, winy);
316         CLAMP(disprect->ymax, 0, winy);
317 //      printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax);
318
319 }
320
321 static int is_preview_allowed(ScrArea *cur)
322 {
323         SpaceImage *sima= cur->spacedata.first;
324         ScrArea *sa;
325
326         /* check if another areawindow has preview set */
327         for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
328                 if(sa!=cur && sa->spacetype==SPACE_IMAGE) {
329                         if(image_preview_active(sa, NULL, NULL))
330                                 return 0;
331                 }
332         }
333         /* check image type */
334         if(sima->image==NULL || sima->image->type!=IMA_TYPE_COMPOSITE)
335                 return 0;
336         
337         return 1;
338 }
339
340
341 static void image_panel_preview(ScrArea *sa, short cntrl)       // IMAGE_HANDLER_PREVIEW
342 {
343         uiBlock *block;
344         SpaceImage *sima= sa->spacedata.first;
345         int ofsx, ofsy;
346         
347         if(is_preview_allowed(sa)==0) {
348                 rem_blockhandler(sa, IMAGE_HANDLER_PREVIEW);
349                 G.scene->r.scemode &= ~R_COMP_CROP;     /* quite weak */
350                 return;
351         }
352         
353         block= uiBeginBlock(C, ar, "image_panel_preview", UI_EMBOSS);
354         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | UI_PNL_SCALE | cntrl);
355         uiSetPanelHandler(IMAGE_HANDLER_PREVIEW);  // for close and esc
356         
357         ofsx= -150+(sa->winx/2)/sima->blockscale;
358         ofsy= -100+(sa->winy/2)/sima->blockscale;
359         if(uiNewPanel(C, ar, block, "Preview", "Image", ofsx, ofsy, 300, 200)==0) return;
360         
361         uiBlockSetDrawExtraFunc(block, preview_cb);
362         
363 }
364 #endif
365
366
367 /* ********************* callbacks for standard image buttons *************** */
368
369 static char *slot_menu(void)
370 {
371         char *str;
372         int a, slot;
373         
374         str= MEM_callocN(IMA_MAX_RENDER_SLOT*32, "menu slots");
375         
376         strcpy(str, "Slot %t");
377         a= strlen(str);
378
379         for(slot=0; slot<IMA_MAX_RENDER_SLOT; slot++)
380                 a += sprintf(str+a, "|Slot %d %%x%d", slot+1, slot);
381         
382         return str;
383 }
384
385 /* TODO, curlay should be removed? */
386 static char *layer_menu(RenderResult *rr, short *UNUSED(curlay))
387 {
388         RenderLayer *rl;
389         int len= 64 + 32*BLI_countlist(&rr->layers);
390         short a, nr= 0;
391         char *str= MEM_callocN(len, "menu layers");
392         
393         strcpy(str, "Layer %t");
394         a= strlen(str);
395         
396         /* compo result */
397         if(rr->rectf) {
398                 a+= sprintf(str+a, "|Composite %%x0");
399                 nr= 1;
400         }
401         for(rl= rr->layers.first; rl; rl= rl->next, nr++) {
402                 a+= sprintf(str+a, "|%s %%x%d", rl->name, nr);
403         }
404         
405         /* no curlay clip here, on render (redraws) the amount of layers can be 1 fir single-layer render */
406         
407         return str;
408 }
409
410 /* rl==NULL means composite result */
411 static char *pass_menu(RenderLayer *rl, short *curpass)
412 {
413         RenderPass *rpass;
414         int len= 64 + 32*(rl?BLI_countlist(&rl->passes):1);
415         short a, nr= 0;
416         char *str= MEM_callocN(len, "menu layers");
417         
418         strcpy(str, "Pass %t");
419         a= strlen(str);
420         
421         /* rendered results don't have a Combined pass */
422         if(rl==NULL || rl->rectf) {
423                 a+= sprintf(str+a, "|Combined %%x0");
424                 nr= 1;
425         }
426         
427         if(rl)
428                 for(rpass= rl->passes.first; rpass; rpass= rpass->next, nr++)
429                         a+= sprintf(str+a, "|%s %%x%d", rpass->name, nr);
430         
431         if(*curpass >= nr)
432                 *curpass= 0;
433         
434         return str;
435 }
436
437 static void set_frames_cb(bContext *C, void *ima_v, void *iuser_v)
438 {
439         Scene *scene= CTX_data_scene(C);
440         Image *ima= ima_v;
441         ImageUser *iuser= iuser_v;
442         
443         if(ima->anim) {
444                 iuser->frames = IMB_anim_get_duration(ima->anim);
445                 BKE_image_user_calc_frame(iuser, scene->r.cfra, 0);
446         }
447 }
448
449 /* 5 layer button callbacks... */
450 static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v) 
451 {
452         ImageUser *iuser= iuser_v;
453
454         BKE_image_multilayer_index(rr_v, iuser); 
455         WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
456 }
457 static void image_multi_inclay_cb(bContext *C, void *rr_v, void *iuser_v) 
458 {
459         RenderResult *rr= rr_v;
460         ImageUser *iuser= iuser_v;
461         int tot= BLI_countlist(&rr->layers) + (rr->rectf?1:0);  /* fake compo result layer */
462
463         if(iuser->layer<tot-1) {
464                 iuser->layer++;
465                 BKE_image_multilayer_index(rr, iuser); 
466                 WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
467         }
468 }
469 static void image_multi_declay_cb(bContext *C, void *rr_v, void *iuser_v) 
470 {
471         ImageUser *iuser= iuser_v;
472
473         if(iuser->layer>0) {
474                 iuser->layer--;
475                 BKE_image_multilayer_index(rr_v, iuser); 
476                 WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
477         }
478 }
479 static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v) 
480 {
481         RenderResult *rr= rr_v;
482         ImageUser *iuser= iuser_v;
483         RenderLayer *rl= BLI_findlink(&rr->layers, iuser->layer);
484
485         if(rl) {
486                 int tot= BLI_countlist(&rl->passes) + (rl->rectf?1:0);  /* builtin render result has no combined pass in list */
487                 if(iuser->pass<tot-1) {
488                         iuser->pass++;
489                         BKE_image_multilayer_index(rr, iuser); 
490                         WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
491                 }
492         }
493 }
494 static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v) 
495 {
496         ImageUser *iuser= iuser_v;
497
498         if(iuser->pass>0) {
499                 iuser->pass--;
500                 BKE_image_multilayer_index(rr_v, iuser); 
501                 WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
502         }
503 }
504
505 #if 0
506 static void image_pack_cb(bContext *C, void *ima_v, void *iuser_v) 
507 {
508         if(ima_v) {
509                 Image *ima= ima_v;
510                 if(ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE) {
511                         if (ima->packedfile) {
512                                 if (G.fileflags & G_AUTOPACK) {
513                                         if (okee("Disable AutoPack ?")) {
514                                                 G.fileflags &= ~G_AUTOPACK;
515                                         }
516                                 }
517                                 
518                                 if ((G.fileflags & G_AUTOPACK) == 0) {
519                                         unpackImage(NULL, ima, PF_ASK); /* XXX report errors */
520                                         ED_undo_push(C, "Unpack image");
521                                 }
522                         } 
523                         else {
524                                 ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser_v);
525                                 if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
526                                         // XXX error("Can't pack painted image. Save image or use Repack as PNG.");
527                                 } else {
528                                         ima->packedfile = newPackedFile(NULL, ima->name); /* XXX report errors */
529                                         ED_undo_push(C, "Pack image");
530                                 }
531                         }
532                 }
533         }
534 }
535 #endif
536
537 #if 0
538 static void image_freecache_cb(bContext *C, void *ima_v, void *unused) 
539 {
540         Scene *scene= CTX_data_scene(C);
541         BKE_image_free_anim_ibufs(ima_v, scene->r.cfra);
542         WM_event_add_notifier(C, NC_IMAGE, ima_v);
543 }
544 #endif
545
546 #if 0
547 static void image_user_change(bContext *C, void *iuser_v, void *unused)
548 {
549         Scene *scene= CTX_data_scene(C);
550         BKE_image_user_calc_imanr(iuser_v, scene->r.cfra, 0);
551 }
552 #endif
553
554 static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
555 {
556         uiBlock *block= uiLayoutGetBlock(layout);
557         uiBut *but;
558         RenderLayer *rl= NULL;
559         int wmenu1, wmenu2, wmenu3;
560         char *strp;
561
562         uiLayoutRow(layout, 1);
563
564         /* layer menu is 1/3 larger than pass */
565         wmenu1= (2*w)/5;
566         wmenu2= (3*w)/5;
567         wmenu3= (3*w)/6;
568         
569         /* menu buts */
570         if(render_slot) {
571                 strp= slot_menu();
572                 but= uiDefButS(block, MENU, 0, strp,                                    0, 0, wmenu1, 20, render_slot, 0,0,0,0, "Select Slot");
573                 uiButSetFunc(but, image_multi_cb, rr, iuser);
574                 MEM_freeN(strp);
575         }
576
577         if(rr) {
578                 strp= layer_menu(rr, &iuser->layer);
579                 but= uiDefButS(block, MENU, 0, strp,                                    0, 0, wmenu2, 20, &iuser->layer, 0,0,0,0, "Select Layer");
580                 uiButSetFunc(but, image_multi_cb, rr, iuser);
581                 MEM_freeN(strp);
582                 
583                 rl= BLI_findlink(&rr->layers, iuser->layer - (rr->rectf?1:0)); /* fake compo layer, return NULL is meant to be */
584                 strp= pass_menu(rl, &iuser->pass);
585                 but= uiDefButS(block, MENU, 0, strp,                                    0, 0, wmenu3, 20, &iuser->pass, 0,0,0,0, "Select Pass");
586                 uiButSetFunc(but, image_multi_cb, rr, iuser);
587                 MEM_freeN(strp);        
588         }
589 }
590
591 static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, short *render_slot)
592 {
593         uiBlock *block= uiLayoutGetBlock(layout);
594         uiLayout *row;
595         uiBut *but;
596         const float dpi_fac= UI_DPI_FAC;
597         
598         row= uiLayoutRow(layout, 1);
599
600         if(rr==NULL || iuser==NULL)
601                 return;
602         if(rr->layers.first==NULL) {
603                 uiItemL(row, "No Layers in Render Result.", ICON_NONE);
604                 return;
605         }
606
607         /* decrease, increase arrows */
608         but= uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT,        0,0,17,20, NULL, 0, 0, 0, 0, "Previous Layer");
609         uiButSetFunc(but, image_multi_declay_cb, rr, iuser);
610         but= uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT,       0,0,18,20, NULL, 0, 0, 0, 0, "Next Layer");
611         uiButSetFunc(but, image_multi_inclay_cb, rr, iuser);
612
613         uiblock_layer_pass_buttons(row, rr, iuser, 230 * dpi_fac, render_slot);
614
615         /* decrease, increase arrows */
616         but= uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT,        0,0,17,20, NULL, 0, 0, 0, 0, "Previous Pass");
617         uiButSetFunc(but, image_multi_decpass_cb, rr, iuser);
618         but= uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT,       0,0,18,20, NULL, 0, 0, 0, 0, "Next Pass");
619         uiButSetFunc(but, image_multi_incpass_cb, rr, iuser);
620
621         uiBlockEndAlign(block);
622 }
623
624 // XXX HACK!
625 // static int packdummy=0;
626
627 typedef struct RNAUpdateCb {
628         PointerRNA ptr;
629         PropertyRNA *prop;
630         ImageUser *iuser;
631 } RNAUpdateCb;
632
633 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
634 {
635         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
636
637         /* ideally this would be done by RNA itself, but there we have
638            no image user available, so we just update this flag here */
639         cb->iuser->ok= 1;
640
641         /* we call update here on the pointer property, this way the
642            owner of the image pointer can still define it's own update
643            and notifier */
644         RNA_property_update(C, &cb->ptr, cb->prop);
645 }
646
647 void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact)
648 {
649         PropertyRNA *prop;
650         PointerRNA imaptr;
651         RNAUpdateCb *cb;
652         Image *ima;
653         ImageUser *iuser;
654         ImBuf *ibuf;
655         Scene *scene= CTX_data_scene(C);
656         uiLayout *row, *split, *col;
657         uiBlock *block;
658         uiBut *but;
659         char str[128];
660         void *lock;
661
662         if(!ptr->data)
663                 return;
664
665         prop= RNA_struct_find_property(ptr, propname);
666         if(!prop) {
667                 printf("uiTemplateImage: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
668                 return;
669         }
670
671         if(RNA_property_type(prop) != PROP_POINTER) {
672                 printf("uiTemplateImage: expected pointer property for %s.%s\n", RNA_struct_identifier(ptr->type), propname);
673                 return;
674         }
675
676         block= uiLayoutGetBlock(layout);
677
678
679         imaptr= RNA_property_pointer_get(ptr, prop);
680         ima= imaptr.data;
681         iuser= userptr->data;
682
683         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
684         cb->ptr= *ptr;
685         cb->prop= prop;
686         cb->iuser= iuser;
687
688         uiLayoutSetContextPointer(layout, "edit_image", &imaptr);
689
690         if(!compact)
691                 uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL);
692
693         // XXX missing: reload, pack
694
695         if(ima) {
696                 uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
697
698                 if(ima->source == IMA_SRC_VIEWER) {
699                         ibuf= BKE_image_acquire_ibuf(ima, iuser, &lock);
700                         image_info(scene, iuser, ima, ibuf, str);
701                         BKE_image_release_ibuf(ima, lock);
702
703                         uiItemL(layout, ima->id.name+2, ICON_NONE);
704                         uiItemL(layout, str, ICON_NONE);
705
706                         if(ima->type==IMA_TYPE_COMPOSITE) {
707                                 // XXX not working yet
708 #if 0
709                                 iuser= ntree_get_active_iuser(scene->nodetree);
710                                 if(iuser) {
711                                         uiBlockBeginAlign(block);
712                                         uiDefIconTextBut(block, BUT, B_SIMA_RECORD, ICON_REC, "Record", 10,120,100,20, 0, 0, 0, 0, 0, "");
713                                         uiDefIconTextBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, "Play",    110,120,100,20, 0, 0, 0, 0, 0, "");
714                                         but= uiDefBut(block, BUT, B_NOP, "Free Cache",  210,120,100,20, 0, 0, 0, 0, 0, "");
715                                         uiButSetFunc(but, image_freecache_cb, ima, NULL);
716                                         
717                                         if(iuser->frames)
718                                                 sprintf(str, "(%d) Frames:", iuser->framenr);
719                                         else strcpy(str, "Frames:");
720                                         uiBlockBeginAlign(block);
721                                         uiDefButI(block, NUM, imagechanged, str,                10, 90,150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use");
722                                         uiDefButI(block, NUM, imagechanged, "StartFr:", 160,90,150,20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Sets the global starting frame of the movie");
723                                 }
724 #endif
725                         }
726                         else if(ima->type==IMA_TYPE_R_RESULT) {
727                                 /* browse layer/passes */
728                                 Render *re= RE_GetRender(scene->id.name);
729                                 RenderResult *rr= RE_AcquireResultRead(re);
730                                 uiblock_layer_pass_arrow_buttons(layout, rr, iuser, &ima->render_slot);
731                                 RE_ReleaseResult(re);
732                         }
733                 }
734                 else {
735                         row= uiLayoutRow(layout, 0);
736                         uiItemR(row, &imaptr, "source", 0, NULL, ICON_NONE);
737
738                         if(ima->source != IMA_SRC_GENERATED) {
739                                 row= uiLayoutRow(layout, 1);
740                                 split = uiLayoutSplit(row, 0.0, 0);
741                                 if (ima->packedfile)
742                                         uiItemO(split, "", ICON_PACKAGE, "image.unpack");
743                                 else
744                                         uiItemO(split, "", ICON_UGLYPACKAGE, "image.pack");
745                                 
746                                 split = uiLayoutSplit(row, 0.0, 0);
747                                 row= uiLayoutRow(split, 1);
748                                 uiLayoutSetEnabled(row, ima->packedfile==NULL);
749                                 
750                                 uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
751                                 uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
752                         }
753
754                         // XXX what was this for?
755 #if 0
756                          /* check for re-render, only buttons */
757                         if(imagechanged==B_IMAGECHANGED) {
758                                 if(iuser->flag & IMA_ANIM_REFRESHED) {
759                                         iuser->flag &= ~IMA_ANIM_REFRESHED;
760                                         WM_event_add_notifier(C, NC_IMAGE, ima);
761                                 }
762                         }
763 #endif
764
765                         /* multilayer? */
766                         if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
767                                 uiblock_layer_pass_arrow_buttons(layout, ima->rr, iuser, NULL);
768                         }
769                         else if(ima->source != IMA_SRC_GENERATED) {
770                                 if(compact == 0) {
771                                         ibuf= BKE_image_acquire_ibuf(ima, iuser, &lock);
772                                         image_info(scene, iuser, ima, ibuf, str);
773                                         BKE_image_release_ibuf(ima, lock);
774                                         uiItemL(layout, str, ICON_NONE);
775                                 }
776                         }
777                         
778                         if(ima->source != IMA_SRC_GENERATED) {
779                                 if(compact == 0) { /* background image view doesnt need these */
780                                         uiItemS(layout);
781
782                                         split= uiLayoutSplit(layout, 0, 0);
783
784                                         col= uiLayoutColumn(split, 0);
785                                         uiItemR(col, &imaptr, "use_fields", 0, NULL, ICON_NONE);
786                                         row= uiLayoutRow(col, 0);
787                                         uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
788                                         uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields"));
789
790                                         col= uiLayoutColumn(split, 0);
791                                         uiItemR(col, &imaptr, "use_premultiply", 0, NULL, ICON_NONE);
792                                 }
793                         }
794
795                         if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
796                                 uiItemS(layout);
797                                 
798                                 split= uiLayoutSplit(layout, 0, 0);
799
800                                 col= uiLayoutColumn(split, 0);
801                                  
802                                 sprintf(str, "(%d) Frames", iuser->framenr);
803                                 row= uiLayoutRow(col, 1);
804                                 uiItemR(col, userptr, "frame_duration", 0, str, ICON_NONE);
805                                 if(ima->anim) {
806                                         block= uiLayoutGetBlock(row);
807                                         but= uiDefBut(block, BUT, 0, "Match Movie Length", 0, 0, UI_UNIT_X*2, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Set the number of frames to match the movie or sequence.");
808                                         uiButSetFunc(but, set_frames_cb, ima, iuser);
809                                 }
810
811                                 uiItemR(col, userptr, "frame_start", 0, "Start", ICON_NONE);
812                                 uiItemR(col, userptr, "frame_offset", 0, NULL, ICON_NONE);
813
814                                 col= uiLayoutColumn(split, 0);
815                                 uiItemR(col, userptr, "fields_per_frame", 0, "Fields", ICON_NONE);
816                                 uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE);
817                                 uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE);
818                         }
819                         else if(ima->source==IMA_SRC_GENERATED) {
820                                 split= uiLayoutSplit(layout, 0, 0);
821
822                                 col= uiLayoutColumn(split, 1);
823                                 uiItemR(col, &imaptr, "generated_width", 0, "X", ICON_NONE);
824                                 uiItemR(col, &imaptr, "generated_height", 0, "Y", ICON_NONE);
825
826                                 col= uiLayoutColumn(split, 0);
827                                 uiItemR(col, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
828                         }
829
830                                         }
831
832                 uiBlockSetNFunc(block, NULL, NULL, NULL);
833         }
834
835         MEM_freeN(cb);
836 }
837
838 void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
839 {
840         Scene *scene= CTX_data_scene(C);
841         RenderResult *rr;
842
843         /* render layers and passes */
844         if(ima && iuser) {
845                 const float dpi_fac= UI_DPI_FAC;
846                 rr= BKE_image_acquire_renderresult(scene, ima);
847                 uiblock_layer_pass_buttons(layout, rr, iuser, 160 * dpi_fac, (ima->type==IMA_TYPE_R_RESULT)? &ima->render_slot: NULL);
848                 BKE_image_release_renderresult(scene, ima);
849         }
850 }
851
852 void image_buttons_register(ARegionType *art)
853 {
854         PanelType *pt;
855
856         pt= MEM_callocN(sizeof(PanelType), "spacetype image panel curves");
857         strcpy(pt->idname, "IMAGE_PT_curves");
858         strcpy(pt->label, "Curves");
859         pt->draw= image_panel_curves;
860         pt->poll= image_panel_poll;
861         pt->flag |= PNL_DEFAULT_CLOSED;
862         BLI_addtail(&art->paneltypes, pt);
863         
864         pt= MEM_callocN(sizeof(PanelType), "spacetype image panel gpencil");
865         strcpy(pt->idname, "IMAGE_PT_gpencil");
866         strcpy(pt->label, "Grease Pencil");
867         pt->draw= gpencil_panel_standard;
868         BLI_addtail(&art->paneltypes, pt);
869 }
870
871 static int image_properties(bContext *C, wmOperator *UNUSED(op))
872 {
873         ScrArea *sa= CTX_wm_area(C);
874         ARegion *ar= image_has_buttons_region(sa);
875         
876         if(ar)
877                 ED_region_toggle_hidden(C, ar);
878
879         return OPERATOR_FINISHED;
880 }
881
882 void IMAGE_OT_properties(wmOperatorType *ot)
883 {
884         ot->name= "Properties";
885         ot->idname= "IMAGE_OT_properties";
886         ot->description= "Toggle display properties panel";
887         
888         ot->exec= image_properties;
889         ot->poll= ED_operator_image_active;
890         
891         /* flags */
892         ot->flag= 0;
893 }
894
895 static int image_scopes(bContext *C, wmOperator *UNUSED(op))
896 {
897         ScrArea *sa= CTX_wm_area(C);
898         ARegion *ar= image_has_scope_region(sa);
899         
900         if(ar)
901                 ED_region_toggle_hidden(C, ar);
902         
903         return OPERATOR_FINISHED;
904 }
905
906 void IMAGE_OT_scopes(wmOperatorType *ot)
907 {
908         ot->name= "Scopes";
909         ot->idname= "IMAGE_OT_scopes";
910         ot->description= "Toggle display scopes panel";
911         
912         ot->exec= image_scopes;
913         ot->poll= ED_operator_image_active;
914         
915         /* flags */
916         ot->flag= 0;
917 }
918