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