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