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