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