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