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