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