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