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