Merged changes in the trunk up to revision 36408.
[blender.git] / source / blender / editors / interface / interface_templates.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/interface/interface_templates.c
26  *  \ingroup edinterface
27  */
28
29
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_scene_types.h"
37 #include "DNA_userdef_types.h"
38
39 #include "BLI_string.h"
40 #include "BLI_utildefines.h"
41
42 #include "BKE_animsys.h"
43 #include "BKE_colortools.h"
44 #include "BKE_context.h"
45 #include "BKE_global.h"
46 #include "BKE_library.h"
47 #include "BKE_main.h"
48 #include "BKE_object.h"
49 #include "BKE_material.h"
50 #include "BKE_texture.h"
51 #include "BKE_report.h"
52 #include "BKE_displist.h"
53
54 #include "ED_screen.h"
55 #include "ED_render.h"
56
57 #include "RNA_access.h"
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 #include "UI_interface.h"
63 #include "interface_intern.h"
64
65 #include "BLF_api.h"
66
67 void UI_template_fix_linking(void)
68 {
69 }
70
71 /********************** Header Template *************************/
72
73 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
74 {
75         uiBlock *block;
76
77         block= uiLayoutAbsoluteBlock(layout);
78         if(menus) ED_area_header_standardbuttons(C, block, 0);
79         else ED_area_header_switchbutton(C, block, 0);
80 }
81
82 /********************** Search Callbacks *************************/
83
84 typedef struct TemplateID {
85         PointerRNA ptr;
86         PropertyRNA *prop;
87
88         ListBase *idlb;
89         int prv_rows, prv_cols;
90 } TemplateID;
91
92 /* Search browse menu, assign  */
93 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
94 {
95         TemplateID *template= (TemplateID*)arg_template;
96
97         /* ID */
98         if(item) {
99                 PointerRNA idptr;
100
101                 RNA_id_pointer_create(item, &idptr);
102                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
103                 RNA_property_update(C, &template->ptr, template->prop);
104         }
105 }
106
107 /* ID Search browse menu, do the search */
108 static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
109 {
110         TemplateID *template= (TemplateID*)arg_template;
111         ListBase *lb= template->idlb;
112         ID *id, *id_from= template->ptr.id.data;
113         int iconid;
114         int flag= RNA_property_flag(template->prop);
115
116         /* ID listbase */
117         for(id= lb->first; id; id= id->next) {
118                 if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
119
120                         /* use filter */
121                         if(RNA_property_type(template->prop)==PROP_POINTER) {
122                                 PointerRNA ptr;
123                                 RNA_id_pointer_create(id, &ptr);
124                                 if(RNA_property_pointer_poll(&template->ptr, template->prop, &ptr)==0)
125                                         continue;
126                         }
127
128                         /* hide dot-datablocks, but only if filter does not force it visible */
129                         if(U.uiflag & USER_HIDE_DOT)
130                                 if ((id->name[2]=='.') && (str[0] != '.'))
131                                         continue;
132
133                         if(BLI_strcasestr(id->name+2, str)) {
134                                 char name_ui[32];
135                                 name_uiprefix_id(name_ui, id);
136
137                                 iconid= ui_id_icon_get((bContext*)C, id, 1);
138
139                                 if(!uiSearchItemAdd(items, name_ui, id, iconid))
140                                         break;
141                         }
142                 }
143         }
144 }
145
146 /* ID Search browse menu, open */
147 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
148 {
149         static char search[256];
150         static TemplateID template;
151         PointerRNA idptr;
152         wmWindow *win= CTX_wm_window(C);
153         uiBlock *block;
154         uiBut *but;
155         
156         /* clear initial search string, then all items show */
157         search[0]= 0;
158         /* arg_litem is malloced, can be freed by parent button */
159         template= *((TemplateID*)arg_litem);
160         
161         /* get active id for showing first item */
162         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
163
164         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
165         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
166         
167         /* preview thumbnails */
168         if (template.prv_rows > 0 && template.prv_cols > 0) {
169                 int w = 96 * template.prv_cols;
170                 int h = 96 * template.prv_rows + 20;
171                 
172                 /* fake button, it holds space for search items */
173                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
174                 
175                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
176                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
177         }
178         /* list view */
179         else {
180                 /* fake button, it holds space for search items */
181                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
182                 
183                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
184                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
185         }
186                 
187         
188         uiBoundsBlock(block, 6);
189         uiBlockSetDirection(block, UI_DOWN);    
190         uiEndBlock(C, block);
191         
192         /* give search-field focus */
193         uiButSetFocusOnEnter(win, but);
194         /* this type of search menu requires undo */
195         but->flag |= UI_BUT_UNDO;
196         
197         return block;
198 }
199
200 /************************ ID Template ***************************/
201 /* This is for browsing and editing the ID-blocks used */
202
203 /* for new/open operators */
204 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
205 {
206         TemplateID *template;
207         ARegion *ar= CTX_wm_region(C);
208         uiBlock *block;
209         uiBut *but;
210
211         memset(ptr, 0, sizeof(*ptr));
212         *prop= NULL;
213
214         if(!ar)
215                 return;
216
217         for(block=ar->uiblocks.first; block; block=block->next) {
218                 for(but=block->buttons.first; but; but= but->next) {
219                         /* find the button before the active one */
220                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
221                                 if(but->func_argN) {
222                                         template= but->func_argN;
223                                         *ptr= template->ptr;
224                                         *prop= template->prop;
225                                         return;
226                                 }
227                         }
228                 }
229         }
230 }
231
232
233 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
234 {
235         TemplateID *template= (TemplateID*)arg_litem;
236         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
237         ID *id= idptr.data, *newid;
238         int event= GET_INT_FROM_POINTER(arg_event);
239         
240         switch(event) {
241                 case UI_ID_BROWSE:
242                 case UI_ID_PIN:
243                         RNA_warning("warning, id event %d shouldnt come here\n", event);
244                         break;
245                 case UI_ID_OPEN:
246                 case UI_ID_ADD_NEW:
247                         /* these call uiIDContextPropertySet */
248                         break;
249                 case UI_ID_DELETE:
250                         memset(&idptr, 0, sizeof(idptr));
251                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
252                         RNA_property_update(C, &template->ptr, template->prop);
253
254                         if(id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
255                                 id->us= 0;
256
257                         break;
258                 case UI_ID_FAKE_USER:
259                         if(id) {
260                                 if(id->flag & LIB_FAKEUSER) id_us_plus(id);
261                                 else id_us_min(id);
262                         }
263                         else return;
264                         break;
265                 case UI_ID_LOCAL:
266                         if(id) {
267                                 if(id_make_local(id, 0)) {
268                                         /* reassign to get get proper updates/notifiers */
269                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
270                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
271                                         RNA_property_update(C, &template->ptr, template->prop);
272                                 }
273                         }
274                         break;
275                 case UI_ID_ALONE:
276                         if(id) {
277                                 /* make copy */
278                                 if(id_copy(id, &newid, 0) && newid) {
279                                         /* copy animation actions too */
280                                         BKE_copy_animdata_id_action(id);
281                                         /* us is 1 by convention, but RNA_property_pointer_set
282                                            will also incremement it, so set it to zero */
283                                         newid->us= 0;
284
285                                         /* assign copy */
286                                         RNA_id_pointer_create(newid, &idptr);
287                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
288                                         RNA_property_update(C, &template->ptr, template->prop);
289                                 }
290                         }
291                         break;
292 #if 0
293                 case UI_ID_AUTO_NAME:
294                         break;
295 #endif
296         }
297 }
298
299 static const char *template_id_browse_tip(StructRNA *type)
300 {
301         if(type) {
302                 switch(RNA_type_to_ID_code(type)) {
303                         case ID_SCE: return "Browse Scene to be linked";
304                         case ID_OB: return "Browse Object to be linked";
305                         case ID_ME: return "Browse Mesh Data to be linked";
306                         case ID_CU: return "Browse Curve Data to be linked";
307                         case ID_MB: return "Browse MetaBall Data to be linked";
308                         case ID_MA: return "Browse Material to be linked";
309                         case ID_TE: return "Browse Texture to be linked";
310                         case ID_IM: return "Browse Image to be linked";
311                         case ID_LA: return "Browse Lattice Data to be linked";
312                         case ID_CA: return "Browse Camera Data to be linked";
313                         case ID_WO: return "Browse World Settings to be linked";
314                         case ID_SCR: return "Choose Screen lay-out";
315                         case ID_TXT: return "Browse Text to be linked";
316                         case ID_SO: return "Browse Sound to be linked";
317                         case ID_AR: return "Browse Armature data to be linked";
318                         case ID_AC: return "Browse Action to be linked";
319                         case ID_NT: return "Browse Node Tree to be linked";
320                         case ID_BR: return "Browse Brush to be linked";
321                         case ID_PA: return "Browse Particle System to be linked";
322                         case ID_GD: return "Browse Grease Pencil Data to be linked";
323                 }
324         }
325         return "Browse ID data to be linked";
326 }
327
328 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop)
329 {
330         uiBut *but;
331         uiBlock *block;
332         PointerRNA idptr;
333         // ListBase *lb; // UNUSED
334         ID *id, *idfrom;
335
336         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
337         id= idptr.data;
338         idfrom= template->ptr.id.data;
339         // lb= template->idlb;
340
341         block= uiLayoutGetBlock(layout);
342         uiBlockBeginAlign(block);
343
344         if(idptr.type)
345                 type= idptr.type;
346
347         if(flag & UI_ID_PREVIEWS) {
348
349                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, template_id_browse_tip(type));
350                 if(type) {
351                         but->icon= RNA_struct_ui_icon(type);
352                         if (id) but->icon = ui_id_icon_get(C, id, 1);
353                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
354                 }
355                 if((idfrom && idfrom->lib))
356                         uiButSetFlag(but, UI_BUT_DISABLED);
357                 
358                 
359                 uiLayoutRow(layout, 1);
360         } else 
361                 
362         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))
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))
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))
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))
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 gets not 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))
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, 16, 20, &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, 16, 20, &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         
1286         uiBut *bt;
1287         uiLayout *row;
1288
1289         if(coba==NULL) return;
1290
1291         bt= uiDefBut(block, BUT, 0,     "Add",                  0+xoffs,100+yoffs,40,20, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1292         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1293
1294         bt= uiDefBut(block, BUT, 0,     "Delete",               45+xoffs,100+yoffs,45,20, NULL, 0, 0, 0, 0, "Delete the active position");
1295         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1296
1297
1298         /* XXX, todo for later - convert to operator - campbell */
1299         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,100+yoffs,20,20, NULL, 0, 0, 0, 0, "Flip colorband");
1300         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1301
1302         uiDefButS(block, NUM, 0,                "",                             120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop");
1303
1304         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1305                         210+xoffs, 100+yoffs, 90, 20,           &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1306         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1307         uiBlockEndAlign(block);
1308
1309         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, "");
1310         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1311
1312
1313
1314         if(coba->tot) {
1315                 CBData *cbd= coba->data + coba->cur;
1316
1317                 /* better to use rna so we can animate them */
1318                 PointerRNA ptr;
1319                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1320                 row= uiLayoutRow(layout, 0);
1321                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1322                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1323         }
1324
1325 }
1326
1327 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1328 {
1329         uiBut *bt;
1330         float unit= (butr->xmax-butr->xmin)/14.0f;
1331         float xs= butr->xmin;
1332
1333         uiBlockBeginAlign(block);
1334         bt= uiDefBut(block, BUT, 0,     "Add",                  xs,butr->ymin+20.0f,2.0f*unit,20,       NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1335         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1336         bt= uiDefBut(block, BUT, 0,     "Delete",               xs+2.0f*unit,butr->ymin+20.0f,1.5f*unit,20,     NULL, 0, 0, 0, 0, "Delete the active position");
1337         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1338         bt= uiDefBut(block, BUT, 0,     "F",            xs+3.5f*unit,butr->ymin+20.0f,0.5f*unit,20,     NULL, 0, 0, 0, 0, "Flip the color ramp");
1339         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1340         uiBlockEndAlign(block);
1341
1342         if(coba->tot) {
1343                 CBData *cbd= coba->data + coba->cur;
1344                 PointerRNA ptr;
1345                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1346                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1347         }
1348
1349         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1350                         xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20,            &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1351         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1352
1353         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, "");
1354         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1355
1356         uiBlockEndAlign(block);
1357 }
1358
1359 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1360 {
1361         if(small)
1362                 colorband_buttons_small(layout, block, coba, butr, cb);
1363         else
1364                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1365 }
1366
1367 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1368 {
1369         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1370         PointerRNA cptr;
1371         RNAUpdateCb *cb;
1372         uiBlock *block;
1373         rctf rect;
1374
1375         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1376                 return;
1377
1378         cptr= RNA_property_pointer_get(ptr, prop);
1379         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1380                 return;
1381
1382         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1383         cb->ptr= *ptr;
1384         cb->prop= prop;
1385
1386         rect.xmin= 0; rect.xmax= 200;
1387         rect.ymin= 0; rect.ymax= 190;
1388
1389         block= uiLayoutAbsoluteBlock(layout);
1390         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1391
1392         MEM_freeN(cb);
1393 }
1394
1395 /********************* Histogram Template ************************/
1396
1397 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1398 {
1399         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1400         PointerRNA cptr;
1401         RNAUpdateCb *cb;
1402         uiBlock *block;
1403         uiBut *bt;
1404         Histogram *hist;
1405         rctf rect;
1406         
1407         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1408                 return;
1409         
1410         cptr= RNA_property_pointer_get(ptr, prop);
1411         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1412                 return;
1413         
1414         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1415         cb->ptr= *ptr;
1416         cb->prop= prop;
1417         
1418         rect.xmin= 0; rect.xmax= 200;
1419         rect.ymin= 0; rect.ymax= 190;
1420         
1421         block= uiLayoutAbsoluteBlock(layout);
1422         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1423
1424         hist = (Histogram *)cptr.data;
1425
1426         hist->height= (hist->height<=20)?20:hist->height;
1427
1428         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
1429         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1430
1431         MEM_freeN(cb);
1432 }
1433
1434 /********************* Waveform Template ************************/
1435
1436 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1437 {
1438         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1439         PointerRNA cptr;
1440         RNAUpdateCb *cb;
1441         uiBlock *block;
1442         uiBut *bt;
1443         Scopes *scopes;
1444         rctf rect;
1445         
1446         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1447                 return;
1448         
1449         cptr= RNA_property_pointer_get(ptr, prop);
1450         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1451                 return;
1452         scopes = (Scopes *)cptr.data;
1453         
1454         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1455         cb->ptr= *ptr;
1456         cb->prop= prop;
1457         
1458         rect.xmin= 0; rect.xmax= 200;
1459         rect.ymin= 0; rect.ymax= 190;
1460         
1461         block= uiLayoutAbsoluteBlock(layout);
1462         
1463         scopes->wavefrm_height= (scopes->wavefrm_height<=20)?20:scopes->wavefrm_height;
1464
1465         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1466         (void)bt; // UNUSED
1467         
1468         MEM_freeN(cb);
1469 }
1470
1471 /********************* Vectorscope Template ************************/
1472
1473 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1474 {
1475         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1476         PointerRNA cptr;
1477         RNAUpdateCb *cb;
1478         uiBlock *block;
1479         uiBut *bt;
1480         Scopes *scopes;
1481         rctf rect;
1482         
1483         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1484                 return;
1485         
1486         cptr= RNA_property_pointer_get(ptr, prop);
1487         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1488                 return;
1489         scopes = (Scopes *)cptr.data;
1490
1491         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1492         cb->ptr= *ptr;
1493         cb->prop= prop;
1494         
1495         rect.xmin= 0; rect.xmax= 200;
1496         rect.ymin= 0; rect.ymax= 190;
1497         
1498         block= uiLayoutAbsoluteBlock(layout);
1499
1500         scopes->vecscope_height= (scopes->vecscope_height<=20)?20:scopes->vecscope_height;
1501         
1502         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1503         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1504         
1505         MEM_freeN(cb);
1506 }
1507
1508 /********************* CurveMapping Template ************************/
1509
1510
1511 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1512 {
1513         CurveMapping *cumap = cumap_v;
1514         float d;
1515
1516         /* we allow 20 times zoom */
1517         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1518                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1519                 cumap->curr.xmin+= d;
1520                 cumap->curr.xmax-= d;
1521                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1522                 cumap->curr.ymin+= d;
1523                 cumap->curr.ymax-= d;
1524         }
1525
1526         ED_region_tag_redraw(CTX_wm_region(C));
1527 }
1528
1529 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1530 {
1531         CurveMapping *cumap = cumap_v;
1532         float d, d1;
1533
1534         /* we allow 20 times zoom, but dont view outside clip */
1535         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1536                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1537
1538                 if(cumap->flag & CUMA_DO_CLIP) 
1539                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1540                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1541                 cumap->curr.xmin-= d1;
1542
1543                 d1= d;
1544                 if(cumap->flag & CUMA_DO_CLIP) 
1545                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1546                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1547                 cumap->curr.xmax+= d1;
1548
1549                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1550
1551                 if(cumap->flag & CUMA_DO_CLIP) 
1552                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1553                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1554                 cumap->curr.ymin-= d1;
1555
1556                 d1= d;
1557                 if(cumap->flag & CUMA_DO_CLIP) 
1558                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1559                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1560                 cumap->curr.ymax+= d1;
1561         }
1562
1563         ED_region_tag_redraw(CTX_wm_region(C));
1564 }
1565
1566 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1567 {
1568         CurveMapping *cumap = cumap_v;
1569
1570         curvemapping_changed(cumap, 0);
1571 }       
1572
1573 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1574 {
1575         CurveMapping *cumap = cumap_v;
1576
1577         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1578         curvemapping_changed(cumap, 0);
1579
1580         rna_update_cb(C, cb_v, NULL);
1581 }
1582
1583 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1584 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1585 {
1586         CurveMapping *cumap = cumap_v;
1587         uiBlock *block;
1588         uiBut *bt;
1589
1590         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
1591
1592         /* use this for a fake extra empy space around the buttons */
1593         uiDefBut(block, LABEL, 0, "",                   -4, 16, 128, 106, NULL, 0, 0, 0, 0, "");
1594
1595         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1596                         0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, "");
1597         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1598
1599         uiBlockBeginAlign(block);
1600         uiDefButF(block, NUM, 0, "Min X ",       0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
1601         uiDefButF(block, NUM, 0, "Min Y ",       0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
1602         uiDefButF(block, NUM, 0, "Max X ",       0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
1603         uiDefButF(block, NUM, 0, "Max Y ",       0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
1604
1605         uiBlockSetDirection(block, UI_RIGHT);
1606
1607         uiEndBlock(C, block);
1608         return block;
1609 }
1610
1611 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1612 {
1613         CurveMapping *cumap = cumap_v;
1614         CurveMap *cuma= cumap->cm+cumap->cur;
1615
1616         switch(event) {
1617                 case 0: /* reset */
1618                         curvemap_reset(cuma, &cumap->clipr,     cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1619                         curvemapping_changed(cumap, 0);
1620                         break;
1621                 case 1:
1622                         cumap->curr= cumap->clipr;
1623                         break;
1624                 case 2: /* set vector */
1625                         curvemap_sethandle(cuma, 1);
1626                         curvemapping_changed(cumap, 0);
1627                         break;
1628                 case 3: /* set auto */
1629                         curvemap_sethandle(cuma, 0);
1630                         curvemapping_changed(cumap, 0);
1631                         break;
1632                 case 4: /* extend horiz */
1633                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1634                         curvemapping_changed(cumap, 0);
1635                         break;
1636                 case 5: /* extend extrapolate */
1637                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1638                         curvemapping_changed(cumap, 0);
1639                         break;
1640         }
1641         ED_region_tag_redraw(CTX_wm_region(C));
1642 }
1643
1644 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1645 {
1646         uiBlock *block;
1647         short yco= 0, menuwidth=120;
1648
1649         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1650         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1651
1652         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1653         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1654         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1655         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
1656         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
1657         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
1658
1659         uiBlockSetDirection(block, UI_RIGHT);
1660         uiTextBoundsBlock(block, 50);
1661
1662         uiEndBlock(C, block);
1663         return block;
1664 }
1665
1666 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1667 {
1668         uiBlock *block;
1669         short yco= 0, menuwidth=120;
1670
1671         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1672         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1673
1674         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1675         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1676         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1677         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
1678
1679         uiBlockSetDirection(block, UI_RIGHT);
1680         uiTextBoundsBlock(block, 50);
1681
1682         uiEndBlock(C, block);
1683         return block;
1684 }
1685
1686 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1687 {
1688         ED_region_tag_redraw(CTX_wm_region(C));
1689 }
1690
1691 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1692 {
1693         CurveMapping *cumap = cumap_v;
1694         int a;
1695         
1696         cumap->preset = CURVE_PRESET_LINE;
1697         for(a=0; a<CM_TOT; a++)
1698                 curvemap_reset(cumap->cm+a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1699         
1700         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1701         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1702         curvemapping_set_black_white(cumap, NULL, NULL);
1703         
1704         curvemapping_changed(cumap, 0);
1705
1706         rna_update_cb(C, cb_v, NULL);
1707 }
1708
1709 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1710 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1711 {
1712         CurveMapping *cumap= ptr->data;
1713         uiLayout *row, *sub, *split;
1714         uiBlock *block;
1715         uiBut *bt;
1716         float dx= UI_UNIT_X;
1717         int icon, size;
1718         int bg=-1;
1719
1720         block= uiLayoutGetBlock(layout);
1721
1722         /* curve chooser */
1723         row= uiLayoutRow(layout, 0);
1724
1725         if(labeltype=='v') {
1726                 /* vector */
1727                 sub= uiLayoutRow(row, 1);
1728                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1729
1730                 if(cumap->cm[0].curve) {
1731                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1732                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1733                 }
1734                 if(cumap->cm[1].curve) {
1735                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1736                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1737                 }
1738                 if(cumap->cm[2].curve) {
1739                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1740                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1741                 }
1742         }
1743         else if(labeltype=='c') {
1744                 /* color */
1745                 sub= uiLayoutRow(row, 1);
1746                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1747
1748                 if(cumap->cm[3].curve) {
1749                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1750                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1751                 }
1752                 if(cumap->cm[0].curve) {
1753                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1754                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1755                 }
1756                 if(cumap->cm[1].curve) {
1757                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1758                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1759                 }
1760                 if(cumap->cm[2].curve) {
1761                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1762                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1763                 }
1764         }
1765         else if (labeltype == 'h') {
1766                 /* HSV */
1767                 sub= uiLayoutRow(row, 1);
1768                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1769                 
1770                 if(cumap->cm[0].curve) {
1771                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1772                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1773                 }
1774                 if(cumap->cm[1].curve) {
1775                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1776                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1777                 }
1778                 if(cumap->cm[2].curve) {
1779                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1780                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1781                 }
1782         }
1783         else
1784                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1785         
1786         if (labeltype=='h')
1787                 bg = UI_GRAD_H;
1788
1789         /* operation buttons */
1790         sub= uiLayoutRow(row, 1);
1791
1792         uiBlockSetEmboss(block, UI_EMBOSSN);
1793
1794         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
1795         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1796
1797         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
1798         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1799
1800         if(brush)
1801                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1802         else
1803                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1804
1805         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1806
1807         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1808         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, 18, "Clipping Options");
1809         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1810
1811         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
1812         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1813
1814         uiBlockSetEmboss(block, UI_EMBOSS);
1815
1816         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1817
1818         /* curve itself */
1819         size= uiLayoutGetWidth(layout);
1820         row= uiLayoutRow(layout, 0);
1821         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1822
1823         /* black/white levels */
1824         if(levels) {
1825                 split= uiLayoutSplit(layout, 0, 0);
1826                 uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1827                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1828
1829                 uiLayoutRow(layout, 0);
1830                 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");
1831                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1832         }
1833
1834         uiBlockSetNFunc(block, NULL, NULL, NULL);
1835 }
1836
1837 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
1838 {
1839         RNAUpdateCb *cb;
1840         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1841         PointerRNA cptr;
1842
1843         if(!prop) {
1844                 RNA_warning("uiTemplateCurveMapping: curve property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1845                 return;
1846         }
1847
1848         if(RNA_property_type(prop) != PROP_POINTER) {
1849                 RNA_warning("uiTemplateCurveMapping: curve is not a pointer: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1850                 return;
1851         }
1852
1853         cptr= RNA_property_pointer_get(ptr, prop);
1854         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1855                 return;
1856
1857         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1858         cb->ptr= *ptr;
1859         cb->prop= prop;
1860
1861         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1862
1863         MEM_freeN(cb);
1864 }
1865
1866 /********************* ColorWheel Template ************************/
1867
1868 #define WHEEL_SIZE      100
1869
1870 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
1871 {
1872         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1873         uiBlock *block= uiLayoutGetBlock(layout);
1874         uiLayout *col, *row;
1875         uiBut *but;
1876         float softmin, softmax, step, precision;
1877         
1878         if (!prop) {
1879                 RNA_warning("uiTemplateColorWheel: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1880                 return;
1881         }
1882
1883         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
1884         
1885         col = uiLayoutColumn(layout, 0);
1886         row= uiLayoutRow(col, 1);
1887         
1888         but= uiDefButR(block, HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, propname, -1, 0.0, 0.0, 0, 0, "");
1889
1890         if(lock) {
1891                 but->flag |= UI_BUT_COLOR_LOCK;
1892         }
1893
1894         if(lock_luminosity) {
1895                 float color[4]; /* incase of alpha */
1896                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
1897                 RNA_property_float_get_array(ptr, prop, color);
1898                 but->a2= len_v3(color);
1899         }
1900
1901         if(cubic)
1902                 but->flag |= UI_BUT_COLOR_CUBIC;
1903
1904         uiItemS(row);
1905         
1906         if (value_slider)
1907                 uiDefButR(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, propname, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
1908 }
1909
1910 /********************* Layer Buttons Template ************************/
1911
1912 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
1913 {
1914         uiBut *but = arg1;
1915         int cur = GET_INT_FROM_POINTER(arg2);
1916         wmWindow *win= CTX_wm_window(C);
1917         int i, tot, shift= win->eventstate->shift;
1918
1919         if(!shift) {
1920                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
1921                 
1922                 /* Normally clicking only selects one layer */
1923                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
1924                 for(i = 0; i < tot; ++i) {
1925                         if(i != cur)
1926                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
1927                 }
1928         }
1929         
1930         /* view3d layer change should update depsgraph (invisible object changed maybe) */
1931         /* see view3d_header.c */
1932 }
1933
1934 // TODO:
1935 //      - for now, grouping of layers is determined by dividing up the length of 
1936 //        the array of layer bitflags
1937
1938 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
1939                           PointerRNA *used_ptr, const char *used_propname, int active_layer)
1940 {
1941         uiLayout *uRow, *uCol;
1942         PropertyRNA *prop, *used_prop= NULL;
1943         int groups, cols, layers;
1944         int group, col, layer, row;
1945         int cols_per_group = 5;
1946
1947         prop= RNA_struct_find_property(ptr, propname);
1948         if (!prop) {
1949                 RNA_warning("uiTemplateLayer: layers property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1950                 return;
1951         }
1952         
1953         /* the number of layers determines the way we group them 
1954          *      - we want 2 rows only (for now)
1955          *      - the number of columns (cols) is the total number of buttons per row
1956          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
1957          *      - for now, only split into groups if group will have at least 5 items
1958          */
1959         layers= RNA_property_array_length(ptr, prop);
1960         cols= (layers / 2) + (layers % 2);
1961         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
1962
1963         if(used_ptr && used_propname) {
1964                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
1965                 if (!used_prop) {
1966                         RNA_warning("uiTemplateLayer: used layers property not found: %s.%s\n", RNA_struct_identifier(ptr->type), used_propname);
1967                         return;
1968                 }
1969
1970                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
1971                         used_prop = NULL;
1972         }
1973         
1974         /* layers are laid out going across rows, with the columns being divided into groups */
1975         
1976         for (group= 0; group < groups; group++) {
1977                 uCol= uiLayoutColumn(layout, 1);
1978                 
1979                 for (row= 0; row < 2; row++) {
1980                         uiBlock *block;
1981                         uiBut *but;
1982
1983                         uRow= uiLayoutRow(uCol, 1);
1984                         block= uiLayoutGetBlock(uRow);
1985                         layer= groups*cols_per_group*row + cols_per_group*group;
1986                         
1987                         /* add layers as toggle buts */
1988                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
1989                                 int icon = 0;
1990                                 int butlay = 1 << layer;
1991
1992                                 if(active_layer & butlay)
1993                                         icon = ICON_LAYER_ACTIVE;
1994                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
1995                                         icon = ICON_LAYER_USED;
1996                                 
1997                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, 10, 10);
1998                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
1999                                 but->type= TOG;
2000                         }
2001                 }
2002         }
2003 }
2004
2005
2006 /************************* List Template **************************/
2007
2008 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
2009 {
2010         ID *id= NULL;
2011         int icon;
2012
2013         if(!itemptr->data)
2014                 return rnaicon;
2015
2016         /* try ID, material or texture slot */
2017         if(RNA_struct_is_ID(itemptr->type)) {
2018                 id= itemptr->id.data;
2019         }
2020         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2021                 id= RNA_pointer_get(itemptr, "material").data;
2022         }
2023         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2024                 id= RNA_pointer_get(itemptr, "texture").data;
2025         }
2026
2027         /* get icon from ID */
2028         if(id) {
2029                 icon= ui_id_icon_get(C, id, big);
2030
2031                 if(icon)
2032                         return icon;
2033         }
2034
2035         return rnaicon;
2036 }
2037
2038 static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, const char *activepropname)
2039 {
2040         uiBlock *block= uiLayoutGetBlock(layout);
2041         uiBut *but;
2042         uiLayout *split, *overlap, *sub, *row;
2043         char *namebuf;
2044         const char *name;
2045         int icon;
2046
2047         overlap= uiLayoutOverlap(layout);
2048
2049         /* list item behind label & other buttons */
2050         sub= uiLayoutRow(overlap, 0);
2051
2052         but= uiDefButR(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2053         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2054
2055         sub= uiLayoutRow(overlap, 0);
2056
2057         /* retrieve icon and name */
2058         icon= list_item_icon_get(C, itemptr, rnaicon, 0);
2059         if(icon == ICON_NONE || icon == ICON_DOT)
2060                 icon= 0;
2061
2062         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0);
2063         name= (namebuf)? namebuf: "";
2064
2065         /* hardcoded types */
2066         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
2067                 uiItemL(sub, name, icon);
2068                 uiBlockSetEmboss(block, UI_EMBOSSN);
2069                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2070                 uiBlockSetEmboss(block, UI_EMBOSS);
2071         }
2072         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2073                 uiItemL(sub, name, icon);
2074                 uiBlockSetEmboss(block, UI_EMBOSS);
2075                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2076         }
2077         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer) || RNA_struct_is_a(itemptr->type, &RNA_FreestyleLineSet)) {
2078                 uiItemL(sub, name, icon);
2079                 uiBlockSetEmboss(block, UI_EMBOSS);
2080                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
2081         }
2082         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2083                 /* provision to draw active node name */
2084                 Material *ma, *manode;
2085                 Object *ob= (Object*)ptr->id.data;
2086                 int index= (Material**)itemptr->data - ob->mat;
2087                 
2088                 /* default item with material base name */
2089                 uiItemL(sub, name, icon);
2090                 
2091                 ma= give_current_material(ob, index+1);
2092                 if(ma) {
2093                         manode= give_node_material(ma);
2094                         if(manode) {
2095                                 char str[MAX_ID_NAME + 12];
2096                                 sprintf(str, "Node %s", manode->id.name+2);
2097                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
2098                         }
2099                         else if(ma->use_nodes) {
2100                                 uiItemL(sub, "Node <none>", ICON_NONE);
2101                         }
2102                 }
2103         }
2104         else if(itemptr->type == &RNA_ShapeKey) {
2105                 Object *ob= (Object*)activeptr->data;
2106
2107                 split= uiLayoutSplit(sub, 0.75f, 0);
2108
2109                 uiItemL(split, name, icon);
2110
2111                 uiBlockSetEmboss(block, UI_EMBOSSN);
2112                 row= uiLayoutRow(split, 1);
2113                 if(i == 0) uiItemL(row, "", ICON_NONE);
2114                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2115
2116                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2117                         uiLayoutSetActive(row, 0);
2118                 //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
2119                 uiBlockSetEmboss(block, UI_EMBOSS);
2120         }
2121         else
2122                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2123
2124         /* free name */
2125         if(namebuf)
2126                 MEM_freeN(namebuf);
2127 }
2128
2129 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, const char *activepropname, int rows, int maxrows, int listtype)
2130 {
2131         //Scene *scene= CTX_data_scene(C);
2132         PropertyRNA *prop= NULL, *activeprop;
2133         PropertyType type, activetype;
2134         StructRNA *ptype;
2135         uiLayout *box, *row, *col;
2136         uiBlock *block;
2137         uiBut *but;
2138         Panel *pa;
2139         char *name, str[32];
2140         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2141
2142         /* validate arguments */
2143         block= uiLayoutGetBlock(layout);
2144         pa= block->panel;
2145
2146         if(!pa) {
2147                 RNA_warning("uiTemplateList: only works inside a panel.\n");
2148                 return;
2149         }
2150
2151         if(!activeptr->data)
2152                 return;
2153         
2154         if(ptr->data) {
2155                 prop= RNA_struct_find_property(ptr, propname);
2156                 if(!prop) {
2157                         RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
2158                         return;
2159                 }
2160         }
2161
2162         activeprop= RNA_struct_find_property(activeptr, activepropname);
2163         if(!activeprop) {
2164                 RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), activepropname);
2165                 return;
2166         }
2167
2168         if(prop) {
2169                 type= RNA_property_type(prop);
2170                 if(type != PROP_COLLECTION) {
2171                         RNA_warning("uiTemplateList: expected collection property.\n");
2172                         return;
2173                 }
2174         }
2175
2176         activetype= RNA_property_type(activeprop);
2177         if(activetype != PROP_INT) {
2178                 RNA_warning("uiTemplateList: expected integer property.\n");
2179                 return;
2180         }
2181
2182         /* get icon */
2183         if(ptr->data && prop) {
2184                 ptype= RNA_property_pointer_type(ptr, prop);
2185                 rnaicon= RNA_struct_ui_icon(ptype);
2186         }
2187
2188         /* get active data */
2189         activei= RNA_property_int_get(activeptr, activeprop);
2190
2191         if(listtype == 'i') {
2192                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2193                 col= uiLayoutColumn(box, 1);
2194                 row= uiLayoutRow(col, 0);
2195
2196                 if(ptr->data && prop) {
2197                         /* create list items */
2198                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2199                                 /* create button */
2200                                 if(i == 9)
2201                                         row= uiLayoutRow(col, 0);
2202
2203                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
2204                                 but= uiDefIconButR(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2205                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2206                                 
2207
2208                                 i++;
2209                         }
2210                         RNA_PROP_END;
2211                 }
2212         }
2213         else if(listtype == 'c') {
2214                 /* compact layout */
2215                 found= 0;
2216
2217                 row= uiLayoutRow(layout, 1);
2218
2219                 if(ptr->data && prop) {
2220                         /* create list items */
2221                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2222                                 found= (activei == i);
2223
2224                                 if(found) {
2225                                         /* create button */
2226                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
2227                                         icon= list_item_icon_get(C, &itemptr, rnaicon, 0);
2228                                         uiItemL(row, (name)? name: "", icon);
2229
2230                                         if(name)
2231                                                 MEM_freeN(name);
2232                                 }
2233
2234                                 i++;
2235                         }
2236                         RNA_PROP_END;
2237                 }
2238
2239                 /* if not found, add in dummy button */
2240                 if(i == 0)
2241                         uiItemL(row, "", ICON_NONE);
2242
2243                 /* next/prev button */
2244                 sprintf(str, "%d :", i);
2245                 but= uiDefIconTextButR(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activepropname, 0, 0, 0, 0, 0, "");
2246                 if(i == 0)
2247                         uiButSetFlag(but, UI_BUT_DISABLED);
2248         }
2249         else {
2250                 /* default rows */
2251                 if(rows == 0)
2252                         rows= 5;
2253                 if (maxrows == 0)
2254                         maxrows = 5;
2255                 if(pa->list_grip_size != 0)
2256                         rows= pa->list_grip_size;
2257
2258                 /* layout */
2259                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2260                 row= uiLayoutRow(box, 0);
2261                 col = uiLayoutColumn(row, 1);
2262
2263                 /* init numbers */
2264                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2265
2266                 if(prop)
2267                         len= RNA_property_collection_length(ptr, prop);
2268                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2269
2270                 /* if list length changes and active is out of view, scroll to it */
2271                 if(pa->list_last_len != len)
2272                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2273                                 pa->list_scroll= activei;
2274
2275                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2276                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2277                 pa->list_size= items;
2278                 pa->list_last_len= len;
2279
2280                 if(ptr->data && prop) {
2281                         /* create list items */
2282                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2283                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2284                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activepropname);
2285
2286                                 i++;
2287                         }
2288                         RNA_PROP_END;
2289                 }
2290
2291                 /* add dummy buttons to fill space */
2292                 while(i < pa->list_scroll+items) {
2293                         if(i >= pa->list_scroll)
2294                                 uiItemL(col, "", ICON_NONE);
2295                         i++;
2296                 }
2297
2298                 /* add scrollbar */
2299                 if(len > items) {
2300                         col= uiLayoutColumn(row, 0);
2301                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2302                 }
2303         }
2304 }
2305
2306 /************************* Operator Search Template **************************/
2307
2308 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
2309 {
2310         wmOperatorType *ot= arg2;
2311         
2312         if(ot)
2313                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2314 }
2315
2316 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
2317 {
2318         wmOperatorType *ot = WM_operatortype_first();
2319         
2320         for(; ot; ot= ot->next) {
2321                 
2322                 if(BLI_strcasestr(ot->name, str)) {
2323                         if(WM_operator_poll((bContext*)C, ot)) {
2324                                 char name[256];
2325                                 int len= strlen(ot->name);
2326                                 
2327                                 /* display name for menu, can hold hotkey */
2328                                 BLI_strncpy(name, ot->name, 256);
2329                                 
2330                                 /* check for hotkey */
2331                                 if(len < 256-6) {
2332                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
2333                                                 name[len]= '|';
2334                                 }
2335                                 
2336                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2337                                         break;
2338                         }
2339                 }
2340         }
2341 }
2342
2343 void uiTemplateOperatorSearch(uiLayout *layout)
2344 {
2345         uiBlock *block;
2346         uiBut *but;
2347         static char search[256]= "";
2348                 
2349         block= uiLayoutGetBlock(layout);
2350         uiBlockSetCurLayout(block, layout);
2351
2352         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2353         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2354 }
2355
2356 /************************* Running Jobs Template **************************/
2357
2358 #define B_STOPRENDER    1
2359 #define B_STOPCAST              2
2360 #define B_STOPANIM              3
2361 #define B_STOPCOMPO             4
2362
2363 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2364 {
2365         switch(event) {
2366                 case B_STOPRENDER:
2367                         G.afbreek= 1;
2368                         break;
2369                 case B_STOPCAST:
2370                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2371                         break;
2372                 case B_STOPANIM:
2373                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2374                         break;
2375                 case B_STOPCOMPO:
2376                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2377                         break;
2378         }
2379 }
2380
2381 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2382 {
2383         bScreen *screen= CTX_wm_screen(C);
2384         wmWindowManager *wm= CTX_wm_manager(C);
2385         ScrArea *sa= CTX_wm_area(C);
2386         uiBlock *block;
2387         void *owner= NULL;
2388         int handle_event;
2389         
2390         block= uiLayoutGetBlock(layout);
2391         uiBlockSetCurLayout(block, layout);
2392
2393         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2394
2395         if(sa->spacetype==SPACE_NODE) {
2396                 if(WM_jobs_test(wm, sa))
2397                    owner = sa;
2398                 handle_event= B_STOPCOMPO;
2399         } 
2400         else {
2401                 Scene *scene;
2402                 /* another scene can be rendering too, for example via compositor */
2403                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2404                         if(WM_jobs_test(wm, scene))
2405                                 break;
2406                 owner = scene;
2407                 handle_event= B_STOPRENDER;
2408         }
2409
2410         if(owner) {
2411                 uiLayout *ui_abs;
2412                 
2413                 ui_abs= uiLayoutAbsolute(layout, 0);
2414                 (void)ui_abs; // UNUSED
2415                 
2416                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2417                                 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");
2418                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2419                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, "Progress");
2420                 
2421                 uiLayoutRow(layout, 0);
2422         }
2423         if(WM_jobs_test(wm, screen))
2424                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
2425         if(screen->animtimer)
2426                 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");
2427 }
2428
2429 /************************* Reports for Last Operator Template **************************/
2430
2431 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2432 {
2433         ReportList *reports = CTX_wm_reports(C);
2434         Report *report= BKE_reports_last_displayable(reports);
2435         ReportTimerInfo *rti;
2436         
2437         uiLayout *ui_abs;
2438         uiBlock *block;
2439         uiBut *but;
2440         uiStyle *style= U.uistyles.first;
2441         int width;
2442         int icon=0;
2443         
2444         /* if the report display has timed out, don't show */
2445         if (!reports->reporttimer) return;
2446         
2447         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2448         
2449         if (!rti || rti->widthfac==0.0f || !report) return;
2450         
2451         ui_abs= uiLayoutAbsolute(layout, 0);
2452         block= uiLayoutGetBlock(ui_abs);
2453         
2454         width = BLF_width(style->widget.uifont_id, report->message);
2455         width = MIN2(rti->widthfac*width, width);
2456         width = MAX2(width, 10);
2457         
2458         /* make a box around the report to make it stand out */
2459         uiBlockBeginAlign(block);
2460         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2461         /* set the report's bg color in but->col - ROUNDBOX feature */
2462         but->col[0]= FTOCHAR(rti->col[0]);
2463         but->col[1]= FTOCHAR(rti->col[1]);
2464         but->col[2]= FTOCHAR(rti->col[2]);
2465         but->col[3]= 255; 
2466
2467         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2468         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2469         but->col[3]= 255;
2470
2471         uiBlockEndAlign(block);
2472         
2473         
2474         /* icon and report message on top */
2475         if(report->type & RPT_ERROR_ALL)
2476                 icon = ICON_ERROR;
2477         else if(report->type & RPT_WARNING_ALL)
2478                 icon = ICON_ERROR;
2479         else if(report->type & RPT_INFO_ALL)
2480                 icon = ICON_INFO;
2481         
2482         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2483          * to be shown instead of icon when appropriate...
2484          */
2485         uiBlockSetEmboss(block, UI_EMBOSSN);
2486
2487         if (reports->list.first != reports->list.last)
2488                 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'");
2489         else
2490                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2491
2492         uiBlockSetEmboss(block, UI_EMBOSS);
2493         
2494         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, "");
2495 }
2496