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