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