Blender  V2.59
interface_templates.c
Go to the documentation of this file.
00001 /*
00002  * $Id: interface_templates.c 39293 2011-08-11 06:06:17Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * Contributor(s): Blender Foundation 2009.
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include <stdlib.h>
00031 #include <stddef.h>
00032 #include <string.h>
00033 
00034 #include "MEM_guardedalloc.h"
00035 
00036 #include "DNA_key_types.h"
00037 #include "DNA_scene_types.h"
00038 #include "DNA_userdef_types.h"
00039 
00040 #include "BLI_string.h"
00041 #include "BLI_utildefines.h"
00042 #include "BLI_ghash.h"
00043 
00044 #include "BKE_animsys.h"
00045 #include "BKE_colortools.h"
00046 #include "BKE_context.h"
00047 #include "BKE_global.h"
00048 #include "BKE_library.h"
00049 #include "BKE_main.h"
00050 #include "BKE_object.h"
00051 #include "BKE_material.h"
00052 #include "BKE_texture.h"
00053 #include "BKE_report.h"
00054 #include "BKE_displist.h"
00055 
00056 #include "ED_screen.h"
00057 #include "ED_object.h"
00058 #include "ED_render.h"
00059 
00060 #include "RNA_access.h"
00061 
00062 #include "WM_api.h"
00063 #include "WM_types.h"
00064 
00065 #include "UI_interface.h"
00066 #include "interface_intern.h"
00067 
00068 #include "BLF_api.h"
00069 
00070 void UI_template_fix_linking(void)
00071 {
00072 }
00073 
00074 /********************** Header Template *************************/
00075 
00076 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
00077 {
00078         uiBlock *block;
00079 
00080         block= uiLayoutAbsoluteBlock(layout);
00081         if(menus) ED_area_header_standardbuttons(C, block, 0);
00082         else ED_area_header_switchbutton(C, block, 0);
00083 }
00084 
00085 /********************** Search Callbacks *************************/
00086 
00087 typedef struct TemplateID {
00088         PointerRNA ptr;
00089         PropertyRNA *prop;
00090 
00091         ListBase *idlb;
00092         int prv_rows, prv_cols;
00093 } TemplateID;
00094 
00095 /* Search browse menu, assign  */
00096 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
00097 {
00098         TemplateID *template= (TemplateID*)arg_template;
00099 
00100         /* ID */
00101         if(item) {
00102                 PointerRNA idptr;
00103 
00104                 RNA_id_pointer_create(item, &idptr);
00105                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
00106                 RNA_property_update(C, &template->ptr, template->prop);
00107         }
00108 }
00109 
00110 /* ID Search browse menu, do the search */
00111 static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
00112 {
00113         TemplateID *template= (TemplateID*)arg_template;
00114         ListBase *lb= template->idlb;
00115         ID *id, *id_from= template->ptr.id.data;
00116         int iconid;
00117         int flag= RNA_property_flag(template->prop);
00118 
00119         /* ID listbase */
00120         for(id= lb->first; id; id= id->next) {
00121                 if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
00122 
00123                         /* use filter */
00124                         if(RNA_property_type(template->prop)==PROP_POINTER) {
00125                                 PointerRNA ptr;
00126                                 RNA_id_pointer_create(id, &ptr);
00127                                 if(RNA_property_pointer_poll(&template->ptr, template->prop, &ptr)==0)
00128                                         continue;
00129                         }
00130 
00131                         /* hide dot-datablocks, but only if filter does not force it visible */
00132                         if(U.uiflag & USER_HIDE_DOT)
00133                                 if ((id->name[2]=='.') && (str[0] != '.'))
00134                                         continue;
00135 
00136                         if(BLI_strcasestr(id->name+2, str)) {
00137                                 char name_ui[32];
00138                                 name_uiprefix_id(name_ui, id);
00139 
00140                                 iconid= ui_id_icon_get((bContext*)C, id, 1);
00141 
00142                                 if(!uiSearchItemAdd(items, name_ui, id, iconid))
00143                                         break;
00144                         }
00145                 }
00146         }
00147 }
00148 
00149 /* ID Search browse menu, open */
00150 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
00151 {
00152         static char search[256];
00153         static TemplateID template;
00154         PointerRNA idptr;
00155         wmWindow *win= CTX_wm_window(C);
00156         uiBlock *block;
00157         uiBut *but;
00158         
00159         /* clear initial search string, then all items show */
00160         search[0]= 0;
00161         /* arg_litem is malloced, can be freed by parent button */
00162         template= *((TemplateID*)arg_litem);
00163         
00164         /* get active id for showing first item */
00165         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
00166 
00167         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
00168         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
00169         
00170         /* preview thumbnails */
00171         if (template.prv_rows > 0 && template.prv_cols > 0) {
00172                 int w = 96 * template.prv_cols;
00173                 int h = 96 * template.prv_rows + 20;
00174                 
00175                 /* fake button, it holds space for search items */
00176                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
00177                 
00178                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
00179                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
00180         }
00181         /* list view */
00182         else {
00183                 /* fake button, it holds space for search items */
00184                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
00185                 
00186                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
00187                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
00188         }
00189                 
00190         
00191         uiBoundsBlock(block, 6);
00192         uiBlockSetDirection(block, UI_DOWN);    
00193         uiEndBlock(C, block);
00194         
00195         /* give search-field focus */
00196         uiButSetFocusOnEnter(win, but);
00197         /* this type of search menu requires undo */
00198         but->flag |= UI_BUT_UNDO;
00199         
00200         return block;
00201 }
00202 
00203 /************************ ID Template ***************************/
00204 /* This is for browsing and editing the ID-blocks used */
00205 
00206 /* for new/open operators */
00207 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
00208 {
00209         TemplateID *template;
00210         ARegion *ar= CTX_wm_region(C);
00211         uiBlock *block;
00212         uiBut *but;
00213 
00214         memset(ptr, 0, sizeof(*ptr));
00215         *prop= NULL;
00216 
00217         if(!ar)
00218                 return;
00219 
00220         for(block=ar->uiblocks.first; block; block=block->next) {
00221                 for(but=block->buttons.first; but; but= but->next) {
00222                         /* find the button before the active one */
00223                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
00224                                 if(but->func_argN) {
00225                                         template= but->func_argN;
00226                                         *ptr= template->ptr;
00227                                         *prop= template->prop;
00228                                         return;
00229                                 }
00230                         }
00231                 }
00232         }
00233 }
00234 
00235 
00236 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
00237 {
00238         TemplateID *template= (TemplateID*)arg_litem;
00239         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
00240         ID *id= idptr.data, *newid;
00241         int event= GET_INT_FROM_POINTER(arg_event);
00242         
00243         switch(event) {
00244                 case UI_ID_BROWSE:
00245                 case UI_ID_PIN:
00246                         RNA_warning("warning, id event %d shouldnt come here\n", event);
00247                         break;
00248                 case UI_ID_OPEN:
00249                 case UI_ID_ADD_NEW:
00250                         /* these call uiIDContextPropertySet */
00251                         break;
00252                 case UI_ID_DELETE:
00253                         memset(&idptr, 0, sizeof(idptr));
00254                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
00255                         RNA_property_update(C, &template->ptr, template->prop);
00256 
00257                         if(id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
00258                                 id->us= 0;
00259 
00260                         break;
00261                 case UI_ID_FAKE_USER:
00262                         if(id) {
00263                                 if(id->flag & LIB_FAKEUSER) id_us_plus(id);
00264                                 else id_us_min(id);
00265                         }
00266                         else return;
00267                         break;
00268                 case UI_ID_LOCAL:
00269                         if(id) {
00270                                 if(id_make_local(id, 0)) {
00271                                         /* reassign to get get proper updates/notifiers */
00272                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
00273                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
00274                                         RNA_property_update(C, &template->ptr, template->prop);
00275                                 }
00276                         }
00277                         break;
00278                 case UI_ID_ALONE:
00279                         if(id) {
00280                                 const int do_scene_obj= (GS(id->name) == ID_OB) &&
00281                                                         (template->ptr.type == &RNA_SceneObjects);
00282 
00283                                 /* make copy */
00284                                 if(do_scene_obj) {
00285                                         Scene *scene= CTX_data_scene(C);
00286                                         ED_object_single_user(scene, (struct Object *)id);
00287                                         WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
00288                                 }
00289                                 else {
00290                                         if(id_copy(id, &newid, 0) && newid) {
00291                                                 /* copy animation actions too */
00292                                                 BKE_copy_animdata_id_action(id);
00293                                                 /* us is 1 by convention, but RNA_property_pointer_set
00294                                                    will also incremement it, so set it to zero */
00295                                                 newid->us= 0;
00296 
00297                                                 /* assign copy */
00298                                                 RNA_id_pointer_create(newid, &idptr);
00299                                                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
00300                                                 RNA_property_update(C, &template->ptr, template->prop);
00301                                         }
00302                                 }
00303                         }
00304                         break;
00305 #if 0
00306                 case UI_ID_AUTO_NAME:
00307                         break;
00308 #endif
00309         }
00310 }
00311 
00312 static const char *template_id_browse_tip(StructRNA *type)
00313 {
00314         if(type) {
00315                 switch(RNA_type_to_ID_code(type)) {
00316                         case ID_SCE: return "Browse Scene to be linked";
00317                         case ID_OB: return "Browse Object to be linked";
00318                         case ID_ME: return "Browse Mesh Data to be linked";
00319                         case ID_CU: return "Browse Curve Data to be linked";
00320                         case ID_MB: return "Browse MetaBall Data to be linked";
00321                         case ID_MA: return "Browse Material to be linked";
00322                         case ID_TE: return "Browse Texture to be linked";
00323                         case ID_IM: return "Browse Image to be linked";
00324                         case ID_LA: return "Browse Lattice Data to be linked";
00325                         case ID_CA: return "Browse Camera Data to be linked";
00326                         case ID_WO: return "Browse World Settings to be linked";
00327                         case ID_SCR: return "Choose Screen lay-out";
00328                         case ID_TXT: return "Browse Text to be linked";
00329                         case ID_SO: return "Browse Sound to be linked";
00330                         case ID_AR: return "Browse Armature data to be linked";
00331                         case ID_AC: return "Browse Action to be linked";
00332                         case ID_NT: return "Browse Node Tree to be linked";
00333                         case ID_BR: return "Browse Brush to be linked";
00334                         case ID_PA: return "Browse Particle System to be linked";
00335                         case ID_GD: return "Browse Grease Pencil Data to be linked";
00336                 }
00337         }
00338         return "Browse ID data to be linked";
00339 }
00340 
00341 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop)
00342 {
00343         uiBut *but;
00344         uiBlock *block;
00345         PointerRNA idptr;
00346         // ListBase *lb; // UNUSED
00347         ID *id, *idfrom;
00348         int editable= RNA_property_editable(&template->ptr, template->prop);
00349 
00350         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
00351         id= idptr.data;
00352         idfrom= template->ptr.id.data;
00353         // lb= template->idlb;
00354 
00355         block= uiLayoutGetBlock(layout);
00356         uiBlockBeginAlign(block);
00357 
00358         if(idptr.type)
00359                 type= idptr.type;
00360 
00361         if(flag & UI_ID_PREVIEWS) {
00362 
00363                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, template_id_browse_tip(type));
00364                 if(type) {
00365                         but->icon= RNA_struct_ui_icon(type);
00366                         if (id) but->icon = ui_id_icon_get(C, id, 1);
00367                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
00368                 }
00369                 if((idfrom && idfrom->lib) || !editable)
00370                         uiButSetFlag(but, UI_BUT_DISABLED);
00371                 
00372                 uiLayoutRow(layout, 1);
00373         }
00374         else if(flag & UI_ID_BROWSE) {
00375                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, template_id_browse_tip(type));
00376                 if(type) {
00377                         but->icon= RNA_struct_ui_icon(type);
00378                         /* default dragging of icon for id browse buttons */
00379                         uiButSetDragID(but, id);
00380                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_LEFT);
00381                 }
00382 
00383                 if((idfrom && idfrom->lib) || !editable)
00384                         uiButSetFlag(but, UI_BUT_DISABLED);
00385         }
00386 
00387         /* text button with name */
00388         if(id) {
00389                 char name[UI_MAX_NAME_STR];
00390                 const short user_alert= (id->us <= 0);
00391 
00392                 //text_idbutton(id, name);
00393                 name[0]= '\0';
00394                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
00395                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
00396                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
00397 
00398                 if(id->lib) {
00399                         if(id->flag & LIB_INDIRECT) {
00400                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0,
00401                                         "Indirect library datablock, cannot change.");
00402                                 uiButSetFlag(but, UI_BUT_DISABLED);
00403                         }
00404                         else {
00405                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0,
00406                                         "Direct linked library datablock, click to make local.");
00407                                 if(!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
00408                                         uiButSetFlag(but, UI_BUT_DISABLED);
00409                         }
00410 
00411                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
00412                 }
00413 
00414                 if(id->us > 1) {
00415                         char str[32];
00416 
00417                         sprintf(str, "%d", id->us);
00418 
00419                         but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X + ((id->us < 10) ? 0:10), UI_UNIT_Y, NULL, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
00420 
00421                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
00422                         if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib) || !editable)
00423                                 uiButSetFlag(but, UI_BUT_DISABLED);
00424                 }
00425         
00426                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
00427                 
00428                 if(id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
00429                         uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
00430                 }
00431         }
00432         
00433         if(flag & UI_ID_ADD_NEW) {
00434                 int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6;
00435                 
00436                 if(newop) {
00437                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL);
00438                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
00439                 }
00440                 else {
00441                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
00442                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
00443                 }
00444 
00445                 if((idfrom && idfrom->lib) || !editable)
00446                         uiButSetFlag(but, UI_BUT_DISABLED);
00447         }
00448 
00449         if(flag & UI_ID_OPEN) {
00450                 int w= id?UI_UNIT_X: (flag & UI_ID_ADD_NEW)? UI_UNIT_X*3: UI_UNIT_X*6;
00451                 
00452                 if(openop) {
00453                         but= uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL);
00454                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
00455                 }
00456                 else {
00457                         but= uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
00458                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
00459                 }
00460 
00461                 if((idfrom && idfrom->lib) || !editable)
00462                         uiButSetFlag(but, UI_BUT_DISABLED);
00463         }
00464         
00465         /* delete button */
00466         if(id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK)==0) {
00467                 if(unlinkop) {
00468                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
00469                         /* so we can access the template from operators, font unlinking needs this */
00470                         uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
00471                 }
00472                 else {
00473                         but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Unlink datablock. Shift + Click to set users to zero, data will then not be saved");
00474                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
00475 
00476                         if(RNA_property_flag(template->prop) & PROP_NEVER_NULL)
00477                                 uiButSetFlag(but, UI_BUT_DISABLED);
00478                 }
00479 
00480                 if((idfrom && idfrom->lib) || !editable)
00481                         uiButSetFlag(but, UI_BUT_DISABLED);
00482         }
00483         
00484         uiBlockEndAlign(block);
00485 }
00486 
00487 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)
00488 {
00489         TemplateID *template;
00490         PropertyRNA *prop;
00491         StructRNA *type;
00492 
00493         prop= RNA_struct_find_property(ptr, propname);
00494 
00495         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
00496                 RNA_warning("uiTemplateID: pointer property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
00497                 return;
00498         }
00499 
00500         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
00501         template->ptr= *ptr;
00502         template->prop= prop;
00503         template->prv_rows = prv_rows;
00504         template->prv_cols = prv_cols;
00505 
00506         if(newop)
00507                 flag |= UI_ID_ADD_NEW;
00508         if(openop)
00509                 flag |= UI_ID_OPEN;
00510 
00511         type= RNA_property_pointer_type(ptr, prop);
00512         template->idlb= which_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
00513         
00514         /* create UI elements for this template
00515          *      - template_ID makes a copy of the template data and assigns it to the relevant buttons
00516          */
00517         if(template->idlb) {
00518                 uiLayoutRow(layout, 1);
00519                 template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
00520         }
00521 
00522         MEM_freeN(template);
00523 }
00524 
00525 void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
00526 {
00527         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
00528 }
00529 
00530 void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
00531 {
00532         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
00533 }
00534 
00535 void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols)
00536 {
00537         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
00538 }
00539 
00540 /************************ ID Chooser Template ***************************/
00541 
00542 /* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use 
00543  *
00544  * - propname: property identifier for property that ID-pointer gets stored to
00545  * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
00546  */
00547 void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename, const char *text)
00548 {
00549         PropertyRNA *propID, *propType;
00550         uiLayout *row;
00551         
00552         /* get properties... */
00553         propID= RNA_struct_find_property(ptr, propname);
00554         propType= RNA_struct_find_property(ptr, proptypename);
00555 
00556         if (!propID || RNA_property_type(propID) != PROP_POINTER) {
00557                 RNA_warning("uiTemplateAnyID: pointer property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
00558                 return;
00559         }
00560         if (!propType || RNA_property_type(propType) != PROP_ENUM) { 
00561                 RNA_warning("uiTemplateAnyID: pointer-type property not found: %s.%s\n", RNA_struct_identifier(ptr->type), proptypename);
00562                 return;
00563         }
00564         
00565         /* Start drawing UI Elements using standard defines */
00566         row= uiLayoutRow(layout, 1);
00567         
00568         /* Label - either use the provided text, or will become "ID-Block:" */
00569         if (text)
00570                 uiItemL(row, text, ICON_NONE);
00571         else
00572                 uiItemL(row, "ID-Block:", ICON_NONE);
00573         
00574         /* ID-Type Selector - just have a menu of icons */
00575         // FIXME: the icon-only setting doesn't work when we supply a blank name
00576         uiItemFullR(row, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
00577         
00578         /* ID-Block Selector - just use pointer widget... */
00579         uiItemFullR(row, ptr, propID, 0, 0, 0, "", ICON_NONE);
00580 }
00581 
00582 /********************* RNA Path Builder Template ********************/
00583 
00584 /* ---------- */
00585 
00586 /* This is creating/editing RNA-Paths 
00587  *
00588  * - ptr: struct which holds the path property
00589  * - propname: property identifier for property that path gets stored to
00590  * - root_ptr: struct that path gets built from
00591  */
00592 void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *UNUSED(root_ptr), const char *text)
00593 {
00594         PropertyRNA *propPath;
00595         uiLayout *row;
00596         
00597         /* check that properties are valid */
00598         propPath= RNA_struct_find_property(ptr, propname);
00599         if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
00600                 RNA_warning("uiTemplatePathBuilder: path property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
00601                 return;
00602         }
00603         
00604         /* Start drawing UI Elements using standard defines */
00605         row= uiLayoutRow(layout, 1);
00606         
00607         /* Path (existing string) Widget */
00608         uiItemR(row, ptr, propname, 0, text, ICON_RNA);
00609         
00610         // TODO: attach something to this to make allow searching of nested properties to 'build' the path
00611 }
00612 
00613 /************************ Modifier Template *************************/
00614 
00615 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
00616 
00617 #include <string.h>
00618 
00619 #include "DNA_object_force.h"
00620 
00621 #include "BKE_depsgraph.h"
00622 #include "BKE_modifier.h"
00623 #include "BKE_particle.h"
00624 
00625 #include "ED_util.h"
00626 
00627 #include "BLI_math.h"
00628 #include "BLI_listbase.h"
00629 
00630 #include "ED_object.h"
00631 
00632 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
00633 {
00634         Scene *scene = CTX_data_scene(C);
00635         Object *ob = ob_v;
00636         ModifierData *md= md_v;
00637         int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
00638 
00639         /* undo button operation */
00640         md->mode ^= eModifierMode_OnCage;
00641 
00642         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
00643                 if(md == md_v) {
00644                         if(i >= cageIndex)
00645                                 md->mode ^= eModifierMode_OnCage;
00646                         break;
00647                 }
00648         }
00649 
00650         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
00651         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
00652 }
00653 
00654 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
00655 {
00656         Object *ob = ob_v;
00657         ModifierData *md = md_v;
00658         ModifierData *nmd = modifier_new(md->type);
00659 
00660         modifier_copyData(md, nmd);
00661         nmd->mode &= ~eModifierMode_Virtual;
00662 
00663         BLI_addhead(&ob->modifiers, nmd);
00664         
00665         modifier_unique_name(&ob->modifiers, nmd);
00666 
00667         ob->partype = PAROBJECT;
00668 
00669         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
00670         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
00671 
00672         ED_undo_push(C, "Modifier convert to real");
00673 }
00674 
00675 static int modifier_can_delete(ModifierData *md)
00676 {
00677         // fluid particle modifier can't be deleted here
00678         if(md->type == eModifierType_ParticleSystem)
00679                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
00680                         return 0;
00681 
00682         return 1;
00683 }
00684 
00685 // Check wheter Modifier is a simulation or not, this is used for switching to the physics/particles context tab
00686 static int modifier_is_simulation(ModifierData *md)
00687 {
00688         // Physic Tab
00689         if(ELEM6(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface)) {
00690                 return 1;
00691         }
00692         // Particle Tab
00693         else if (md->type == eModifierType_ParticleSystem) {
00694                 return 2;
00695         }
00696         else {
00697                 return 0;
00698         }
00699 }
00700 
00701 static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
00702 {
00703         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
00704         PointerRNA ptr;
00705         uiBut *but;
00706         uiBlock *block;
00707         uiLayout *box, *column, *row;
00708         uiLayout *result= NULL;
00709         int isVirtual = (md->mode & eModifierMode_Virtual);
00710         char str[128];
00711 
00712         /* create RNA pointer */
00713         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
00714 
00715         column= uiLayoutColumn(layout, 1);
00716         uiLayoutSetContextPointer(column, "modifier", &ptr);
00717 
00718         /* rounded header ------------------------------------------------------------------- */
00719         box= uiLayoutBox(column);
00720         
00721         if (isVirtual) {
00722                 row= uiLayoutRow(box, 0);
00723                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
00724                 block= uiLayoutGetBlock(row);
00725                 /* VIRTUAL MODIFIER */
00726                 // XXX this is not used now, since these cannot be accessed via RNA
00727                 sprintf(str, "%s parent deform", md->name);
00728                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
00729                 
00730                 but = uiDefBut(block, BUT, 0, "Make Real", 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Convert virtual modifier to a real modifier");
00731                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
00732         }
00733         else {
00734                 /* REAL MODIFIER */
00735                 row = uiLayoutRow(box, 0);
00736                 block = uiLayoutGetBlock(row);
00737                 
00738                 uiBlockSetEmboss(block, UI_EMBOSSN);
00739                 /* Open/Close .................................  */
00740                 uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
00741                 
00742                 /* modifier-type icon */
00743                 uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
00744                 uiBlockSetEmboss(block, UI_EMBOSS);
00745                 
00746                 /* modifier name */
00747                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
00748                 
00749                 /* mode enabling buttons */
00750                 uiBlockBeginAlign(block);
00751                 /* Softbody not allowed in this situation, enforce! */
00752                 if ( ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) 
00753                         && (md->type!=eModifierType_Surface) ) 
00754                 {
00755                         uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
00756                         uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
00757                         
00758                         if (mti->flags & eModifierTypeFlag_SupportsEditmode)
00759                                 uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE);
00760                 }
00761                 if ((ob->type==OB_MESH) && modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) 
00762                 {
00763                         /* -- convert to rna ? */
00764                         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, "Apply modifier to editing cage during Editmode");
00765                         if (index < cageIndex)
00766                                 uiButSetFlag(but, UI_BUT_DISABLED);
00767                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
00768                 }
00769 
00770                 /* tesselation point for curve-typed objects */
00771                 if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
00772                         /* some modifiers could work with pre-tesselated curves only */
00773                         if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
00774                                 /* add disabled pre-tesselated button, so users could have
00775                                    message for this modifiers */
00776                                 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, "This modifier could be applied on splines' points only");
00777                                 uiButSetFlag(but, UI_BUT_DISABLED);
00778                         } else if (mti->type != eModifierTypeType_Constructive) {
00779                                 /* constructive modifiers tesselates curve before applying */
00780                                 uiItemR(row, &ptr, "use_apply_on_spline", 0, "", ICON_NONE);
00781                         }
00782                 }
00783 
00784                 uiBlockEndAlign(block);
00785                 
00786                 /* Up/Down + Delete ........................... */
00787                 uiBlockBeginAlign(block);
00788                 uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
00789                 uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
00790                 uiBlockEndAlign(block);
00791                 
00792                 uiBlockSetEmboss(block, UI_EMBOSSN);
00793                 // When Modifier is a simulation, show button to switch to context rather than the delete button. 
00794                 if (modifier_can_delete(md) && !modifier_is_simulation(md))
00795                         uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
00796                 if (modifier_is_simulation(md) == 1)
00797                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
00798                 else if (modifier_is_simulation(md) == 2)
00799                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
00800                 uiBlockSetEmboss(block, UI_EMBOSS);
00801         }
00802 
00803         
00804         /* modifier settings (under the header) --------------------------------------------------- */
00805         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
00806                 /* apply/convert/copy */
00807                 box= uiLayoutBox(column);
00808                 row= uiLayoutRow(box, 0);
00809                 
00810                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
00811                         /* only here obdata, the rest of modifiers is ob level */
00812                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
00813                         
00814                         if (md->type==eModifierType_ParticleSystem) {
00815                                 ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
00816                                 
00817                                 if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
00818                                         if(ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
00819                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_duplicates_make_real");
00820                                         else if(psys->part->ren_as == PART_DRAW_PATH)
00821                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_modifier_convert");
00822                                 }
00823                         }
00824                         else {
00825                                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
00826                                 uiItemEnumO(row, "OBJECT_OT_modifier_apply", "Apply", 0, "apply_as", MODIFIER_APPLY_DATA);
00827                                 
00828                                 if (modifier_sameTopology(md))
00829                                         uiItemEnumO(row, "OBJECT_OT_modifier_apply", "Apply as Shape", 0, "apply_as", MODIFIER_APPLY_SHAPE);
00830                         }
00831                         
00832                         uiBlockClearButLock(block);
00833                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
00834                         
00835                         if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke))
00836                                 uiItemO(row, "Copy", ICON_NONE, "OBJECT_OT_modifier_copy");
00837                 }
00838                 
00839                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
00840                 result= uiLayoutColumn(box, 0);
00841                 block= uiLayoutAbsoluteBlock(box);
00842         }
00843         
00844         /* error messages */
00845         if(md->error) {
00846                 box = uiLayoutBox(column);
00847                 row = uiLayoutRow(box, 0);
00848                 uiItemL(row, md->error, ICON_ERROR);
00849         }
00850         
00851         return result;
00852 }
00853 
00854 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
00855 {
00856         Scene *scene = CTX_data_scene(C);
00857         Object *ob;
00858         ModifierData *md, *vmd;
00859         int i, lastCageIndex, cageIndex;
00860 
00861         /* verify we have valid data */
00862         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
00863                 RNA_warning("uiTemplateModifier: Expected modifier on object.\n");
00864                 return NULL;
00865         }
00866 
00867         ob= ptr->id.data;
00868         md= ptr->data;
00869 
00870         if(!ob || !(GS(ob->id.name) == ID_OB)) {
00871                 RNA_warning("uiTemplateModifier: Expected modifier on object.\n");
00872                 return NULL;
00873         }
00874         
00875         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
00876         
00877         /* find modifier and draw it */
00878         cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
00879 
00880         // XXX virtual modifiers are not accesible for python
00881         vmd = modifiers_getVirtualModifierList(ob);
00882 
00883         for(i=0; vmd; i++, vmd=vmd->next) {
00884                 if(md == vmd)
00885                         return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex);
00886                 else if(vmd->mode & eModifierMode_Virtual)
00887                         i--;
00888         }
00889 
00890         return NULL;
00891 }
00892 
00893 /************************ Constraint Template *************************/
00894 
00895 #include "DNA_constraint_types.h"
00896 
00897 #include "BKE_action.h"
00898 #include "BKE_constraint.h"
00899 
00900 #define REDRAWIPO                                       1
00901 #define REDRAWNLA                                       2
00902 #define REDRAWBUTSOBJECT                        3               
00903 #define REDRAWACTION                            4
00904 #define B_CONSTRAINT_TEST                       5
00905 #define B_CONSTRAINT_CHANGETARGET       6
00906 #define REMAKEIPO                                       8
00907 #define B_DIFF                                          9
00908 
00909 static void do_constraint_panels(bContext *C, void *ob_pt, int event)
00910 {
00911         Main *bmain= CTX_data_main(C);
00912         Scene *scene= CTX_data_scene(C);
00913         Object *ob= (Object *)ob_pt;
00914         
00915         switch(event) {
00916         case B_CONSTRAINT_TEST:
00917                 break;  // no handling
00918         case B_CONSTRAINT_CHANGETARGET:
00919                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
00920                 DAG_scene_sort(bmain, scene);
00921                 break;
00922         default:
00923                 break;
00924         }
00925 
00926         // note: RNA updates now call this, commenting else it gets called twice.
00927         // if there are problems because of this, then rna needs changed update functions.
00928         // 
00929         // object_test_constraints(ob);
00930         // if(ob->pose) update_pose_constraint_flags(ob->pose);
00931         
00932         if(ob->type==OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
00933         else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
00934 
00935         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
00936 }
00937 
00938 static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
00939 {
00940         ED_object_constraint_set_active(ob_v, con_v);
00941 }
00942 
00943 /* draw panel showing settings for a constraint */
00944 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
00945 {
00946         bPoseChannel *pchan= get_active_posechannel(ob);
00947         bConstraintTypeInfo *cti;
00948         uiBlock *block;
00949         uiLayout *result= NULL, *col, *box, *row;
00950         PointerRNA ptr;
00951         char typestr[32];
00952         short proxy_protected, xco=0, yco=0;
00953         // int rb_col; // UNUSED
00954 
00955         /* get constraint typeinfo */
00956         cti= constraint_get_typeinfo(con);
00957         if (cti == NULL) {
00958                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
00959                 if (con->type == CONSTRAINT_TYPE_NULL)
00960                         strcpy(typestr, "Null");
00961                 else
00962                         strcpy(typestr, "Unknown");
00963         }
00964         else
00965                 strcpy(typestr, cti->name);
00966                 
00967         /* determine whether constraint is proxy protected or not */
00968         if (proxylocked_constraints_owner(ob, pchan))
00969                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
00970         else
00971                 proxy_protected= 0;
00972 
00973         /* unless button has own callback, it adds this callback to button */
00974         block= uiLayoutGetBlock(layout);
00975         uiBlockSetHandleFunc(block, do_constraint_panels, ob);
00976         uiBlockSetFunc(block, constraint_active_func, ob, con);
00977 
00978         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
00979 
00980         col= uiLayoutColumn(layout, 1);
00981         uiLayoutSetContextPointer(col, "constraint", &ptr);
00982 
00983         box= uiLayoutBox(col);
00984         row = uiLayoutRow(box, 0);
00985         block= uiLayoutGetBlock(box);
00986 
00987         /* Draw constraint header */
00988 
00989         /* open/close */
00990         uiBlockSetEmboss(block, UI_EMBOSSN);
00991         uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
00992         uiBlockSetEmboss(block, UI_EMBOSS);
00993         
00994         /* name */
00995         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
00996 
00997         if (con->flag & CONSTRAINT_DISABLE)
00998                 uiLayoutSetRedAlert(row, 1);
00999         
01000         if(proxy_protected == 0) {
01001                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
01002         }
01003         else
01004                 uiItemL(row, con->name, ICON_NONE);
01005         
01006         uiLayoutSetRedAlert(row, 0);
01007         
01008         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
01009         if (proxy_protected) {
01010                 uiBlockSetEmboss(block, UI_EMBOSSN);
01011                 
01012                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
01013                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
01014                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
01015                 
01016                 uiBlockSetEmboss(block, UI_EMBOSS);
01017         }
01018         else {
01019                 short prev_proxylock, show_upbut, show_downbut;
01020                 
01021                 /* Up/Down buttons: 
01022                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
01023                  *      as that poses problems when restoring them, so disable the "up" button where
01024                  *      it may cause this situation. 
01025                  *
01026                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
01027                  */
01028                 if (proxylocked_constraints_owner(ob, pchan)) {
01029                         if (con->prev) {
01030                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
01031                         }
01032                         else
01033                                 prev_proxylock= 0;
01034                 }
01035                 else
01036                         prev_proxylock= 0;
01037                         
01038                 show_upbut= ((prev_proxylock == 0) && (con->prev));
01039                 show_downbut= (con->next) ? 1 : 0;
01040                 
01041                 /* enabled */
01042                 uiBlockSetEmboss(block, UI_EMBOSSN);
01043                 uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
01044                 uiBlockSetEmboss(block, UI_EMBOSS);
01045                 
01046                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
01047                 
01048                 /* up/down */
01049                 if (show_upbut || show_downbut) {
01050                         uiBlockBeginAlign(block);
01051                         if (show_upbut)
01052                                 uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
01053                                 
01054                         if (show_downbut)
01055                                 uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
01056                         uiBlockEndAlign(block);
01057                 }
01058                 
01059                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
01060                 uiBlockSetEmboss(block, UI_EMBOSSN);
01061                 uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
01062                 uiBlockSetEmboss(block, UI_EMBOSS);
01063         }
01064 
01065         /* Set but-locks for protected settings (magic numbers are used here!) */
01066         if (proxy_protected)
01067                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
01068 
01069         /* Draw constraint data */
01070         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
01071                 (yco) -= 21;
01072         }
01073         else {
01074                 box= uiLayoutBox(col);
01075                 block= uiLayoutAbsoluteBlock(box);
01076                 result= box;
01077         }
01078 
01079         /* clear any locks set up for proxies/lib-linking */
01080         uiBlockClearButLock(block);
01081 
01082         return result;
01083 }
01084 
01085 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
01086 {
01087         Object *ob;
01088         bConstraint *con;
01089 
01090         /* verify we have valid data */
01091         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
01092                 RNA_warning("uiTemplateConstraint: Expected constraint on object.\n");
01093                 return NULL;
01094         }
01095 
01096         ob= ptr->id.data;
01097         con= ptr->data;
01098 
01099         if(!ob || !(GS(ob->id.name) == ID_OB)) {
01100                 RNA_warning("uiTemplateConstraint: Expected constraint on object.\n");
01101                 return NULL;
01102         }
01103         
01104         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
01105 
01106         /* hrms, the temporal constraint should not draw! */
01107         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
01108                 bKinematicConstraint *data= con->data;
01109                 if(data->flag & CONSTRAINT_IK_TEMP)
01110                         return NULL;
01111         }
01112 
01113         return draw_constraint(layout, ob, con);
01114 }
01115 
01116 
01117 /************************* Preview Template ***************************/
01118 
01119 #include "DNA_lamp_types.h"
01120 #include "DNA_material_types.h"
01121 #include "DNA_world_types.h"
01122 
01123 #define B_MATPRV 1
01124 
01125 static void do_preview_buttons(bContext *C, void *arg, int event)
01126 {
01127         switch(event) {
01128                 case B_MATPRV:
01129                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
01130                         break;
01131         }
01132 }
01133 
01134 void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot)
01135 {
01136         uiLayout *row, *col;
01137         uiBlock *block;
01138         Material *ma= NULL;
01139         Tex *tex = (Tex*)id;
01140         ID *pid, *pparent;
01141         short *pr_texture= NULL;
01142         PointerRNA material_ptr;
01143         PointerRNA texture_ptr;
01144 
01145         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
01146                 RNA_warning("uiTemplatePreview: Expected ID of type material, texture, lamp or world.\n");
01147                 return;
01148         }
01149 
01150         /* decide what to render */
01151         pid= id;
01152         pparent= NULL;
01153 
01154         if(id && (GS(id->name) == ID_TE)) {
01155                 if(parent && (GS(parent->name) == ID_MA))
01156                         pr_texture= &((Material*)parent)->pr_texture;
01157                 else if(parent && (GS(parent->name) == ID_WO))
01158                         pr_texture= &((World*)parent)->pr_texture;
01159                 else if(parent && (GS(parent->name) == ID_LA))
01160                         pr_texture= &((Lamp*)parent)->pr_texture;
01161 
01162                 if(pr_texture) {
01163                         if(*pr_texture == TEX_PR_OTHER)
01164                                 pid= parent;
01165                         else if(*pr_texture == TEX_PR_BOTH)
01166                                 pparent= parent;
01167                 }
01168         }
01169 
01170         /* layout */
01171         block= uiLayoutGetBlock(layout);
01172         row= uiLayoutRow(layout, 0);
01173         col= uiLayoutColumn(row, 0);
01174         uiLayoutSetKeepAspect(col, 1);
01175         
01176         /* add preview */
01177         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, pid, 0.0, 0.0, 0, 0, "");
01178         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
01179         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
01180         
01181         /* add buttons */
01182         if (pid && show_buttons) {
01183                 if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
01184                         if(GS(pid->name) == ID_MA) ma= (Material*)pid;
01185                         else ma= (Material*)pparent;
01186                         
01187                         /* Create RNA Pointer */
01188                         RNA_pointer_create(id, &RNA_Material, ma, &material_ptr);
01189 
01190                         col = uiLayoutColumn(row, 1);
01191                         uiLayoutSetScaleX(col, 1.5);
01192                         uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
01193                 }
01194 
01195                 if(pr_texture) {
01196                         /* Create RNA Pointer */
01197                         RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
01198                         
01199                         uiLayoutRow(layout, 1);
01200                         uiDefButS(block, ROW, B_MATPRV, "Texture",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
01201                         if(GS(parent->name) == ID_MA)
01202                                 uiDefButS(block, ROW, B_MATPRV, "Material",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
01203                         else if(GS(parent->name) == ID_LA)
01204                                 uiDefButS(block, ROW, B_MATPRV, "Lamp",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
01205                         else if(GS(parent->name) == ID_WO)
01206                                 uiDefButS(block, ROW, B_MATPRV, "World",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
01207                         uiDefButS(block, ROW, B_MATPRV, "Both",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
01208                         
01209                         /* Alpha buton for texture preview */
01210                         if(*pr_texture!=TEX_PR_OTHER) {
01211                                 row = uiLayoutRow(layout, 0);
01212                                 uiItemR(row, &texture_ptr, "use_preview_alpha", 0, NULL, ICON_NONE);
01213                         }
01214                 }
01215         }
01216 }
01217 
01218 /********************** ColorRamp Template **************************/
01219 
01220 
01221 typedef struct RNAUpdateCb {
01222         PointerRNA ptr;
01223         PropertyRNA *prop;
01224 } RNAUpdateCb;
01225 
01226 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
01227 {
01228         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
01229 
01230         /* we call update here on the pointer property, this way the
01231            owner of the curve mapping can still define it's own update
01232            and notifier, even if the CurveMapping struct is shared. */
01233         RNA_property_update(C, &cb->ptr, cb->prop);
01234 }
01235 
01236 #define B_BANDCOL 1
01237 
01238 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
01239 {
01240         ColorBand *coba= coba_v;
01241         float pos= 0.5f;
01242 
01243         if(coba->tot > 1) {
01244                 if(coba->cur > 0)       pos= (coba->data[coba->cur-1].pos + coba->data[coba->cur].pos) * 0.5f;
01245                 else                            pos= (coba->data[coba->cur+1].pos + coba->data[coba->cur].pos) * 0.5f;
01246         }
01247 
01248         if(colorband_element_add(coba, pos)) {
01249                 rna_update_cb(C, cb_v, NULL);
01250                 ED_undo_push(C, "Add colorband");       
01251         }
01252 }
01253 
01254 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
01255 {
01256         ColorBand *coba= coba_v;
01257 
01258         if(colorband_element_remove(coba, coba->cur)) {
01259                 ED_undo_push(C, "Delete colorband");
01260                 rna_update_cb(C, cb_v, NULL);
01261         }
01262 }
01263 
01264 static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
01265 {
01266         CBData data_tmp[MAXCOLORBAND];
01267 
01268         ColorBand *coba= coba_v;
01269         int a;
01270 
01271         for(a=0; a<coba->tot; a++) {
01272                 data_tmp[a]= coba->data[coba->tot - (a + 1)];
01273         }
01274         for(a=0; a<coba->tot; a++) {
01275                 data_tmp[a].pos = 1.0f - data_tmp[a].pos;
01276                 coba->data[a]= data_tmp[a];
01277         }
01278 
01279         /* may as well flip the cur*/
01280         coba->cur= coba->tot - (coba->cur + 1);
01281 
01282         ED_undo_push(C, "Flip colorband");
01283 
01284         rna_update_cb(C, cb_v, NULL);
01285 }
01286 
01287 
01288 /* offset aligns from bottom, standard width 300, height 115 */
01289 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
01290 {
01291         uiBut *bt;
01292         uiLayout *row;
01293         const int line1_y= yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
01294         const int line2_y= yoffs + 65;
01295 
01296         if(coba==NULL) return;
01297 
01298         bt= uiDefBut(block, BUT, 0,     "Add",                  0+xoffs,line1_y,40,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
01299         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
01300 
01301         bt= uiDefBut(block, BUT, 0,     "Delete",               45+xoffs,line1_y,45,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Delete the active position");
01302         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
01303 
01304 
01305         /* XXX, todo for later - convert to operator - campbell */
01306         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,line1_y,20,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Flip colorband");
01307         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
01308 
01309         uiDefButS(block, NUM, 0,                "",                             120+xoffs,line1_y,80, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop");
01310 
01311         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
01312                         210+xoffs, line1_y, 90, UI_UNIT_Y,              &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
01313         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01314         uiBlockEndAlign(block);
01315 
01316         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,line2_y,300,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
01317         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01318 
01319 
01320 
01321         if(coba->tot) {
01322                 CBData *cbd= coba->data + coba->cur;
01323 
01324                 /* better to use rna so we can animate them */
01325                 PointerRNA ptr;
01326                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
01327                 row= uiLayoutRow(layout, 0);
01328                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
01329                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
01330         }
01331 
01332 }
01333 
01334 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
01335 {
01336         uiBut *bt;
01337         float unit= (butr->xmax-butr->xmin)/14.0f;
01338         float xs= butr->xmin;
01339 
01340         uiBlockBeginAlign(block);
01341         bt= uiDefBut(block, BUT, 0,     "Add",                  xs,butr->ymin+UI_UNIT_Y,2.0f*unit,UI_UNIT_Y,    NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
01342         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
01343         bt= uiDefBut(block, BUT, 0,     "Delete",               xs+2.0f*unit,butr->ymin+UI_UNIT_Y,1.5f*unit,UI_UNIT_Y,  NULL, 0, 0, 0, 0, "Delete the active position");
01344         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
01345         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, "Flip the color ramp");
01346         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
01347         uiBlockEndAlign(block);
01348 
01349         if(coba->tot) {
01350                 CBData *cbd= coba->data + coba->cur;
01351                 PointerRNA ptr;
01352                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
01353                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
01354         }
01355 
01356         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
01357                         xs+10.0f*unit, butr->ymin+UI_UNIT_Y, unit*4, UI_UNIT_Y,         &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
01358         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01359 
01360         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
01361         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01362 
01363         uiBlockEndAlign(block);
01364 }
01365 
01366 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
01367 {
01368         if(small)
01369                 colorband_buttons_small(layout, block, coba, butr, cb);
01370         else
01371                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
01372 }
01373 
01374 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
01375 {
01376         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01377         PointerRNA cptr;
01378         RNAUpdateCb *cb;
01379         uiBlock *block;
01380         rctf rect;
01381 
01382         if(!prop || RNA_property_type(prop) != PROP_POINTER)
01383                 return;
01384 
01385         cptr= RNA_property_pointer_get(ptr, prop);
01386         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
01387                 return;
01388 
01389         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
01390         cb->ptr= *ptr;
01391         cb->prop= prop;
01392 
01393         rect.xmin= 0; rect.xmax= 200;
01394         rect.ymin= 0; rect.ymax= 190;
01395 
01396         block= uiLayoutAbsoluteBlock(layout);
01397         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
01398 
01399         MEM_freeN(cb);
01400 }
01401 
01402 /********************* Histogram Template ************************/
01403 
01404 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
01405 {
01406         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01407         PointerRNA cptr;
01408         RNAUpdateCb *cb;
01409         uiBlock *block;
01410         uiBut *bt;
01411         Histogram *hist;
01412         rctf rect;
01413         
01414         if(!prop || RNA_property_type(prop) != PROP_POINTER)
01415                 return;
01416         
01417         cptr= RNA_property_pointer_get(ptr, prop);
01418         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
01419                 return;
01420         
01421         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
01422         cb->ptr= *ptr;
01423         cb->prop= prop;
01424         
01425         rect.xmin= 0; rect.xmax= 200;
01426         rect.ymin= 0; rect.ymax= 190;
01427         
01428         block= uiLayoutAbsoluteBlock(layout);
01429         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
01430 
01431         hist = (Histogram *)cptr.data;
01432 
01433         hist->height= (hist->height<=UI_UNIT_Y)?UI_UNIT_Y:hist->height;
01434 
01435         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
01436         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01437 
01438         MEM_freeN(cb);
01439 }
01440 
01441 /********************* Waveform Template ************************/
01442 
01443 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
01444 {
01445         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01446         PointerRNA cptr;
01447         RNAUpdateCb *cb;
01448         uiBlock *block;
01449         uiBut *bt;
01450         Scopes *scopes;
01451         rctf rect;
01452         
01453         if(!prop || RNA_property_type(prop) != PROP_POINTER)
01454                 return;
01455         
01456         cptr= RNA_property_pointer_get(ptr, prop);
01457         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
01458                 return;
01459         scopes = (Scopes *)cptr.data;
01460         
01461         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
01462         cb->ptr= *ptr;
01463         cb->prop= prop;
01464         
01465         rect.xmin= 0; rect.xmax= 200;
01466         rect.ymin= 0; rect.ymax= 190;
01467         
01468         block= uiLayoutAbsoluteBlock(layout);
01469         
01470         scopes->wavefrm_height= (scopes->wavefrm_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->wavefrm_height;
01471 
01472         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
01473         (void)bt; // UNUSED
01474         
01475         MEM_freeN(cb);
01476 }
01477 
01478 /********************* Vectorscope Template ************************/
01479 
01480 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
01481 {
01482         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01483         PointerRNA cptr;
01484         RNAUpdateCb *cb;
01485         uiBlock *block;
01486         uiBut *bt;
01487         Scopes *scopes;
01488         rctf rect;
01489         
01490         if(!prop || RNA_property_type(prop) != PROP_POINTER)
01491                 return;
01492         
01493         cptr= RNA_property_pointer_get(ptr, prop);
01494         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
01495                 return;
01496         scopes = (Scopes *)cptr.data;
01497 
01498         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
01499         cb->ptr= *ptr;
01500         cb->prop= prop;
01501         
01502         rect.xmin= 0; rect.xmax= 200;
01503         rect.ymin= 0; rect.ymax= 190;
01504         
01505         block= uiLayoutAbsoluteBlock(layout);
01506 
01507         scopes->vecscope_height= (scopes->vecscope_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->vecscope_height;
01508         
01509         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
01510         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01511         
01512         MEM_freeN(cb);
01513 }
01514 
01515 /********************* CurveMapping Template ************************/
01516 
01517 
01518 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
01519 {
01520         CurveMapping *cumap = cumap_v;
01521         float d;
01522 
01523         /* we allow 20 times zoom */
01524         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
01525                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
01526                 cumap->curr.xmin+= d;
01527                 cumap->curr.xmax-= d;
01528                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
01529                 cumap->curr.ymin+= d;
01530                 cumap->curr.ymax-= d;
01531         }
01532 
01533         ED_region_tag_redraw(CTX_wm_region(C));
01534 }
01535 
01536 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
01537 {
01538         CurveMapping *cumap = cumap_v;
01539         float d, d1;
01540 
01541         /* we allow 20 times zoom, but dont view outside clip */
01542         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
01543                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
01544 
01545                 if(cumap->flag & CUMA_DO_CLIP) 
01546                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
01547                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
01548                 cumap->curr.xmin-= d1;
01549 
01550                 d1= d;
01551                 if(cumap->flag & CUMA_DO_CLIP) 
01552                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
01553                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
01554                 cumap->curr.xmax+= d1;
01555 
01556                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
01557 
01558                 if(cumap->flag & CUMA_DO_CLIP) 
01559                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
01560                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
01561                 cumap->curr.ymin-= d1;
01562 
01563                 d1= d;
01564                 if(cumap->flag & CUMA_DO_CLIP) 
01565                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
01566                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
01567                 cumap->curr.ymax+= d1;
01568         }
01569 
01570         ED_region_tag_redraw(CTX_wm_region(C));
01571 }
01572 
01573 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
01574 {
01575         CurveMapping *cumap = cumap_v;
01576 
01577         curvemapping_changed(cumap, 0);
01578 }       
01579 
01580 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
01581 {
01582         CurveMapping *cumap = cumap_v;
01583 
01584         curvemap_remove(cumap->cm+cumap->cur, SELECT);
01585         curvemapping_changed(cumap, 0);
01586 
01587         rna_update_cb(C, cb_v, NULL);
01588 }
01589 
01590 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
01591 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
01592 {
01593         CurveMapping *cumap = cumap_v;
01594         uiBlock *block;
01595         uiBut *bt;
01596         float width= 8*UI_UNIT_X;
01597 
01598         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
01599 
01600         /* use this for a fake extra empy space around the buttons */
01601         uiDefBut(block, LABEL, 0, "",                   -4, 16, width+8, 6*UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
01602 
01603         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
01604                         0,5*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
01605         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
01606 
01607         uiBlockBeginAlign(block);
01608         uiDefButF(block, NUM, 0, "Min X ",       0,4*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
01609         uiDefButF(block, NUM, 0, "Min Y ",       0,3*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
01610         uiDefButF(block, NUM, 0, "Max X ",       0,2*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
01611         uiDefButF(block, NUM, 0, "Max Y ",       0,UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
01612 
01613         uiBlockSetDirection(block, UI_RIGHT);
01614 
01615         uiEndBlock(C, block);
01616         return block;
01617 }
01618 
01619 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
01620 {
01621         CurveMapping *cumap = cumap_v;
01622         CurveMap *cuma= cumap->cm+cumap->cur;
01623 
01624         switch(event) {
01625                 case 0: /* reset */
01626                         curvemap_reset(cuma, &cumap->clipr,     cumap->preset, CURVEMAP_SLOPE_POSITIVE);
01627                         curvemapping_changed(cumap, 0);
01628                         break;
01629                 case 1:
01630                         cumap->curr= cumap->clipr;
01631                         break;
01632                 case 2: /* set vector */
01633                         curvemap_sethandle(cuma, 1);
01634                         curvemapping_changed(cumap, 0);
01635                         break;
01636                 case 3: /* set auto */
01637                         curvemap_sethandle(cuma, 0);
01638                         curvemapping_changed(cumap, 0);
01639                         break;
01640                 case 4: /* extend horiz */
01641                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
01642                         curvemapping_changed(cumap, 0);
01643                         break;
01644                 case 5: /* extend extrapolate */
01645                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
01646                         curvemapping_changed(cumap, 0);
01647                         break;
01648         }
01649         ED_region_tag_redraw(CTX_wm_region(C));
01650 }
01651 
01652 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
01653 {
01654         uiBlock *block;
01655         short yco= 0, menuwidth=10*UI_UNIT_X;
01656 
01657         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
01658         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
01659 
01660         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
01661         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
01662         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
01663         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 4, "");
01664         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 5, "");
01665         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
01666 
01667         uiBlockSetDirection(block, UI_RIGHT);
01668         uiTextBoundsBlock(block, 50);
01669 
01670         uiEndBlock(C, block);
01671         return block;
01672 }
01673 
01674 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
01675 {
01676         uiBlock *block;
01677         short yco= 0, menuwidth=10*UI_UNIT_X;
01678 
01679         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
01680         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
01681 
01682         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
01683         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
01684         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
01685         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
01686 
01687         uiBlockSetDirection(block, UI_RIGHT);
01688         uiTextBoundsBlock(block, 50);
01689 
01690         uiEndBlock(C, block);
01691         return block;
01692 }
01693 
01694 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
01695 {
01696         ED_region_tag_redraw(CTX_wm_region(C));
01697 }
01698 
01699 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
01700 {
01701         CurveMapping *cumap = cumap_v;
01702         int a;
01703         
01704         cumap->preset = CURVE_PRESET_LINE;
01705         for(a=0; a<CM_TOT; a++)
01706                 curvemap_reset(cumap->cm+a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
01707         
01708         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
01709         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
01710         curvemapping_set_black_white(cumap, NULL, NULL);
01711         
01712         curvemapping_changed(cumap, 0);
01713 
01714         rna_update_cb(C, cb_v, NULL);
01715 }
01716 
01717 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
01718 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
01719 {
01720         CurveMapping *cumap= ptr->data;
01721         uiLayout *row, *sub, *split;
01722         uiBlock *block;
01723         uiBut *bt;
01724         float dx= UI_UNIT_X;
01725         int icon, size;
01726         int bg=-1;
01727 
01728         block= uiLayoutGetBlock(layout);
01729 
01730         /* curve chooser */
01731         row= uiLayoutRow(layout, 0);
01732 
01733         if(labeltype=='v') {
01734                 /* vector */
01735                 sub= uiLayoutRow(row, 1);
01736                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
01737 
01738                 if(cumap->cm[0].curve) {
01739                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
01740                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01741                 }
01742                 if(cumap->cm[1].curve) {
01743                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
01744                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01745                 }
01746                 if(cumap->cm[2].curve) {
01747                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
01748                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01749                 }
01750         }
01751         else if(labeltype=='c') {
01752                 /* color */
01753                 sub= uiLayoutRow(row, 1);
01754                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
01755 
01756                 if(cumap->cm[3].curve) {
01757                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
01758                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01759                 }
01760                 if(cumap->cm[0].curve) {
01761                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
01762                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01763                 }
01764                 if(cumap->cm[1].curve) {
01765                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
01766                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01767                 }
01768                 if(cumap->cm[2].curve) {
01769                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
01770                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01771                 }
01772         }
01773         else if (labeltype == 'h') {
01774                 /* HSV */
01775                 sub= uiLayoutRow(row, 1);
01776                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
01777                 
01778                 if(cumap->cm[0].curve) {
01779                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
01780                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01781                 }
01782                 if(cumap->cm[1].curve) {
01783                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
01784                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01785                 }
01786                 if(cumap->cm[2].curve) {
01787                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
01788                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
01789                 }
01790         }
01791         else
01792                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
01793         
01794         if (labeltype=='h')
01795                 bg = UI_GRAD_H;
01796 
01797         /* operation buttons */
01798         sub= uiLayoutRow(row, 1);
01799 
01800         uiBlockSetEmboss(block, UI_EMBOSSN);
01801 
01802         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
01803         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
01804 
01805         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
01806         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
01807 
01808         if(brush)
01809                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, "Tools");
01810         else
01811                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, "Tools");
01812 
01813         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01814 
01815         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
01816         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, "Clipping Options");
01817         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
01818 
01819         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
01820         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
01821 
01822         uiBlockSetEmboss(block, UI_EMBOSS);
01823 
01824         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
01825 
01826         /* curve itself */
01827         size= uiLayoutGetWidth(layout);
01828         row= uiLayoutRow(layout, 0);
01829         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
01830 
01831         /* black/white levels */
01832         if(levels) {
01833                 split= uiLayoutSplit(layout, 0, 0);
01834                 uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
01835                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
01836 
01837                 uiLayoutRow(layout, 0);
01838                 bt=uiDefBut(block, BUT, 0, "Reset",     0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves");
01839                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
01840         }
01841 
01842         uiBlockSetNFunc(block, NULL, NULL, NULL);
01843 }
01844 
01845 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
01846 {
01847         RNAUpdateCb *cb;
01848         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01849         PointerRNA cptr;
01850 
01851         if(!prop) {
01852                 RNA_warning("uiTemplateCurveMapping: curve property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
01853                 return;
01854         }
01855 
01856         if(RNA_property_type(prop) != PROP_POINTER) {
01857                 RNA_warning("uiTemplateCurveMapping: curve is not a pointer: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
01858                 return;
01859         }
01860 
01861         cptr= RNA_property_pointer_get(ptr, prop);
01862         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
01863                 return;
01864 
01865         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
01866         cb->ptr= *ptr;
01867         cb->prop= prop;
01868 
01869         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
01870 
01871         MEM_freeN(cb);
01872 }
01873 
01874 /********************* ColorWheel Template ************************/
01875 
01876 #define WHEEL_SIZE      100
01877 
01878 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
01879 {
01880         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01881         uiBlock *block= uiLayoutGetBlock(layout);
01882         uiLayout *col, *row;
01883         uiBut *but;
01884         float softmin, softmax, step, precision;
01885         
01886         if (!prop) {
01887                 RNA_warning("uiTemplateColorWheel: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
01888                 return;
01889         }
01890 
01891         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
01892         
01893         col = uiLayoutColumn(layout, 0);
01894         row= uiLayoutRow(col, 1);
01895         
01896         but= uiDefButR_prop(block, HSVCIRCLE, 0, "",    0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, "");
01897 
01898         if(lock) {
01899                 but->flag |= UI_BUT_COLOR_LOCK;
01900         }
01901 
01902         if(lock_luminosity) {
01903                 float color[4]; /* incase of alpha */
01904                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
01905                 RNA_property_float_get_array(ptr, prop, color);
01906                 but->a2= len_v3(color);
01907         }
01908 
01909         if(cubic)
01910                 but->flag |= UI_BUT_COLOR_CUBIC;
01911 
01912         uiItemS(row);
01913         
01914         if (value_slider)
01915                 uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
01916 }
01917 
01918 /********************* Layer Buttons Template ************************/
01919 
01920 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
01921 {
01922         uiBut *but = arg1;
01923         int cur = GET_INT_FROM_POINTER(arg2);
01924         wmWindow *win= CTX_wm_window(C);
01925         int i, tot, shift= win->eventstate->shift;
01926 
01927         if(!shift) {
01928                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
01929                 
01930                 /* Normally clicking only selects one layer */
01931                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
01932                 for(i = 0; i < tot; ++i) {
01933                         if(i != cur)
01934                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
01935                 }
01936         }
01937         
01938         /* view3d layer change should update depsgraph (invisible object changed maybe) */
01939         /* see view3d_header.c */
01940 }
01941 
01942 // TODO:
01943 //      - for now, grouping of layers is determined by dividing up the length of 
01944 //        the array of layer bitflags
01945 
01946 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
01947                           PointerRNA *used_ptr, const char *used_propname, int active_layer)
01948 {
01949         uiLayout *uRow, *uCol;
01950         PropertyRNA *prop, *used_prop= NULL;
01951         int groups, cols, layers;
01952         int group, col, layer, row;
01953         int cols_per_group = 5;
01954 
01955         prop= RNA_struct_find_property(ptr, propname);
01956         if (!prop) {
01957                 RNA_warning("uiTemplateLayer: layers property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
01958                 return;
01959         }
01960         
01961         /* the number of layers determines the way we group them 
01962          *      - we want 2 rows only (for now)
01963          *      - the number of columns (cols) is the total number of buttons per row
01964          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
01965          *      - for now, only split into groups if group will have at least 5 items
01966          */
01967         layers= RNA_property_array_length(ptr, prop);
01968         cols= (layers / 2) + (layers % 2);
01969         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
01970 
01971         if(used_ptr && used_propname) {
01972                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
01973                 if (!used_prop) {
01974                         RNA_warning("uiTemplateLayer: used layers property not found: %s.%s\n", RNA_struct_identifier(ptr->type), used_propname);
01975                         return;
01976                 }
01977 
01978                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
01979                         used_prop = NULL;
01980         }
01981         
01982         /* layers are laid out going across rows, with the columns being divided into groups */
01983         
01984         for (group= 0; group < groups; group++) {
01985                 uCol= uiLayoutColumn(layout, 1);
01986                 
01987                 for (row= 0; row < 2; row++) {
01988                         uiBlock *block;
01989                         uiBut *but;
01990 
01991                         uRow= uiLayoutRow(uCol, 1);
01992                         block= uiLayoutGetBlock(uRow);
01993                         layer= groups*cols_per_group*row + cols_per_group*group;
01994                         
01995                         /* add layers as toggle buts */
01996                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
01997                                 int icon = 0;
01998                                 int butlay = 1 << layer;
01999 
02000                                 if(active_layer & butlay)
02001                                         icon = ICON_LAYER_ACTIVE;
02002                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
02003                                         icon = ICON_LAYER_USED;
02004                                 
02005                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X/2, UI_UNIT_Y/2);
02006                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
02007                                 but->type= TOG;
02008                         }
02009                 }
02010         }
02011 }
02012 
02013 
02014 /************************* List Template **************************/
02015 
02016 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
02017 {
02018         ID *id= NULL;
02019         int icon;
02020 
02021         if(!itemptr->data)
02022                 return rnaicon;
02023 
02024         /* try ID, material or texture slot */
02025         if(RNA_struct_is_ID(itemptr->type)) {
02026                 id= itemptr->id.data;
02027         }
02028         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
02029                 id= RNA_pointer_get(itemptr, "material").data;
02030         }
02031         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
02032                 id= RNA_pointer_get(itemptr, "texture").data;
02033         }
02034 
02035         /* get icon from ID */
02036         if(id) {
02037                 icon= ui_id_icon_get(C, id, big);
02038 
02039                 if(icon)
02040                         return icon;
02041         }
02042 
02043         return rnaicon;
02044 }
02045 
02046 static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop)
02047 {
02048         uiBlock *block= uiLayoutGetBlock(layout);
02049         uiBut *but;
02050         uiLayout *split, *overlap, *sub, *row;
02051         char *namebuf;
02052         const char *name;
02053         int icon;
02054 
02055         overlap= uiLayoutOverlap(layout);
02056 
02057         /* list item behind label & other buttons */
02058         sub= uiLayoutRow(overlap, 0);
02059 
02060         but= uiDefButR_prop(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
02061         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
02062 
02063         sub= uiLayoutRow(overlap, 0);
02064 
02065         /* retrieve icon and name */
02066         icon= list_item_icon_get(C, itemptr, rnaicon, 0);
02067         if(icon == ICON_NONE || icon == ICON_DOT)
02068                 icon= 0;
02069 
02070         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0);
02071         name= (namebuf)? namebuf: "";
02072 
02073         /* hardcoded types */
02074         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
02075                 uiItemL(sub, name, icon);
02076                 uiBlockSetEmboss(block, UI_EMBOSSN);
02077                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
02078                 uiBlockSetEmboss(block, UI_EMBOSS);
02079         }
02080         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
02081                 uiItemL(sub, name, icon);
02082                 uiBlockSetEmboss(block, UI_EMBOSS);
02083                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
02084         }
02085         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
02086                 uiItemL(sub, name, icon);
02087                 uiBlockSetEmboss(block, UI_EMBOSS);
02088                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
02089         }
02090         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
02091                 /* provision to draw active node name */
02092                 Material *ma, *manode;
02093                 Object *ob= (Object*)ptr->id.data;
02094                 int index= (Material**)itemptr->data - ob->mat;
02095                 
02096                 /* default item with material base name */
02097                 uiItemL(sub, name, icon);
02098                 
02099                 ma= give_current_material(ob, index+1);
02100                 if(ma) {
02101                         manode= give_node_material(ma);
02102                         if(manode) {
02103                                 char str[MAX_ID_NAME + 12];
02104                                 sprintf(str, "Node %s", manode->id.name+2);
02105                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
02106                         }
02107                         else if(ma->use_nodes) {
02108                                 uiItemL(sub, "Node <none>", ICON_NONE);
02109                         }
02110                 }
02111         }
02112         else if(itemptr->type == &RNA_ShapeKey) {
02113                 Object *ob= (Object*)activeptr->data;
02114                 Key *key= (Key*)itemptr->id.data;
02115 
02116                 split= uiLayoutSplit(sub, 0.75f, 0);
02117 
02118                 uiItemL(split, name, icon);
02119 
02120                 uiBlockSetEmboss(block, UI_EMBOSSN);
02121                 row= uiLayoutRow(split, 1);
02122                 if(i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
02123                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
02124 
02125                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
02126                         uiLayoutSetActive(row, 0);
02127                 //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
02128                 uiBlockSetEmboss(block, UI_EMBOSS);
02129         }
02130         else
02131                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
02132 
02133         /* free name */
02134         if(namebuf)
02135                 MEM_freeN(namebuf);
02136 }
02137 
02138 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, const char *activepropname, int rows, int maxrows, int listtype)
02139 {
02140         //Scene *scene= CTX_data_scene(C);
02141         PropertyRNA *prop= NULL, *activeprop;
02142         PropertyType type, activetype;
02143         StructRNA *ptype;
02144         uiLayout *box, *row, *col;
02145         uiBlock *block;
02146         uiBut *but;
02147         Panel *pa;
02148         char *name, str[32];
02149         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
02150 
02151         /* validate arguments */
02152         block= uiLayoutGetBlock(layout);
02153         pa= block->panel;
02154 
02155         if(!pa) {
02156                 RNA_warning("uiTemplateList: only works inside a panel.\n");
02157                 return;
02158         }
02159 
02160         if(!activeptr->data)
02161                 return;
02162         
02163         if(ptr->data) {
02164                 prop= RNA_struct_find_property(ptr, propname);
02165                 if(!prop) {
02166                         RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
02167                         return;
02168                 }
02169         }
02170 
02171         activeprop= RNA_struct_find_property(activeptr, activepropname);
02172         if(!activeprop) {
02173                 RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), activepropname);
02174                 return;
02175         }
02176 
02177         if(prop) {
02178                 type= RNA_property_type(prop);
02179                 if(type != PROP_COLLECTION) {
02180                         RNA_warning("uiTemplateList: Expected collection property.\n");
02181                         return;
02182                 }
02183         }
02184 
02185         activetype= RNA_property_type(activeprop);
02186         if(activetype != PROP_INT) {
02187                 RNA_warning("uiTemplateList: Expected integer property.\n");
02188                 return;
02189         }
02190 
02191         /* get icon */
02192         if(ptr->data && prop) {
02193                 ptype= RNA_property_pointer_type(ptr, prop);
02194                 rnaicon= RNA_struct_ui_icon(ptype);
02195         }
02196 
02197         /* get active data */
02198         activei= RNA_property_int_get(activeptr, activeprop);
02199 
02200         if(listtype == 'i') {
02201                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
02202                 col= uiLayoutColumn(box, 1);
02203                 row= uiLayoutRow(col, 0);
02204 
02205                 if(ptr->data && prop) {
02206                         /* create list items */
02207                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
02208                                 /* create button */
02209                                 if(!(i % 9))
02210                                         row= uiLayoutRow(col, 0);
02211 
02212                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
02213                                 but= uiDefIconButR_prop(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
02214                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
02215                                 
02216 
02217                                 i++;
02218                         }
02219                         RNA_PROP_END;
02220                 }
02221         }
02222         else if(listtype == 'c') {
02223                 /* compact layout */
02224 
02225                 row= uiLayoutRow(layout, 1);
02226 
02227                 if(ptr->data && prop) {
02228                         /* create list items */
02229                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
02230                                 found= (activei == i);
02231 
02232                                 if(found) {
02233                                         /* create button */
02234                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
02235                                         icon= list_item_icon_get(C, &itemptr, rnaicon, 0);
02236                                         uiItemL(row, (name)? name: "", icon);
02237 
02238                                         if(name)
02239                                                 MEM_freeN(name);
02240                                 }
02241 
02242                                 i++;
02243                         }
02244                         RNA_PROP_END;
02245                 }
02246 
02247                 /* if not found, add in dummy button */
02248                 if(i == 0)
02249                         uiItemL(row, "", ICON_NONE);
02250 
02251                 /* next/prev button */
02252                 sprintf(str, "%d :", i);
02253                 but= uiDefIconTextButR_prop(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activeprop, 0, 0, 0, 0, 0, "");
02254                 if(i == 0)
02255                         uiButSetFlag(but, UI_BUT_DISABLED);
02256         }
02257         else {
02258                 /* default rows */
02259                 if(rows == 0)
02260                         rows= 5;
02261                 if (maxrows == 0)
02262                         maxrows = 5;
02263                 if(pa->list_grip_size != 0)
02264                         rows= pa->list_grip_size;
02265 
02266                 /* layout */
02267                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
02268                 row= uiLayoutRow(box, 0);
02269                 col = uiLayoutColumn(row, 1);
02270 
02271                 /* init numbers */
02272                 RNA_property_int_range(activeptr, activeprop, &min, &max);
02273 
02274                 if(prop)
02275                         len= RNA_property_collection_length(ptr, prop);
02276                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
02277 
02278                 /* if list length changes and active is out of view, scroll to it */
02279                 if(pa->list_last_len != len)
02280                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
02281                                 pa->list_scroll= activei;
02282 
02283                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
02284                 pa->list_scroll= MAX2(pa->list_scroll, 0);
02285                 pa->list_size= items;
02286                 pa->list_last_len= len;
02287 
02288                 if(ptr->data && prop) {
02289                         /* create list items */
02290                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
02291                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
02292                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop);
02293 
02294                                 i++;
02295                         }
02296                         RNA_PROP_END;
02297                 }
02298 
02299                 /* add dummy buttons to fill space */
02300                 while(i < pa->list_scroll+items) {
02301                         if(i >= pa->list_scroll)
02302                                 uiItemL(col, "", ICON_NONE);
02303                         i++;
02304                 }
02305 
02306                 /* add scrollbar */
02307                 if(len > items) {
02308                         col= uiLayoutColumn(row, 0);
02309                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
02310                 }
02311         }
02312 }
02313 
02314 /************************* Operator Search Template **************************/
02315 
02316 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
02317 {
02318         wmOperatorType *ot= arg2;
02319         
02320         if(ot)
02321                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
02322 }
02323 
02324 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
02325 {
02326         GHashIterator *iter= WM_operatortype_iter();
02327 
02328         for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
02329                 wmOperatorType *ot= BLI_ghashIterator_getValue(iter);
02330 
02331                 if(BLI_strcasestr(ot->name, str)) {
02332                         if(WM_operator_poll((bContext*)C, ot)) {
02333                                 char name[256];
02334                                 int len= strlen(ot->name);
02335                                 
02336                                 /* display name for menu, can hold hotkey */
02337                                 BLI_strncpy(name, ot->name, 256);
02338                                 
02339                                 /* check for hotkey */
02340                                 if(len < 256-6) {
02341                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
02342                                                 name[len]= '|';
02343                                 }
02344                                 
02345                                 if(0==uiSearchItemAdd(items, name, ot, 0))
02346                                         break;
02347                         }
02348                 }
02349         }
02350         BLI_ghashIterator_free(iter);
02351 }
02352 
02353 void uiTemplateOperatorSearch(uiLayout *layout)
02354 {
02355         uiBlock *block;
02356         uiBut *but;
02357         static char search[256]= "";
02358                 
02359         block= uiLayoutGetBlock(layout);
02360         uiBlockSetCurLayout(block, layout);
02361 
02362         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
02363         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
02364 }
02365 
02366 /************************* Running Jobs Template **************************/
02367 
02368 #define B_STOPRENDER    1
02369 #define B_STOPCAST              2
02370 #define B_STOPANIM              3
02371 #define B_STOPCOMPO             4
02372 
02373 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
02374 {
02375         switch(event) {
02376                 case B_STOPRENDER:
02377                         G.afbreek= 1;
02378                         break;
02379                 case B_STOPCAST:
02380                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
02381                         break;
02382                 case B_STOPANIM:
02383                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
02384                         break;
02385                 case B_STOPCOMPO:
02386                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
02387                         break;
02388         }
02389 }
02390 
02391 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
02392 {
02393         bScreen *screen= CTX_wm_screen(C);
02394         wmWindowManager *wm= CTX_wm_manager(C);
02395         ScrArea *sa= CTX_wm_area(C);
02396         uiBlock *block;
02397         void *owner= NULL;
02398         int handle_event;
02399         
02400         block= uiLayoutGetBlock(layout);
02401         uiBlockSetCurLayout(block, layout);
02402 
02403         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
02404 
02405         if(sa->spacetype==SPACE_NODE) {
02406                 if(WM_jobs_test(wm, sa))
02407                    owner = sa;
02408                 handle_event= B_STOPCOMPO;
02409         } 
02410         else {
02411                 Scene *scene;
02412                 /* another scene can be rendering too, for example via compositor */
02413                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
02414                         if(WM_jobs_test(wm, scene))
02415                                 break;
02416                 owner = scene;
02417                 handle_event= B_STOPRENDER;
02418         }
02419 
02420         if(owner) {
02421                 uiLayout *ui_abs;
02422                 
02423                 ui_abs= uiLayoutAbsolute(layout, 0);
02424                 (void)ui_abs; // UNUSED
02425                 
02426                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
02427                                 0, UI_UNIT_Y*0.1, UI_UNIT_X*0.8, UI_UNIT_Y*0.8, NULL, 0.0f, 0.0f, 0, 0, "Stop this job");
02428                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
02429                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, "Progress");
02430                 
02431                 uiLayoutRow(layout, 0);
02432         }
02433         if(WM_jobs_test(wm, screen))
02434                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
02435         if(screen->animtimer)
02436                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, "Anim Player", 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
02437 }
02438 
02439 /************************* Reports for Last Operator Template **************************/
02440 
02441 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
02442 {
02443         ReportList *reports = CTX_wm_reports(C);
02444         Report *report= BKE_reports_last_displayable(reports);
02445         ReportTimerInfo *rti;
02446         
02447         uiLayout *ui_abs;
02448         uiBlock *block;
02449         uiBut *but;
02450         uiStyle *style= U.uistyles.first;
02451         int width;
02452         int icon=0;
02453         
02454         /* if the report display has timed out, don't show */
02455         if (!reports->reporttimer) return;
02456         
02457         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
02458         
02459         if (!rti || rti->widthfac==0.0f || !report) return;
02460         
02461         ui_abs= uiLayoutAbsolute(layout, 0);
02462         block= uiLayoutGetBlock(ui_abs);
02463         
02464         width = BLF_width(style->widget.uifont_id, report->message);
02465         width = MIN2(rti->widthfac*width, width);
02466         width = MAX2(width, 10);
02467         
02468         /* make a box around the report to make it stand out */
02469         uiBlockBeginAlign(block);
02470         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
02471         /* set the report's bg color in but->col - ROUNDBOX feature */
02472         but->col[0]= FTOCHAR(rti->col[0]);
02473         but->col[1]= FTOCHAR(rti->col[1]);
02474         but->col[2]= FTOCHAR(rti->col[2]);
02475         but->col[3]= 255; 
02476 
02477         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
02478         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
02479         but->col[3]= 255;
02480 
02481         uiBlockEndAlign(block);
02482         
02483         
02484         /* icon and report message on top */
02485         if(report->type & RPT_ERROR_ALL)
02486                 icon = ICON_ERROR;
02487         else if(report->type & RPT_WARNING_ALL)
02488                 icon = ICON_ERROR;
02489         else if(report->type & RPT_INFO_ALL)
02490                 icon = ICON_INFO;
02491         
02492         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
02493          * to be shown instead of icon when appropriate...
02494          */
02495         uiBlockSetEmboss(block, UI_EMBOSSN);
02496 
02497         if (reports->list.first != reports->list.last)
02498                 uiDefIconButO(block, BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, "Click to see rest of reports in textblock: 'Recent Reports'");
02499         else
02500                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
02501 
02502         uiBlockSetEmboss(block, UI_EMBOSS);
02503         
02504         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, "");
02505 }
02506