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