Fix #20619: subsurf + explode modifier crash.
[blender.git] / source / blender / editors / interface / interface_templates.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  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <string.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_scene_types.h"
32 #include "DNA_screen_types.h"
33
34 #include "BLI_string.h"
35
36 #include "BKE_colortools.h"
37 #include "BKE_context.h"
38 #include "BKE_icons.h"
39 #include "BKE_global.h"
40 #include "BKE_library.h"
41 #include "BKE_main.h"
42 #include "BKE_utildefines.h"
43
44 #include "ED_screen.h"
45 #include "ED_render.h"
46
47 #include "RNA_access.h"
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51
52 #include "UI_interface.h"
53 #include "UI_resources.h"
54 #include "interface_intern.h"
55
56 void ui_template_fix_linking()
57 {
58 }
59
60 /********************** Header Template *************************/
61
62 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
63 {
64         uiBlock *block;
65
66         block= uiLayoutAbsoluteBlock(layout);
67         if(menus) ED_area_header_standardbuttons(C, block, 0);
68         else ED_area_header_switchbutton(C, block, 0);
69 }
70
71 /********************** DopeSheet Filter Template *************************/
72
73 void uiTemplateDopeSheetFilter(uiLayout *layout, bContext *C, PointerRNA *ptr)
74 {
75         Main *mainptr= CTX_data_main(C);
76         ScrArea *sa= CTX_wm_area(C);
77         uiLayout *row= layout;
78         short nlaActive= ((sa) && (sa->spacetype==SPACE_NLA));
79
80         /* more 'generic' filtering options */
81         if (nlaActive)
82                 row= uiLayoutRow(layout, 1);
83
84         uiItemR(row, "", 0, ptr, "only_selected", 0);
85
86         if (nlaActive)
87                 uiItemR(row, "", 0, ptr, "include_missing_nla", 0);
88
89         if (nlaActive)
90                 row= layout;
91
92         /* datatype based - only available datatypes are shown */
93         row= uiLayoutRow(layout, 1);
94
95         uiItemR(row, "", 0, ptr, "display_scene", 0);
96         uiItemR(row, "", 0, ptr, "display_world", 0);
97         uiItemR(row, "", 0, ptr, "display_node", 0);
98
99         if (mainptr && mainptr->mesh.first)
100                 uiItemR(row, "", 0, ptr, "display_mesh", 0);
101         if (mainptr && mainptr->key.first)
102                 uiItemR(row, "", 0, ptr, "display_shapekeys", 0);
103         if (mainptr && mainptr->mat.first)
104                 uiItemR(row, "", 0, ptr, "display_material", 0);
105         if (mainptr && mainptr->lamp.first)
106                 uiItemR(row, "", 0, ptr, "display_lamp", 0);
107         if (mainptr && mainptr->camera.first)
108                 uiItemR(row, "", 0, ptr, "display_camera", 0);
109         if (mainptr && mainptr->curve.first)
110                 uiItemR(row, "", 0, ptr, "display_curve", 0);
111         if (mainptr && mainptr->mball.first)
112                 uiItemR(row, "", 0, ptr, "display_metaball", 0);
113         if (mainptr && mainptr->armature.first)
114                 uiItemR(row, "", 0, ptr, "display_armature", 0);
115         if (mainptr && mainptr->particle.first)
116                 uiItemR(row, "", 0, ptr, "display_particle", 0);
117 }
118
119 /********************** Search Callbacks *************************/
120
121 typedef struct TemplateID {
122         PointerRNA ptr;
123         PropertyRNA *prop;
124
125         ListBase *idlb;
126         int prv_rows, prv_cols;
127 } TemplateID;
128
129 /* Search browse menu, assign  */
130 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
131 {
132         TemplateID *template= (TemplateID*)arg_template;
133
134         /* ID */
135         if(item) {
136                 PointerRNA idptr;
137
138                 RNA_id_pointer_create(item, &idptr);
139                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
140                 RNA_property_update(C, &template->ptr, template->prop);
141         }
142 }
143
144 /* ID Search browse menu, do the search */
145 static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSearchItems *items)
146 {
147         TemplateID *template= (TemplateID*)arg_template;
148         ListBase *lb= template->idlb;
149         ID *id;
150         int iconid;
151
152         /* ID listbase */
153         for(id= lb->first; id; id= id->next) {
154                 if(BLI_strcasestr(id->name+2, str)) {
155                         iconid= ui_id_icon_get((bContext*)C, id, 0);
156
157                         if(!uiSearchItemAdd(items, id->name+2, id, iconid))
158                                 break;
159                 }
160         }
161 }
162
163 /* ID Search browse menu, open */
164 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
165 {
166         static char search[256];
167         static TemplateID template;
168         PointerRNA idptr;
169         wmEvent event;
170         wmWindow *win= CTX_wm_window(C);
171         uiBlock *block;
172         uiBut *but;
173         
174         /* clear initial search string, then all items show */
175         search[0]= 0;
176         /* arg_litem is malloced, can be freed by parent button */
177         template= *((TemplateID*)arg_litem);
178         
179         /* get active id for showing first item */
180         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
181
182         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
183         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
184         
185         /* preview thumbnails */
186         if (template.prv_rows > 0 && template.prv_cols > 0) {
187                 int w = 96 * template.prv_cols;
188                 int h = 96 * template.prv_rows + 20;
189                 
190                 /* fake button, it holds space for search items */
191                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
192                 
193                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
194                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
195         }
196         /* list view */
197         else {
198                 /* fake button, it holds space for search items */
199                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
200                 
201                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
202                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
203         }
204                 
205         
206         uiBoundsBlock(block, 6);
207         uiBlockSetDirection(block, UI_DOWN);    
208         uiEndBlock(C, block);
209         
210         event= *(win->eventstate);      /* XXX huh huh? make api call */
211         event.type= EVT_BUT_OPEN;
212         event.val= KM_PRESS;
213         event.customdata= but;
214         event.customdatafree= FALSE;
215         wm_event_add(win, &event);
216         
217         return block;
218 }
219
220 /************************ ID Template ***************************/
221 /* This is for browsing and editing the ID-blocks used */
222
223 /* for new/open operators */
224 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
225 {
226         TemplateID *template;
227         ARegion *ar= CTX_wm_region(C);
228         uiBlock *block;
229         uiBut *but;
230
231         memset(ptr, 0, sizeof(*ptr));
232         *prop= NULL;
233
234         if(!ar)
235                 return;
236
237         for(block=ar->uiblocks.first; block; block=block->next) {
238                 for(but=block->buttons.first; but; but= but->next) {
239                         /* find the button before the active one */
240                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
241                                 if(but->func_argN) {
242                                         template= but->func_argN;
243                                         *ptr= template->ptr;
244                                         *prop= template->prop;
245                                         return;
246                                 }
247                         }
248                 }
249         }
250 }
251
252
253 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
254 {
255         TemplateID *template= (TemplateID*)arg_litem;
256         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
257         ID *id= idptr.data, *newid;
258         int event= GET_INT_FROM_POINTER(arg_event);
259         
260         switch(event) {
261                 case UI_ID_BROWSE:
262                 case UI_ID_PIN:
263                         printf("warning, id event %d shouldnt come here\n", event);
264                         break;
265                 case UI_ID_OPEN:
266                 case UI_ID_ADD_NEW:
267                         /* these call uiIDContextPropertySet */
268                         break;
269                 case UI_ID_DELETE:
270                         memset(&idptr, 0, sizeof(idptr));
271                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
272                         RNA_property_update(C, &template->ptr, template->prop);
273                         break;
274                 case UI_ID_FAKE_USER:
275                         if(id) {
276                                 if(id->flag & LIB_FAKEUSER) id->us++;
277                                 else id->us--;
278                         }
279                         else return;
280                         break;
281                 case UI_ID_LOCAL:
282                         if(id) {
283                                 if(id_make_local(id, 0)) {
284                                         /* reassign to get get proper updates/notifiers */
285                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
286                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
287                                         RNA_property_update(C, &template->ptr, template->prop);
288                                 }
289                         }
290                         break;
291                 case UI_ID_ALONE:
292                         if(id) {
293                                 /* make copy */
294                                 if(id_copy(id, &newid, 0) && newid) {
295                                         /* us is 1 by convention, but RNA_property_pointer_set
296                                            will also incremement it, so set it to zero */
297                                         newid->us= 0;
298
299                                         /* assign copy */
300                                         RNA_id_pointer_create(newid, &idptr);
301                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
302                                         RNA_property_update(C, &template->ptr, template->prop);
303                                 }
304                         }
305                         break;
306 #if 0
307                 case UI_ID_AUTO_NAME:
308                         break;
309 #endif
310         }
311 }
312
313 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
314 {
315         uiBut *but;
316         uiBlock *block;
317         PointerRNA idptr;
318         ListBase *lb;
319         ID *id, *idfrom;
320
321         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
322         id= idptr.data;
323         idfrom= template->ptr.id.data;
324         lb= template->idlb;
325
326         block= uiLayoutGetBlock(layout);
327         uiBlockBeginAlign(block);
328
329         if(idptr.type)
330                 type= idptr.type;
331
332         if(flag & UI_ID_PREVIEWS) {
333
334                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, "Browse ID data");
335                 if(type) {
336                         but->icon= RNA_struct_ui_icon(type);
337                         if (id) but->icon = ui_id_icon_get(C, id, 1);
338                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
339                 }
340                 if((idfrom && idfrom->lib))
341                         uiButSetFlag(but, UI_BUT_DISABLED);
342                 
343                 
344                 uiLayoutRow(layout, 1);
345         } else 
346                 
347         if(flag & UI_ID_BROWSE) {
348                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, "Browse ID data");
349                 if(type) {
350                         but->icon= RNA_struct_ui_icon(type);
351                         but->flag|= UI_HAS_ICON;
352                         but->flag|= UI_ICON_LEFT;
353                 }
354
355                 if((idfrom && idfrom->lib))
356                         uiButSetFlag(but, UI_BUT_DISABLED);
357         }
358
359         /* text button with name */
360         if(id) {
361                 char name[64];
362
363                 //text_idbutton(id, name);
364                 name[0]= '\0';
365                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
366                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
367
368                 if(id->lib) {
369                         if(id->flag & LIB_INDIRECT) {
370                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0,
371                                         "Indirect library datablock, cannot change.");
372                                 uiButSetFlag(but, UI_BUT_DISABLED);
373                         }
374                         else {
375                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0,
376                                         "Direct linked library datablock, click to make local.");
377                                 if(!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
378                                         uiButSetFlag(but, UI_BUT_DISABLED);
379                         }
380
381                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
382                 }
383
384                 if(id->us > 1) {
385                         char str[32];
386
387                         sprintf(str, "%d", id->us);
388
389                         if(id->us<10)
390                                 but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
391                         else
392                                 but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X+10,UI_UNIT_Y, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
393
394                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
395                         if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib))
396                                 uiButSetFlag(but, UI_BUT_DISABLED);
397                 }
398         }
399         
400         if(flag & UI_ID_ADD_NEW) {
401                 int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6;
402                 
403                 if(newop) {
404                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_EXEC_DEFAULT, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL);
405                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
406                 }
407                 else {
408                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
409                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
410                 }
411
412                 if((idfrom && idfrom->lib))
413                         uiButSetFlag(but, UI_BUT_DISABLED);
414         }
415
416         if(flag & UI_ID_OPEN) {
417                 int w= id?UI_UNIT_X: (flag & UI_ID_ADD_NEW)? UI_UNIT_X*3: UI_UNIT_X*6;
418                 
419                 if(openop) {
420                         but= uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL);
421                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
422                 }
423                 else {
424                         but= uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
425                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
426                 }
427
428                 if((idfrom && idfrom->lib))
429                         uiButSetFlag(but, UI_BUT_DISABLED);
430         }
431         
432         /* delete button */
433         if(id && (flag & UI_ID_DELETE)) {
434                 if(unlinkop) {
435                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
436                 }
437                 else {
438                         but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
439                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
440                 }
441
442                 if((idfrom && idfrom->lib))
443                         uiButSetFlag(but, UI_BUT_DISABLED);
444         }
445         
446         uiBlockEndAlign(block);
447 }
448
449 static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int previews, int prv_rows, int prv_cols)
450 {
451         TemplateID *template;
452         PropertyRNA *prop;
453         StructRNA *type;
454         int flag;
455
456         prop= RNA_struct_find_property(ptr, propname);
457
458         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
459                 printf("uiTemplateID: pointer property not found: %s\n", propname);
460                 return;
461         }
462
463         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
464         template->ptr= *ptr;
465         template->prop= prop;
466         template->prv_rows = prv_rows;
467         template->prv_cols = prv_cols;
468         
469         flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
470
471         if(newop)
472                 flag |= UI_ID_ADD_NEW;
473         if(openop)
474                 flag |= UI_ID_OPEN;
475         if(previews)
476                 flag |= UI_ID_PREVIEWS;
477         
478         type= RNA_property_pointer_type(ptr, prop);
479         template->idlb= wich_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
480         
481         /* create UI elements for this template
482          *      - template_ID makes a copy of the template data and assigns it to the relevant buttons
483          */
484         if(template->idlb) {
485                 uiLayoutRow(layout, 1);
486                 template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
487         }
488
489         MEM_freeN(template);
490         
491 }
492
493 void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
494 {
495         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, 0, 0, 0);
496 }
497
498 void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int rows, int cols)
499 {
500         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, 1, rows, cols);
501 }
502
503 /************************ ID Chooser Template ***************************/
504
505 /* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use 
506  *
507  * - propname: property identifier for property that ID-pointer gets stored to
508  * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
509  */
510 void uiTemplateAnyID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *proptypename, char *text)
511 {
512         PropertyRNA *propID, *propType;
513         uiLayout *row;
514         
515         /* get properties... */
516         propID= RNA_struct_find_property(ptr, propname);
517         propType= RNA_struct_find_property(ptr, proptypename);
518
519         if (!propID || RNA_property_type(propID) != PROP_POINTER) {
520                 printf("uiTemplateAnyID: pointer property not found: %s\n", propname);
521                 return;
522         }
523         if (!propType || RNA_property_type(propType) != PROP_ENUM) { 
524                 printf("uiTemplateAnyID: pointer-type property not found: %s\n", proptypename);
525                 return;
526         }
527         
528         /* Start drawing UI Elements using standard defines */
529         row= uiLayoutRow(layout, 1);
530         
531         /* Label - either use the provided text, or will become "ID-Block:" */
532         if (text)
533                 uiItemL(row, text, 0);
534         else
535                 uiItemL(row, "ID-Block:", 0);
536         
537         /* ID-Type Selector - just have a menu of icons */
538         // FIXME: the icon-only setting doesn't work when we supply a blank name
539         uiItemFullR(row, "", 0, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY);
540         
541         /* ID-Block Selector - just use pointer widget... */
542         uiItemFullR(row, "", 0, ptr, propID, 0, 0, 0);
543 }
544
545 /********************* RNA Path Builder Template ********************/
546
547 /* ---------- */
548
549 /* This is creating/editing RNA-Paths 
550  *
551  * - ptr: struct which holds the path property
552  * - propname: property identifier for property that path gets stored to
553  * - root_ptr: struct that path gets built from
554  */
555 void uiTemplatePathBuilder(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, PointerRNA *root_ptr, char *text)
556 {
557         PropertyRNA *propPath;
558         uiLayout *row;
559         
560         /* check that properties are valid */
561         propPath= RNA_struct_find_property(ptr, propname);
562         if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
563                 printf("uiTemplatePathBuilder: path property not found: %s\n", propname);
564                 return;
565         }
566         
567         /* Start drawing UI Elements using standard defines */
568         row= uiLayoutRow(layout, 1);
569         
570         /* Path (existing string) Widget */
571         uiItemR(row, text, ICON_RNA, ptr, propname, 0);
572         
573         // TODO: attach something to this to make allow searching of nested properties to 'build' the path
574 }
575
576 /************************ Modifier Template *************************/
577
578 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
579
580 #include <string.h>
581
582 #include "DNA_object_force.h"
583 #include "DNA_object_types.h"
584 #include "DNA_modifier_types.h"
585 #include "DNA_scene_types.h"
586
587 #include "BKE_depsgraph.h"
588 #include "BKE_DerivedMesh.h"
589 #include "BKE_global.h"
590 #include "BKE_modifier.h"
591 #include "BKE_object.h"
592 #include "BKE_particle.h"
593 #include "BKE_report.h"
594
595 #include "UI_resources.h"
596 #include "ED_util.h"
597
598 #include "BLI_math.h"
599 #include "BLI_listbase.h"
600
601 #include "ED_object.h"
602
603 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
604 {
605         Object *ob = ob_v;
606         ModifierData *md= md_v;
607         int i, cageIndex = modifiers_getCageIndex(ob, NULL, 0);
608
609         /* undo button operation */
610         md->mode ^= eModifierMode_OnCage;
611
612         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
613                 if(md == md_v) {
614                         if(i >= cageIndex)
615                                 md->mode ^= eModifierMode_OnCage;
616                         break;
617                 }
618         }
619
620         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
621         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
622 }
623
624 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
625 {
626         Object *ob = ob_v;
627         ModifierData *md = md_v;
628         ModifierData *nmd = modifier_new(md->type);
629
630         modifier_copyData(md, nmd);
631         nmd->mode &= ~eModifierMode_Virtual;
632
633         BLI_addhead(&ob->modifiers, nmd);
634         
635         modifier_unique_name(&ob->modifiers, nmd);
636
637         ob->partype = PAROBJECT;
638
639         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
640         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
641
642         ED_undo_push(C, "Modifier convert to real");
643 }
644
645 static int modifier_can_delete(ModifierData *md)
646 {
647         // fluid particle modifier can't be deleted here
648         if(md->type == eModifierType_ParticleSystem)
649                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
650                         return 0;
651
652         return 1;
653 }
654
655 static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
656 {
657         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
658         PointerRNA ptr;
659         uiBut *but;
660         uiBlock *block;
661         uiLayout *box, *column, *row;
662         uiLayout *result= NULL;
663         int isVirtual = (md->mode & eModifierMode_Virtual);
664         char str[128];
665
666         /* create RNA pointer */
667         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
668
669         column= uiLayoutColumn(layout, 1);
670         uiLayoutSetContextPointer(column, "modifier", &ptr);
671
672         /* rounded header ------------------------------------------------------------------- */
673         box= uiLayoutBox(column);
674         
675         row= uiLayoutRow(box, 0);
676         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
677         block= uiLayoutGetBlock(row);
678         
679         if (isVirtual) {
680                 /* VIRTUAL MODIFIER */
681                 // XXX this is not used now, since these cannot be accessed via RNA
682                 sprintf(str, "%s parent deform", md->name);
683                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
684                 
685                 but = uiDefBut(block, BUT, 0, "Make Real", 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Convert virtual modifier to a real modifier");
686                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
687         }
688         else {
689                 /* REAL MODIFIER */
690                 uiLayout *subrow, *col2;
691                 
692                 /* Open/Close .................................  */
693                 uiBlockSetEmboss(block, UI_EMBOSSN);
694                 uiDefIconButBitI(block, ICONTOG, eModifierMode_Expanded, 0, ICON_TRIA_RIGHT, 0, 0, UI_UNIT_X, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Modifier");
695                 
696                 /* modifier-type icon */
697                 uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
698                 uiBlockSetEmboss(block, UI_EMBOSS);
699                 
700                 /* 'Middle Column' ............................ 
701                  *      - first row is the name of the modifier 
702                  *      - second row is the visibility settings, since the layouts were not wide enough to show all
703                  */
704                 col2= uiLayoutColumn(row, 0);
705                         /* First Row */
706                         subrow= uiLayoutRow(col2, 0);
707                                 /* modifier name */
708                                 uiItemR(subrow, "", 0, &ptr, "name", 0);
709                         
710                         /* Second Row */
711                         subrow= uiLayoutRow(col2, 1);
712                         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_EXPAND);
713                         block= uiLayoutGetBlock(subrow);
714                                 /* Softbody not allowed in this situation, enforce! */
715                                 if ( ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) 
716                                                 && (md->type!=eModifierType_Surface) ) 
717                                 {
718                                         uiItemR(subrow, "", ICON_SCENE, &ptr, "render", 0);
719                                         uiItemR(subrow, "", ICON_RESTRICT_VIEW_OFF, &ptr, "realtime", 0);
720                                         
721                                         if (mti->flags & eModifierTypeFlag_SupportsEditmode)
722                                                 uiItemR(subrow, "", ICON_EDITMODE_HLT, &ptr, "editmode", 0);
723                                 }
724                                 
725                                 if ((ob->type==OB_MESH) && modifier_couldBeCage(md) && (index <= lastCageIndex)) 
726                                 {
727                                         but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, 16, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode");
728                                         if (index < cageIndex)
729                                                 uiButSetFlag(but, UI_BUT_DISABLED);
730                                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
731                                 }
732                         
733                 /* Up/Down + Delete ........................... */
734                 block= uiLayoutGetBlock(row);
735                 uiBlockBeginAlign(block);
736                         uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
737                         uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
738                 uiBlockEndAlign(block);
739                 
740                 uiBlockSetEmboss(block, UI_EMBOSSN);
741                 
742                 if (modifier_can_delete(md))
743                         uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
744                         
745                 uiBlockSetEmboss(block, UI_EMBOSS);
746         }
747
748         
749         /* modifier settings (under the header) --------------------------------------------------- */
750         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
751                 /* apply/convert/copy */
752                 box= uiLayoutBox(column);
753                 row= uiLayoutRow(box, 0);
754                 
755                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
756                         /* only here obdata, the rest of modifiers is ob level */
757                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
758                         
759                         if (md->type==eModifierType_ParticleSystem) {
760                         ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
761                                 
762                         if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
763                                         if(ELEM3(psys->part->ren_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache)
764                                                 uiItemO(row, "Convert", 0, "OBJECT_OT_modifier_convert");
765                                 }
766                         }
767                         else {
768                                 uiItemEnumO(row, "Apply", 0, "OBJECT_OT_modifier_apply", "apply_as", MODIFIER_APPLY_DATA);
769                                 
770                                 if (modifier_sameTopology(md))
771                                         uiItemEnumO(row, "Apply as Shape", 0, "OBJECT_OT_modifier_apply", "apply_as", MODIFIER_APPLY_SHAPE);
772                         }
773                         
774                         uiBlockClearButLock(block);
775                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
776                         
777                         if (!ELEM4(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth))
778                                 uiItemO(row, "Copy", 0, "OBJECT_OT_modifier_copy");
779                 }
780                 
781                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
782                 result= uiLayoutColumn(box, 0);
783                 block= uiLayoutAbsoluteBlock(box);
784         }
785         
786         /* error messages */
787         if(md->error) {
788                 box = uiLayoutBox(column);
789                 row = uiLayoutRow(box, 0);
790                 uiItemL(row, md->error, ICON_ERROR);
791         }
792         
793         return result;
794 }
795
796 uiLayout *uiTemplateModifier(uiLayout *layout, PointerRNA *ptr)
797 {
798         Object *ob;
799         ModifierData *md, *vmd;
800         int i, lastCageIndex, cageIndex;
801
802         /* verify we have valid data */
803         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
804                 printf("uiTemplateModifier: expected modifier on object.\n");
805                 return NULL;
806         }
807
808         ob= ptr->id.data;
809         md= ptr->data;
810
811         if(!ob || !(GS(ob->id.name) == ID_OB)) {
812                 printf("uiTemplateModifier: expected modifier on object.\n");
813                 return NULL;
814         }
815         
816         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
817         
818         /* find modifier and draw it */
819         cageIndex = modifiers_getCageIndex(ob, &lastCageIndex, 0);
820
821         // XXX virtual modifiers are not accesible for python
822         vmd = modifiers_getVirtualModifierList(ob);
823
824         for(i=0; vmd; i++, vmd=vmd->next) {
825                 if(md == vmd)
826                         return draw_modifier(layout, ob, md, i, cageIndex, lastCageIndex);
827                 else if(vmd->mode & eModifierMode_Virtual)
828                         i--;
829         }
830
831         return NULL;
832 }
833
834 /************************ Constraint Template *************************/
835
836 #include "DNA_action_types.h"
837 #include "DNA_constraint_types.h"
838
839 #include "BKE_action.h"
840 #include "BKE_constraint.h"
841
842 #define REDRAWIPO                                       1
843 #define REDRAWNLA                                       2
844 #define REDRAWBUTSOBJECT                        3               
845 #define REDRAWACTION                            4
846 #define B_CONSTRAINT_TEST                       5
847 #define B_CONSTRAINT_CHANGETARGET       6
848 #define B_CONSTRAINT_INF                        7
849 #define REMAKEIPO                                       8
850 #define B_DIFF                                          9
851
852 void do_constraint_panels(bContext *C, void *arg, int event)
853 {
854         Scene *scene= CTX_data_scene(C);
855         Object *ob= CTX_data_active_object(C);
856         
857         switch(event) {
858         case B_CONSTRAINT_TEST:
859                 // XXX allqueue(REDRAWVIEW3D, 0);
860                 // XXX allqueue(REDRAWBUTSOBJECT, 0);
861                 // XXX allqueue(REDRAWBUTSEDIT, 0);
862                 break;  // no handling
863         case B_CONSTRAINT_INF:
864                 /* influence; do not execute actions for 1 dag_flush */
865                 if (ob->pose)
866                         ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
867                 break;
868         case B_CONSTRAINT_CHANGETARGET:
869                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
870                 DAG_scene_sort(scene);
871                 break;
872         default:
873                 break;
874         }
875
876         object_test_constraints(ob);
877         
878         if(ob->pose) update_pose_constraint_flags(ob->pose);
879         
880         if(ob->type==OB_ARMATURE) DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
881         else DAG_id_flush_update(&ob->id, OB_RECALC_OB);
882
883         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
884         
885         // XXX allqueue(REDRAWVIEW3D, 0);
886         // XXX allqueue(REDRAWBUTSOBJECT, 0);
887         // XXX allqueue(REDRAWBUTSEDIT, 0);
888 }
889
890 static void constraint_active_func(bContext *C, void *ob_v, void *con_v)
891 {
892         ED_object_constraint_set_active(ob_v, con_v);
893 }
894
895 static void verify_constraint_name_func (bContext *C, void *con_v, void *dummy)
896 {
897         Object *ob= CTX_data_active_object(C);
898         bConstraint *con= con_v;
899         
900         if (!con)
901                 return;
902         
903         ED_object_constraint_rename(ob, con, NULL);
904         ED_object_constraint_set_active(ob, con);
905         // XXX allqueue(REDRAWACTION, 0); 
906 }
907
908 /* some commonly used macros in the constraints drawing code */
909 #define is_armature_target(target) (target && target->type==OB_ARMATURE)
910 #define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE))
911 #define is_geom_target(target) (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) )
912
913 /* Helper function for draw constraint - draws constraint space stuff 
914  * This function should not be called if no menus are required 
915  * owner/target: -1 = don't draw menu; 0= not posemode, 1 = posemode 
916  */
917 static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short xco, short yco, short owner, short target)
918 {
919         short tarx, ownx, iconx;
920         short bwidth;
921         short iconwidth = 20;
922         
923         /* calculate sizes and placement of menus */
924         if (owner == -1) {
925                 bwidth = 125;
926                 tarx = 120;
927                 ownx = 0;
928         }
929         else if (target == -1) {
930                 bwidth = 125;
931                 tarx = 0;
932                 ownx = 120;
933         }
934         else {
935                 bwidth = 100;
936                 tarx = 85;
937                 iconx = tarx + bwidth + 5;
938                 ownx = tarx + bwidth + iconwidth + 10;
939         }
940         
941         
942         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Convert:", xco, yco, 80,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
943
944         /* Target-Space */
945         if (target == 1) {
946                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
947                                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
948         }
949         else if (target == 0) {
950                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
951                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
952         }
953         
954         if ((target != -1) && (owner != -1))
955                 uiDefIconBut(block, LABEL, 0, ICON_ARROW_LEFTRIGHT,
956                         iconx, yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "");
957         
958         /* Owner-Space */
959         if (owner == 1) {
960                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
961                                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
962         }
963         else if (owner == 0) {
964                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Local (Without Parent) Space %x1", 
965                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
966         }
967 }
968
969 static void test_obpoin_but(bContext *C, char *name, ID **idpp)
970 {
971         ID *id= BLI_findstring(&CTX_data_main(C)->object, name, offsetof(ID, name) + 2);
972         *idpp= id; /* can be NULL */
973         
974         if(id)
975                 id_lib_extern(id);      /* checks lib data, sets correct flag for saving then */
976 }
977
978 /* draw panel showing settings for a constraint */
979 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
980 {
981         bPoseChannel *pchan= get_active_posechannel(ob);
982         bConstraintTypeInfo *cti;
983         uiBlock *block;
984         uiLayout *result= NULL, *col, *box, *row, *subrow;
985         uiBut *but;
986         PointerRNA ptr;
987         char typestr[32];
988         short width = 265;
989         short proxy_protected, xco=0, yco=0;
990         int rb_col;
991
992         /* get constraint typeinfo */
993         cti= constraint_get_typeinfo(con);
994         if (cti == NULL) {
995                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
996                 if (con->type == CONSTRAINT_TYPE_NULL)
997                         strcpy(typestr, "Null");
998                 else
999                         strcpy(typestr, "Unknown");
1000         }
1001         else
1002                 strcpy(typestr, cti->name);
1003                 
1004         /* determine whether constraint is proxy protected or not */
1005         if (proxylocked_constraints_owner(ob, pchan))
1006                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
1007         else
1008                 proxy_protected= 0;
1009
1010         /* unless button has own callback, it adds this callback to button */
1011         block= uiLayoutGetBlock(layout);
1012         uiBlockSetHandleFunc(block, do_constraint_panels, NULL);
1013         uiBlockSetFunc(block, constraint_active_func, ob, con);
1014
1015         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
1016
1017         col= uiLayoutColumn(layout, 1);
1018         uiLayoutSetContextPointer(col, "constraint", &ptr);
1019
1020         box= uiLayoutBox(col);
1021         row= uiLayoutRow(box, 0);
1022
1023         block= uiLayoutGetBlock(box);
1024
1025         subrow= uiLayoutRow(row, 0);
1026         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
1027
1028         /* Draw constraint header */
1029         uiBlockSetEmboss(block, UI_EMBOSSN);
1030         
1031         /* rounded header */
1032         rb_col= (con->flag & CONSTRAINT_ACTIVE)?50:20;
1033         
1034         /* open/close */
1035         uiDefIconButBitS(block, ICONTOG, CONSTRAINT_EXPAND, B_CONSTRAINT_TEST, ICON_TRIA_RIGHT, xco-10, yco, 20, 20, &con->flag, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Constraint");
1036         
1037         /* name */      
1038         uiBlockSetEmboss(block, UI_EMBOSS);
1039         
1040         /* XXX if (con->flag & CONSTRAINT_DISABLE)
1041                 uiBlockSetCol(block, TH_REDALERT);*/
1042         
1043         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1044         
1045         if(proxy_protected == 0) {
1046                 but = uiDefBut(block, TEX, B_CONSTRAINT_TEST, "", xco+120, yco, 85, 18, con->name, 0.0, 29.0, 0.0, 0.0, "Constraint name"); 
1047                 uiButSetFunc(but, verify_constraint_name_func, con, con->name);
1048         }
1049         else
1050                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, con->name, xco+120, yco-1, 135, 19, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1051
1052         // XXX uiBlockSetCol(block, TH_AUTO);   
1053
1054         subrow= uiLayoutRow(row, 0);
1055         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
1056         
1057         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
1058         if (proxy_protected) {
1059                 uiBlockSetEmboss(block, UI_EMBOSSN);
1060                 
1061                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
1062                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1063                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1064                 
1065                 uiBlockSetEmboss(block, UI_EMBOSS);
1066         }
1067         else {
1068                 short prev_proxylock, show_upbut, show_downbut;
1069                 
1070                 /* Up/Down buttons: 
1071                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
1072                  *      as that poses problems when restoring them, so disable the "up" button where
1073                  *      it may cause this situation. 
1074                  *
1075                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
1076                  */
1077                 if (proxylocked_constraints_owner(ob, pchan)) {
1078                         if (con->prev) {
1079                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
1080                         }
1081                         else
1082                                 prev_proxylock= 0;
1083                 }
1084                 else
1085                         prev_proxylock= 0;
1086                         
1087                 show_upbut= ((prev_proxylock == 0) && (con->prev));
1088                 show_downbut= (con->next) ? 1 : 0;
1089                 
1090                 if (show_upbut || show_downbut) {
1091                         uiBlockBeginAlign(block);
1092                                 uiBlockSetEmboss(block, UI_EMBOSS);
1093                                 
1094                                 if (show_upbut)
1095                                         uiDefIconButO(block, BUT, "CONSTRAINT_OT_move_up", WM_OP_INVOKE_DEFAULT, ICON_TRIA_UP, xco+width-50, yco, 16, 18, "Move constraint up in constraint stack");
1096                                 
1097                                 if (show_downbut)
1098                                         uiDefIconButO(block, BUT, "CONSTRAINT_OT_move_down", WM_OP_INVOKE_DEFAULT, ICON_TRIA_DOWN, xco+width-50+18, yco, 16, 18, "Move constraint down in constraint stack");
1099                         uiBlockEndAlign(block);
1100                 }
1101         
1102                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
1103                 uiBlockSetEmboss(block, UI_EMBOSSN);
1104                         uiDefIconButBitS(block, ICONTOGN, CONSTRAINT_OFF, B_CONSTRAINT_TEST, ICON_CHECKBOX_DEHLT, xco+243, yco, 19, 19, &con->flag, 0.0, 0.0, 0.0, 0.0, "enable/disable constraint");
1105                         
1106                         uiDefIconButO(block, BUT, "CONSTRAINT_OT_delete", WM_OP_INVOKE_DEFAULT, ICON_X, xco+262, yco, 19, 19, "Delete constraint");
1107                 uiBlockSetEmboss(block, UI_EMBOSS);
1108         }
1109         
1110         /* Set but-locks for protected settings (magic numbers are used here!) */
1111         if (proxy_protected)
1112                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1113         
1114         /* Draw constraint data */
1115         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1116                 (yco) -= 21;
1117         }
1118         else {
1119                 box= uiLayoutBox(col);
1120                 block= uiLayoutAbsoluteBlock(box);
1121
1122                 switch (con->type) {
1123 #ifndef DISABLE_PYTHON
1124                 case CONSTRAINT_TYPE_PYTHON:
1125                         {
1126                                 bPythonConstraint *data = con->data;
1127                                 bConstraintTarget *ct;
1128                                 // uiBut *but2;
1129                                 int tarnum, theight;
1130                                 // static int pyconindex=0;
1131                                 // char *menustr;
1132                                 
1133                                 theight = (data->tarnum)? (data->tarnum * 38) : (38);
1134                                 
1135                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", xco+60, yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1136                                 
1137                                 /* do the scripts menu */
1138                                 /* XXX menustr = buildmenu_pyconstraints(data->text, &pyconindex);
1139                                 but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
1140                                       xco+120, yco-24, 150, 20, &pyconindex,
1141                                       0, 0, 0, 0, "Set the Script Constraint to use");
1142                                 uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
1143                                 MEM_freeN(menustr);      */
1144                                 
1145                                 /* draw target(s) */
1146                                 if (data->flag & PYCON_USETARGETS) {
1147                                         /* Draw target parameters */ 
1148                                         for (ct=data->targets.first, tarnum=1; ct; ct=ct->next, tarnum++) {
1149                                                 char tarstr[32];
1150                                                 short yoffset= ((tarnum-1) * 38);
1151         
1152                                                 /* target label */
1153                                                 sprintf(tarstr, "Target %d:", tarnum);
1154                                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, xco+45, yco-(48+yoffset), 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1155                                                 
1156                                                 /* target space-selector - per target */
1157                                                 if (is_armature_target(ct->tar)) {
1158                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", 
1159                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1160                                                 }
1161                                                 else {
1162                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
1163                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1164                                                 }
1165                                                 
1166                                                 uiBlockBeginAlign(block);
1167                                                         /* target object */
1168                                                         uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", xco+120, yco-(48+yoffset), 150, 18, &ct->tar, "Target Object"); 
1169                                                         
1170                                                         /* subtarget */
1171                                                         if (is_armature_target(ct->tar)) {
1172                                                                 but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone");
1173                                                                 //uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar);
1174                                                         }
1175                                                         else if (is_geom_target(ct->tar)) {
1176                                                                 but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
1177                                                                 //uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar);
1178                                                         }
1179                                                         else {
1180                                                                 strcpy(ct->subtarget, "");
1181                                                         }
1182                                                 uiBlockEndAlign(block);
1183                                         }
1184                                 }
1185                                 else {
1186                                         /* Draw indication that no target needed */
1187                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", xco+60, yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1188                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", xco+120, yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1189                                 }
1190                                 
1191                                 /* settings */
1192                                 uiBlockBeginAlign(block);
1193                                         but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Options", xco, yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Change some of the constraint's settings.");
1194                                         // XXX uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL);
1195                                         
1196                                         but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Refresh", xco+((width/2)+10), yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Force constraint to refresh it's settings");
1197                                 uiBlockEndAlign(block);
1198                                 
1199                                 /* constraint space settings */
1200                                 draw_constraint_spaceselect(block, con, xco, yco-(73+theight), is_armature_owner(ob), -1);
1201                         }
1202                         break;
1203 #endif 
1204
1205                 case CONSTRAINT_TYPE_NULL:
1206                         {
1207                                 uiItemL(box, "", 0);
1208                         }
1209                         break;
1210                 default:
1211                         result= box;
1212                         break;
1213                 }
1214         }
1215         
1216         /* clear any locks set up for proxies/lib-linking */
1217         uiBlockClearButLock(block);
1218
1219         return result;
1220 }
1221
1222 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1223 {
1224         Object *ob;
1225         bConstraint *con;
1226
1227         /* verify we have valid data */
1228         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1229                 printf("uiTemplateConstraint: expected constraint on object.\n");
1230                 return NULL;
1231         }
1232
1233         ob= ptr->id.data;
1234         con= ptr->data;
1235
1236         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1237                 printf("uiTemplateConstraint: expected constraint on object.\n");
1238                 return NULL;
1239         }
1240         
1241         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1242
1243         /* hrms, the temporal constraint should not draw! */
1244         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1245                 bKinematicConstraint *data= con->data;
1246                 if(data->flag & CONSTRAINT_IK_TEMP)
1247                         return NULL;
1248         }
1249
1250         return draw_constraint(layout, ob, con);
1251 }
1252
1253
1254 /************************* Preview Template ***************************/
1255
1256 #include "DNA_lamp_types.h"
1257 #include "DNA_material_types.h"
1258 #include "DNA_world_types.h"
1259
1260 #define B_MATPRV 1
1261
1262 static void do_preview_buttons(bContext *C, void *arg, int event)
1263 {
1264         switch(event) {
1265                 case B_MATPRV:
1266                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1267                         break;
1268         }
1269 }
1270
1271 void uiTemplatePreview(uiLayout *layout, ID *id, ID *parent, MTex *slot)
1272 {
1273         uiLayout *row, *col;
1274         uiBlock *block;
1275         Material *ma= NULL;
1276         ID *pid, *pparent;
1277         short *pr_texture= NULL;
1278
1279         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1280                 printf("uiTemplatePreview: expected ID of type material, texture, lamp or world.\n");
1281                 return;
1282         }
1283
1284         /* decide what to render */
1285         pid= id;
1286         pparent= NULL;
1287
1288         if(id && (GS(id->name) == ID_TE)) {
1289                 if(parent && (GS(parent->name) == ID_MA))
1290                         pr_texture= &((Material*)parent)->pr_texture;
1291                 else if(parent && (GS(parent->name) == ID_WO))
1292                         pr_texture= &((World*)parent)->pr_texture;
1293                 else if(parent && (GS(parent->name) == ID_LA))
1294                         pr_texture= &((Lamp*)parent)->pr_texture;
1295
1296                 if(pr_texture) {
1297                         if(*pr_texture == TEX_PR_OTHER)
1298                                 pid= parent;
1299                         else if(*pr_texture == TEX_PR_BOTH)
1300                                 pparent= parent;
1301                 }
1302         }
1303
1304         /* layout */
1305         block= uiLayoutGetBlock(layout);
1306         row= uiLayoutRow(layout, 0);
1307         col= uiLayoutColumn(row, 0);
1308         uiLayoutSetKeepAspect(col, 1);
1309         
1310         /* add preview */
1311         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, pid, 0.0, 0.0, 0, 0, "");
1312         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
1313         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1314         
1315         /* add buttons */
1316         if(pid) {
1317                 if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
1318                         if(GS(pid->name) == ID_MA) ma= (Material*)pid;
1319                         else ma= (Material*)pparent;
1320
1321                         uiLayoutColumn(row, 1);
1322
1323                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATPLANE,  0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_FLAT, 0, 0, "Preview type: Flat XY plane");
1324                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATSPHERE, 0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_SPHERE, 0, 0, "Preview type: Sphere");
1325                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATCUBE,   0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_CUBE, 0, 0, "Preview type: Cube");
1326                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MONKEY,    0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_MONKEY, 0, 0, "Preview type: Monkey");
1327                         uiDefIconButC(block, ROW, B_MATPRV, ICON_HAIR,      0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_HAIR, 0, 0, "Preview type: Hair strands");
1328                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MAT_SPHERE_SKY, 0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_SPHERE_A, 0, 0, "Preview type: Large sphere with sky");
1329                 }
1330
1331                 if(pr_texture) {
1332                         uiLayoutRow(layout, 1);
1333
1334                         uiDefButS(block, ROW, B_MATPRV, "Texture",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
1335                         if(GS(parent->name) == ID_MA)
1336                                 uiDefButS(block, ROW, B_MATPRV, "Material",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1337                         else if(GS(parent->name) == ID_LA)
1338                                 uiDefButS(block, ROW, B_MATPRV, "Lamp",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1339                         else if(GS(parent->name) == ID_WO)
1340                                 uiDefButS(block, ROW, B_MATPRV, "World",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1341                         uiDefButS(block, ROW, B_MATPRV, "Both",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
1342                 }
1343         }
1344 }
1345
1346 /********************** ColorRamp Template **************************/
1347
1348 #include "BKE_texture.h"
1349
1350 typedef struct RNAUpdateCb {
1351         PointerRNA ptr;
1352         PropertyRNA *prop;
1353 } RNAUpdateCb;
1354
1355 static void rna_update_cb(bContext *C, void *arg_cb, void *arg_unused)
1356 {
1357         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
1358
1359         /* we call update here on the pointer property, this way the
1360            owner of the curve mapping can still define it's own update
1361            and notifier, even if the CurveMapping struct is shared. */
1362         RNA_property_update(C, &cb->ptr, cb->prop);
1363 }
1364
1365 #define B_BANDCOL 1
1366
1367 static int vergcband(const void *a1, const void *a2)
1368 {
1369         const CBData *x1=a1, *x2=a2;
1370
1371         if( x1->pos > x2->pos ) return 1;
1372         else if( x1->pos < x2->pos) return -1;
1373         return 0;
1374 }
1375
1376 static void colorband_pos_cb(bContext *C, void *cb_v, void *coba_v)
1377 {
1378         ColorBand *coba= coba_v;
1379         int a;
1380
1381         if(coba->tot<2) return;
1382
1383         for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
1384         qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
1385         for(a=0; a<coba->tot; a++) {
1386                 if(coba->data[a].cur==coba->cur) {
1387                         coba->cur= a;
1388                         break;
1389                 }
1390         }
1391
1392         rna_update_cb(C, cb_v, NULL);
1393 }
1394
1395 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
1396 {
1397         ColorBand *coba= coba_v;
1398
1399         if(coba->tot < MAXCOLORBAND-1) coba->tot++;
1400         coba->cur= coba->tot-1;
1401
1402         colorband_pos_cb(C, cb_v, coba_v);
1403
1404         ED_undo_push(C, "Add colorband");
1405 }
1406
1407 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
1408 {
1409         ColorBand *coba= coba_v;
1410         int a;
1411
1412         if(coba->tot<2) return;
1413
1414         for(a=coba->cur; a<coba->tot; a++) {
1415                 coba->data[a]= coba->data[a+1];
1416         }
1417         if(coba->cur) coba->cur--;
1418         coba->tot--;
1419
1420         ED_undo_push(C, "Delete colorband");
1421
1422         rna_update_cb(C, cb_v, NULL);
1423 }
1424
1425
1426 /* offset aligns from bottom, standard width 300, height 115 */
1427 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1428 {
1429         
1430         uiBut *bt;
1431
1432         if(coba==NULL) return;
1433
1434         bt= uiDefBut(block, BUT, 0,     "Add",                  0+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Add a new color stop to the colorband");
1435         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1436
1437         bt= uiDefBut(block, BUT, 0,     "Delete",               60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position");
1438         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1439
1440         uiDefButS(block, NUM, 0,                "",                             120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop");
1441
1442         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1443                         210+xoffs, 100+yoffs, 90, 20,           &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1444         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1445         uiBlockEndAlign(block);
1446
1447         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, "");
1448         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1449
1450         if(coba->tot) {
1451                 CBData *cbd= coba->data + coba->cur;
1452
1453                 /* better to use rna so we can animate them */
1454                 PointerRNA ptr;
1455                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1456                 uiItemR(layout, NULL, 0, &ptr, "color", 0);
1457                 //uiItemR(layout, NULL, 0, &ptr, "position", 0);
1458                 bt= uiDefButF(block, NUM, 0, "Pos:",                    0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop");
1459                 uiButSetNFunc(bt, colorband_pos_cb, MEM_dupallocN(cb), coba);
1460         }
1461
1462 }
1463
1464 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1465 {
1466         uiBut *bt;
1467         float unit= (butr->xmax-butr->xmin)/14.0f;
1468         float xs= butr->xmin;
1469
1470
1471         bt= uiDefBut(block, BUT, 0,     "Add",                  xs,butr->ymin+20.0f,2.0f*unit,20,       NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1472         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1473         bt= uiDefBut(block, BUT, 0,     "Delete",               xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20,     NULL, 0, 0, 0, 0, "Delete the active position");
1474         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1475
1476         if(coba->tot) {
1477                 CBData *cbd= coba->data + coba->cur;
1478                 PointerRNA ptr;
1479                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1480                 uiItemR(layout, "", 0, &ptr, "color", 0);
1481         }
1482
1483         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1484                         xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20,            &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1485         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1486
1487         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, "");
1488         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1489
1490         uiBlockEndAlign(block);
1491 }
1492
1493 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1494 {
1495         if(small)
1496                 colorband_buttons_small(layout, block, coba, butr, cb);
1497         else
1498                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1499 }
1500
1501 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, char *propname, int expand)
1502 {
1503         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1504         PointerRNA cptr;
1505         RNAUpdateCb *cb;
1506         uiBlock *block;
1507         rctf rect;
1508
1509         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1510                 return;
1511
1512         cptr= RNA_property_pointer_get(ptr, prop);
1513         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1514                 return;
1515
1516         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1517         cb->ptr= *ptr;
1518         cb->prop= prop;
1519
1520         rect.xmin= 0; rect.xmax= 200;
1521         rect.ymin= 0; rect.ymax= 190;
1522
1523         block= uiLayoutAbsoluteBlock(layout);
1524         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1525
1526         MEM_freeN(cb);
1527 }
1528
1529 /********************* CurveMapping Template ************************/
1530
1531 #include "DNA_color_types.h"
1532 #include "BKE_colortools.h"
1533
1534 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *unused)
1535 {
1536         CurveMapping *cumap = cumap_v;
1537         float d;
1538
1539         /* we allow 20 times zoom */
1540         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1541                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1542                 cumap->curr.xmin+= d;
1543                 cumap->curr.xmax-= d;
1544                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1545                 cumap->curr.ymin+= d;
1546                 cumap->curr.ymax-= d;
1547         }
1548
1549         ED_region_tag_redraw(CTX_wm_region(C));
1550 }
1551
1552 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *unused)
1553 {
1554         CurveMapping *cumap = cumap_v;
1555         float d, d1;
1556
1557         /* we allow 20 times zoom, but dont view outside clip */
1558         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1559                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1560
1561                 if(cumap->flag & CUMA_DO_CLIP) 
1562                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1563                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1564                 cumap->curr.xmin-= d1;
1565
1566                 d1= d;
1567                 if(cumap->flag & CUMA_DO_CLIP) 
1568                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1569                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1570                 cumap->curr.xmax+= d1;
1571
1572                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1573
1574                 if(cumap->flag & CUMA_DO_CLIP) 
1575                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1576                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1577                 cumap->curr.ymin-= d1;
1578
1579                 d1= d;
1580                 if(cumap->flag & CUMA_DO_CLIP) 
1581                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1582                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1583                 cumap->curr.ymax+= d1;
1584         }
1585
1586         ED_region_tag_redraw(CTX_wm_region(C));
1587 }
1588
1589 static void curvemap_buttons_setclip(bContext *C, void *cumap_v, void *unused)
1590 {
1591         CurveMapping *cumap = cumap_v;
1592
1593         curvemapping_changed(cumap, 0);
1594 }       
1595
1596 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1597 {
1598         CurveMapping *cumap = cumap_v;
1599
1600         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1601         curvemapping_changed(cumap, 0);
1602
1603         rna_update_cb(C, cb_v, NULL);
1604 }
1605
1606 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1607 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1608 {
1609         CurveMapping *cumap = cumap_v;
1610         uiBlock *block;
1611         uiBut *bt;
1612
1613         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
1614
1615         /* use this for a fake extra empy space around the buttons */
1616         uiDefBut(block, LABEL, 0, "",                   -4, 16, 128, 106, NULL, 0, 0, 0, 0, "");
1617
1618         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1619                         0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, "");
1620         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1621
1622         uiBlockBeginAlign(block);
1623         uiDefButF(block, NUM, 0, "Min X ",       0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
1624         uiDefButF(block, NUM, 0, "Min Y ",       0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
1625         uiDefButF(block, NUM, 0, "Max X ",       0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
1626         uiDefButF(block, NUM, 0, "Max Y ",       0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
1627
1628         uiBlockSetDirection(block, UI_RIGHT);
1629
1630         uiEndBlock(C, block);
1631         return block;
1632 }
1633
1634 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1635 {
1636         CurveMapping *cumap = cumap_v;
1637         CurveMap *cuma= cumap->cm+cumap->cur;
1638
1639         switch(event) {
1640                 case 0: /* reset */
1641                         curvemap_reset(cuma, &cumap->clipr, CURVE_PRESET_LINE);
1642                         curvemapping_changed(cumap, 0);
1643                         break;
1644                 case 1:
1645                         cumap->curr= cumap->clipr;
1646                         break;
1647                 case 2: /* set vector */
1648                         curvemap_sethandle(cuma, 1);
1649                         curvemapping_changed(cumap, 0);
1650                         break;
1651                 case 3: /* set auto */
1652                         curvemap_sethandle(cuma, 0);
1653                         curvemapping_changed(cumap, 0);
1654                         break;
1655                 case 4: /* extend horiz */
1656                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1657                         curvemapping_changed(cumap, 0);
1658                         break;
1659                 case 5: /* extend extrapolate */
1660                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1661                         curvemapping_changed(cumap, 0);
1662                         break;
1663                 case 6: /* reset smooth */
1664                         curvemap_reset(cuma, &cumap->clipr, CURVE_PRESET_SMOOTH);
1665                         curvemapping_changed(cumap, 0);
1666                         break;
1667         }
1668         ED_region_tag_redraw(CTX_wm_region(C));
1669 }
1670
1671 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1672 {
1673         uiBlock *block;
1674         short yco= 0, menuwidth=120;
1675
1676         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1677         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1678
1679         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1680         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1681         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1682         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
1683         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
1684         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
1685
1686         uiBlockSetDirection(block, UI_RIGHT);
1687         uiTextBoundsBlock(block, 50);
1688
1689         uiEndBlock(C, block);
1690         return block;
1691 }
1692
1693 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1694 {
1695         uiBlock *block;
1696         short yco= 0, menuwidth=120;
1697
1698         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1699         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1700
1701         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1702         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1703         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1704         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
1705
1706         uiBlockSetDirection(block, UI_RIGHT);
1707         uiTextBoundsBlock(block, 50);
1708
1709         uiEndBlock(C, block);
1710         return block;
1711 }
1712
1713 static void curvemap_buttons_redraw(bContext *C, void *arg1, void *arg2)
1714 {
1715         ED_region_tag_redraw(CTX_wm_region(C));
1716 }
1717
1718 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1719 {
1720         CurveMapping *cumap = cumap_v;
1721         int a;
1722         
1723         for(a=0; a<CM_TOT; a++)
1724                 curvemap_reset(cumap->cm+a, &cumap->clipr, CURVE_PRESET_LINE);
1725         
1726         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1727         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1728         curvemapping_set_black_white(cumap, NULL, NULL);
1729         
1730         curvemapping_changed(cumap, 0);
1731
1732         rna_update_cb(C, cb_v, NULL);
1733 }
1734
1735 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1736 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1737 {
1738         CurveMapping *cumap= ptr->data;
1739         uiLayout *row, *sub, *split;
1740         uiBlock *block;
1741         uiBut *bt;
1742         float dx= UI_UNIT_X;
1743         int icon, size;
1744
1745         block= uiLayoutGetBlock(layout);
1746
1747         /* curve chooser */
1748         row= uiLayoutRow(layout, 0);
1749
1750         if(labeltype=='v') {
1751                 /* vector */
1752                 sub= uiLayoutRow(row, 1);
1753                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1754
1755                 if(cumap->cm[0].curve) {
1756                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1757                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1758                 }
1759                 if(cumap->cm[1].curve) {
1760                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1761                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1762                 }
1763                 if(cumap->cm[2].curve) {
1764                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1765                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1766                 }
1767         }
1768         else if(labeltype=='c') {
1769                 /* color */
1770                 sub= uiLayoutRow(row, 1);
1771                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1772
1773                 if(cumap->cm[3].curve) {
1774                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1775                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1776                 }
1777                 if(cumap->cm[0].curve) {
1778                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1779                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1780                 }
1781                 if(cumap->cm[1].curve) {
1782                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1783                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1784                 }
1785                 if(cumap->cm[2].curve) {
1786                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1787                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1788                 }
1789         }
1790         else
1791                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1792
1793         /* operation buttons */
1794         sub= uiLayoutRow(row, 1);
1795
1796         uiBlockSetEmboss(block, UI_EMBOSSN);
1797
1798         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
1799         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1800
1801         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
1802         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1803
1804         if(brush)
1805                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1806         else
1807                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1808
1809         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1810
1811         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1812         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, 18, "Clipping Options");
1813         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1814
1815         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
1816         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1817
1818         uiBlockSetEmboss(block, UI_EMBOSS);
1819
1820         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1821
1822         /* curve itself */
1823         size= uiLayoutGetWidth(layout);
1824         row= uiLayoutRow(layout, 0);
1825         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, 0, 0, "");
1826
1827         /* black/white levels */
1828         if(levels) {
1829                 split= uiLayoutSplit(layout, 0, 0);
1830                 uiItemR(uiLayoutColumn(split, 0), NULL, 0, ptr, "black_level", UI_ITEM_R_EXPAND);
1831                 uiItemR(uiLayoutColumn(split, 0), NULL, 0, ptr, "white_level", UI_ITEM_R_EXPAND);
1832
1833                 uiLayoutRow(layout, 0);
1834                 bt=uiDefBut(block, BUT, 0, "Reset",     0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves");
1835                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1836         }
1837
1838         uiBlockSetNFunc(block, NULL, NULL, NULL);
1839 }
1840
1841 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, char *propname, int type, int levels, int brush)
1842 {
1843         RNAUpdateCb *cb;
1844         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1845         PointerRNA cptr;
1846
1847         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1848                 return;
1849
1850         cptr= RNA_property_pointer_get(ptr, prop);
1851         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1852                 return;
1853
1854         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1855         cb->ptr= *ptr;
1856         cb->prop= prop;
1857
1858         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1859
1860         MEM_freeN(cb);
1861 }
1862
1863 /********************* ColorWheel Template ************************/
1864
1865 #define WHEEL_SIZE      100
1866
1867 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, char *propname, int value_slider)
1868 {
1869         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1870         uiBlock *block= uiLayoutGetBlock(layout);
1871         uiLayout *col, *row;
1872         uiBut *but;
1873         
1874         if (!prop) {
1875                 printf("uiTemplateColorWheel: property not found: %s\n", propname);
1876                 return;
1877         }
1878         
1879         col = uiLayoutColumn(layout, 0);
1880         row= uiLayoutRow(col, 1);
1881         
1882         uiDefButR(block, HSVCIRCLE, 0, "",      0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, propname, -1, 0.0, 0.0, 0, 0, "");
1883         
1884         uiItemS(row);
1885         
1886         if (value_slider)
1887                 uiDefButR(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, propname, -1, 0.0, 0.0, 9, 0, "");
1888
1889         /* maybe a switch for this?
1890         row= uiLayoutRow(col, 0);
1891         if(ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA) && RNA_property_array_length(ptr, prop) == 4) {
1892                 but= uiDefAutoButR(block, ptr, prop, 3, "A:", 0, 0, 0, WHEEL_SIZE+20, UI_UNIT_Y);
1893         }
1894         */
1895         
1896 }
1897
1898
1899 /********************* TriColor (ThemeWireColorSet) Template ************************/
1900
1901 void uiTemplateTriColorSet(uiLayout *layout, PointerRNA *ptr, char *propname)
1902 {
1903         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1904         uiLayout *row;
1905         PointerRNA csPtr;
1906
1907         if (!prop) {
1908                 printf("uiTemplateTriColorSet: property not found: %s\n", propname);
1909                 return;
1910         }
1911         
1912         /* we lay out the data in a row as 3 color swatches */
1913         row= uiLayoutRow(layout, 1);
1914         
1915         /* nselected, selected, active color swatches */
1916         csPtr= RNA_property_pointer_get(ptr, prop);
1917         
1918         uiItemR(row, "", 0, &csPtr, "normal", 0);
1919         uiItemR(row, "", 0, &csPtr, "selected", 0);
1920         uiItemR(row, "", 0, &csPtr, "active", 0);
1921 }
1922
1923 /********************* Layer Buttons Template ************************/
1924
1925 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
1926 {
1927         uiBut *but = arg1;
1928         int cur = GET_INT_FROM_POINTER(arg2);
1929         wmWindow *win= CTX_wm_window(C);
1930         int i, tot, shift= win->eventstate->shift;
1931
1932         if(!shift) {
1933                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
1934                 
1935                 /* Normally clicking only selects one layer */
1936                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
1937                 for(i = 0; i < tot; ++i) {
1938                         if(i != cur)
1939                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
1940                 }
1941         }
1942 }
1943
1944 // TODO:
1945 //      - for now, grouping of layers is determined by dividing up the length of 
1946 //        the array of layer bitflags
1947
1948 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, char *propname,
1949                       PointerRNA *used_ptr, char *used_propname, int active_layer)
1950 {
1951         uiLayout *uRow, *uCol;
1952         PropertyRNA *prop, *used_prop= NULL;
1953         int groups, cols, layers;
1954         int group, col, layer, row;
1955         int cols_per_group = 5;
1956         const char *desc;
1957         
1958         prop= RNA_struct_find_property(ptr, propname);
1959         if (!prop) {
1960                 printf("uiTemplateLayer: layers property not found: %s\n", propname);
1961                 return;
1962         }
1963
1964         desc= RNA_property_description(prop);
1965         
1966         /* the number of layers determines the way we group them 
1967          *      - we want 2 rows only (for now)
1968          *      - the number of columns (cols) is the total number of buttons per row
1969          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
1970          *      - for now, only split into groups if group will have at least 5 items
1971          */
1972         layers= RNA_property_array_length(ptr, prop);
1973         cols= (layers / 2) + (layers % 2);
1974         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
1975
1976         if(used_ptr && used_propname) {
1977                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
1978                 if (!used_prop) {
1979                         printf("uiTemplateLayer: used layers property not found: %s\n", used_propname);
1980                         return;
1981                 }
1982
1983                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
1984                         used_prop = NULL;
1985         }
1986         
1987         /* layers are laid out going across rows, with the columns being divided into groups */
1988         
1989         for (group= 0; group < groups; group++) {
1990                 uCol= uiLayoutColumn(layout, 1);
1991                 
1992                 for (row= 0; row < 2; row++) {
1993                         uiBlock *block;
1994                         uiBut *but;
1995
1996                         uRow= uiLayoutRow(uCol, 1);
1997                         block= uiLayoutGetBlock(uRow);
1998                         layer= groups*cols_per_group*row + cols_per_group*group;
1999                         
2000                         /* add layers as toggle buts */
2001                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
2002                                 int icon = 0;
2003                                 int butlay = 1 << layer;
2004
2005                                 if(active_layer & butlay)
2006                                         icon = ICON_LAYER_ACTIVE;
2007                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
2008                                         icon = ICON_LAYER_USED;
2009                                 
2010                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, 10, 10);
2011                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2012                                 but->type= TOG;
2013                         }
2014                 }
2015         }
2016 }
2017
2018
2019 /************************* List Template **************************/
2020
2021 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon)
2022 {
2023         ID *id= NULL;
2024         int icon;
2025
2026         if(!itemptr->data)
2027                 return rnaicon;
2028
2029         /* try ID, material or texture slot */
2030         if(RNA_struct_is_ID(itemptr->type)) {
2031                 id= itemptr->id.data;
2032         }
2033         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2034                 id= RNA_pointer_get(itemptr, "material").data;
2035         }
2036         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2037                 id= RNA_pointer_get(itemptr, "texture").data;
2038         }
2039
2040         /* get icon from ID */
2041         if(id) {
2042                 icon= ui_id_icon_get(C, id, 1);
2043
2044                 if(icon)
2045                         return icon;
2046         }
2047
2048         return rnaicon;
2049 }
2050
2051 static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, char *activepropname)
2052 {
2053         Object *ob;
2054         uiBlock *block= uiLayoutGetBlock(layout);
2055         uiBut *but;
2056         uiLayout *split, *overlap, *sub, *row;
2057         char *name, *namebuf;
2058         int icon;
2059
2060         overlap= uiLayoutOverlap(layout);
2061
2062         /* list item behind label & other buttons */
2063         sub= uiLayoutRow(overlap, 0);
2064
2065         if(itemptr->type == &RNA_ShapeKey) {
2066                 ob= (Object*)activeptr->data;
2067                 if(ob->mode == OB_MODE_EDIT && !(ob->type == OB_MESH))
2068                         uiLayoutSetEnabled(sub, 0);
2069         }
2070
2071         but= uiDefButR(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2072         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2073
2074         sub= uiLayoutRow(overlap, 0);
2075
2076         /* retrieve icon and name */
2077         icon= list_item_icon_get(C, itemptr, rnaicon);
2078         if(!icon || icon == ICON_DOT)
2079                 icon= 0;
2080
2081         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0);
2082         name= (namebuf)? namebuf: "";
2083
2084         /* hardcoded types */
2085         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
2086                 uiItemL(sub, name, icon);
2087                 uiBlockSetEmboss(block, UI_EMBOSSN);
2088                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2089                 uiBlockSetEmboss(block, UI_EMBOSS);
2090         }
2091         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2092                 uiItemL(sub, name, icon);
2093                 uiBlockSetEmboss(block, UI_EMBOSS);
2094                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2095         }
2096         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2097                 uiItemL(sub, name, icon);
2098                 uiBlockSetEmboss(block, UI_EMBOSS);
2099                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "enabled", 0, 0, 0, 0, 0,  NULL);
2100         }
2101         else if(itemptr->type == &RNA_ShapeKey) {
2102                 ob= (Object*)activeptr->data;
2103
2104                 split= uiLayoutSplit(sub, 0.75f, 0);
2105
2106                 uiItemL(split, name, icon);
2107
2108                 uiBlockSetEmboss(block, UI_EMBOSSN);
2109                 row= uiLayoutRow(split, 1);
2110                 if(i == 0) uiItemL(row, "", 0);
2111                 else uiItemR(row, "", 0, itemptr, "value", 0);
2112
2113                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2114                         uiLayoutSetActive(row, 0);
2115                 //uiItemR(row, "", ICON_MUTE_IPO_OFF, itemptr, "mute", 0);
2116                 uiBlockSetEmboss(block, UI_EMBOSS);
2117         }
2118         else
2119                 uiItemL(sub, name, icon);
2120
2121         /* free name */
2122         if(namebuf)
2123                 MEM_freeN(namebuf);
2124 }
2125
2126 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, PointerRNA *activeptr, char *activepropname, int rows, int maxrows, int listtype)
2127 {
2128         //Scene *scene= CTX_data_scene(C);
2129         PropertyRNA *prop= NULL, *activeprop;
2130         PropertyType type, activetype;
2131         StructRNA *ptype;
2132         uiLayout *box, *row, *col;
2133         uiBlock *block;
2134         uiBut *but;
2135         Panel *pa;
2136         char *name, str[32];
2137         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2138
2139         /* validate arguments */
2140         block= uiLayoutGetBlock(layout);
2141         pa= block->panel;
2142
2143         if(!pa) {
2144                 printf("uiTemplateList: only works inside a panel.\n");
2145                 return;
2146         }
2147
2148         if(!activeptr->data)
2149                 return;
2150         
2151         if(ptr->data) {
2152                 prop= RNA_struct_find_property(ptr, propname);
2153                 if(!prop) {
2154                         printf("uiTemplateList: property not found: %s\n", propname);
2155                         return;
2156                 }
2157         }
2158
2159         activeprop= RNA_struct_find_property(activeptr, activepropname);
2160         if(!activeprop) {
2161                 printf("uiTemplateList: property not found: %s\n", activepropname);
2162                 return;
2163         }
2164
2165         if(prop) {
2166                 type= RNA_property_type(prop);
2167                 if(type != PROP_COLLECTION) {
2168                         printf("uiTemplateList: expected collection property.\n");
2169                         return;
2170                 }
2171         }
2172
2173         activetype= RNA_property_type(activeprop);
2174         if(activetype != PROP_INT) {
2175                 printf("uiTemplateList: expected integer property.\n");
2176                 return;
2177         }
2178
2179         /* get icon */
2180         if(ptr->data && prop) {
2181                 ptype= RNA_property_pointer_type(ptr, prop);
2182                 rnaicon= RNA_struct_ui_icon(ptype);
2183         }
2184
2185         /* get active data */
2186         activei= RNA_property_int_get(activeptr, activeprop);
2187
2188         if(listtype == 'i') {
2189                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2190                 col= uiLayoutColumn(box, 1);
2191                 row= uiLayoutRow(col, 0);
2192
2193                 if(ptr->data && prop) {
2194                         /* create list items */
2195                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2196                                 /* create button */
2197                                 if(i == 9)
2198                                         row= uiLayoutRow(col, 0);
2199
2200                                 icon= list_item_icon_get(C, &itemptr, rnaicon);
2201                                 but= uiDefIconButR(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2202                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2203
2204                                 i++;
2205                         }
2206                         RNA_PROP_END;
2207                 }
2208         }
2209         else if(listtype == 'c') {
2210                 /* compact layout */
2211                 found= 0;
2212
2213                 row= uiLayoutRow(layout, 1);
2214
2215                 if(ptr->data && prop) {
2216                         /* create list items */
2217                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2218                                 found= (activei == i);
2219
2220                                 if(found) {
2221                                         /* create button */
2222                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
2223                                         icon= list_item_icon_get(C, &itemptr, rnaicon);
2224                                         uiItemL(row, (name)? name: "", icon);
2225
2226                                         if(name)
2227                                                 MEM_freeN(name);
2228                                 }
2229
2230                                 i++;
2231                         }
2232                         RNA_PROP_END;
2233                 }
2234
2235                 /* if not found, add in dummy button */
2236                 if(i == 0)
2237                         uiItemL(row, "", 0);
2238
2239                 /* next/prev button */
2240                 sprintf(str, "%d :", i);
2241                 but= uiDefIconTextButR(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activepropname, 0, 0, 0, 0, 0, "");
2242                 if(i == 0)
2243                         uiButSetFlag(but, UI_BUT_DISABLED);
2244         }
2245         else {
2246                 /* default rows */
2247                 if(rows == 0)
2248                         rows= 5;
2249                 if (maxrows == 0)
2250                         maxrows = 5;
2251                 if(pa->list_grip_size != 0)
2252                         rows= pa->list_grip_size;
2253
2254                 /* layout */
2255                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2256                 row= uiLayoutRow(box, 0);
2257                 col = uiLayoutColumn(row, 1);
2258
2259                 /* init numbers */
2260                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2261
2262                 if(prop)
2263                         len= RNA_property_collection_length(ptr, prop);
2264                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2265
2266                 /* if list length changes and active is out of view, scroll to it */
2267                 if(pa->list_last_len != len)
2268                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2269                                 pa->list_scroll= activei;
2270
2271                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2272                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2273                 pa->list_size= items;
2274                 pa->list_last_len= len;
2275
2276                 if(ptr->data && prop) {
2277                         /* create list items */
2278                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2279                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2280                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activepropname);
2281
2282                                 i++;
2283                         }
2284                         RNA_PROP_END;
2285                 }
2286
2287                 /* add dummy buttons to fill space */
2288                 while(i < pa->list_scroll+items) {
2289                         if(i >= pa->list_scroll)
2290                                 uiItemL(col, "", 0);
2291                         i++;
2292                 }
2293
2294                 /* add scrollbar */
2295                 if(len > items) {
2296                         col= uiLayoutColumn(row, 0);
2297                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2298                 }
2299         }
2300 }
2301
2302 /************************* Operator Search Template **************************/
2303
2304 static void operator_call_cb(bContext *C, void *arg1, void *arg2)
2305 {
2306         wmOperatorType *ot= arg2;
2307         
2308         if(ot)
2309                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2310 }
2311
2312 static void operator_search_cb(const bContext *C, void *arg, char *str, uiSearchItems *items)
2313 {
2314         wmOperatorType *ot = WM_operatortype_first();
2315         
2316         for(; ot; ot= ot->next) {
2317                 
2318                 if(BLI_strcasestr(ot->name, str)) {
2319                         if(WM_operator_poll((bContext*)C, ot)) {
2320                                 char name[256];
2321                                 int len= strlen(ot->name);
2322                                 
2323                                 /* display name for menu, can hold hotkey */
2324                                 BLI_strncpy(name, ot->name, 256);
2325                                 
2326                                 /* check for hotkey */
2327                                 if(len < 256-6) {
2328                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
2329                                                 name[len]= '|';
2330                                 }
2331                                 
2332                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2333                                         break;
2334                         }
2335                 }
2336         }
2337 }
2338
2339 void uiTemplateOperatorSearch(uiLayout *layout)
2340 {
2341         uiBlock *block;
2342         uiBut *but;
2343         static char search[256]= "";
2344                 
2345         block= uiLayoutGetBlock(layout);
2346         uiBlockSetCurLayout(block, layout);
2347
2348         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2349         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2350 }
2351
2352 /************************* Running Jobs Template **************************/
2353
2354 #define B_STOPRENDER    1
2355 #define B_STOPCAST              2
2356 #define B_STOPANIM              3
2357
2358 static void do_running_jobs(bContext *C, void *arg, int event)
2359 {
2360         switch(event) {
2361                 case B_STOPRENDER:
2362                         G.afbreek= 1;
2363                         break;
2364                 case B_STOPCAST:
2365                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C));
2366                         break;
2367                 case B_STOPANIM:
2368                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2369                         break;
2370         }
2371 }
2372
2373 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2374 {
2375         bScreen *screen= CTX_wm_screen(C);
2376         Scene *scene= CTX_data_scene(C);
2377         wmWindowManager *wm= CTX_wm_manager(C);
2378         uiBlock *block;
2379
2380         block= uiLayoutGetBlock(layout);
2381         uiBlockSetCurLayout(block, layout);
2382
2383         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2384
2385         if(WM_jobs_test(wm, scene))
2386                 uiDefIconTextBut(block, BUT, B_STOPRENDER, ICON_CANCEL, "Render", 0,0,75,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop rendering");
2387         if(WM_jobs_test(wm, screen))
2388                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
2389         if(screen->animtimer)
2390                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, "Anim Player", 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
2391 }
2392
2393