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