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