UI:
[blender-staging.git] / source / blender / editors / interface / interface_utils.c
1 /**
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_action_types.h"
33 #include "DNA_color_types.h"
34 #include "DNA_listBase.h"
35 #include "DNA_material_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_screen_types.h"
38 #include "DNA_windowmanager_types.h"
39
40 #include "BKE_colortools.h"
41 #include "BKE_context.h"
42 #include "BKE_idprop.h"
43 #include "BKE_library.h"
44 #include "BKE_main.h"
45 #include "BKE_utildefines.h"
46
47 #include "RNA_access.h"
48
49 #include "UI_interface.h"
50 #include "UI_resources.h"
51
52 #include "ED_screen.h"
53 #include "ED_util.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58 #include "interface_intern.h"
59
60 #define DEF_BUT_WIDTH           150
61 #define DEF_ICON_BUT_WIDTH      20
62 #define DEF_BUT_HEIGHT          20
63
64 /*************************** RNA Utilities ******************************/
65
66 int UI_GetIconRNA(PointerRNA *ptr)
67 {
68         StructRNA *rnatype= ptr->type;
69
70         if(rnatype == &RNA_Scene)
71                 return ICON_SCENE_DATA;
72         else if(rnatype == &RNA_World)
73                 return ICON_WORLD_DATA;
74         else if(rnatype == &RNA_Object)
75                 return ICON_OBJECT_DATA;
76         else if(rnatype == &RNA_Mesh)
77                 return ICON_MESH_DATA;
78         else if(rnatype == &RNA_MeshVertex)
79                 return ICON_VERTEXSEL;
80         else if(rnatype == &RNA_MeshEdge)
81                 return ICON_EDGESEL;
82         else if(rnatype == &RNA_MeshFace)
83                 return ICON_FACESEL;
84         else if(rnatype == &RNA_MeshTextureFace)
85                 return ICON_FACESEL_HLT;
86         else if(rnatype == &RNA_VertexGroup)
87                 return ICON_VGROUP;
88         else if(rnatype == &RNA_VertexGroupElement)
89                 return ICON_VGROUP;
90         else if(rnatype == &RNA_Curve)
91                 return ICON_CURVE_DATA;
92         else if(rnatype == &RNA_MetaBall)
93                 return ICON_MBALL_DATA;
94         else if(rnatype == &RNA_MetaElement)
95                 return ICON_OUTLINER_DATA_META;
96         else if(rnatype == &RNA_Lattice)
97                 return ICON_LATTICE_DATA;
98         else if(rnatype == &RNA_Armature)
99                 return ICON_ARMATURE_DATA;
100         else if(rnatype == &RNA_Bone)
101                 return ICON_BONE_DATA;
102         else if(rnatype == &RNA_Camera)
103                 return ICON_CAMERA_DATA;
104         else if(rnatype == &RNA_LocalLamp)
105                 return ICON_LAMP_DATA;
106         else if(rnatype == &RNA_AreaLamp)
107                 return ICON_LAMP_DATA;
108         else if(rnatype == &RNA_SpotLamp)
109                 return ICON_LAMP_DATA;
110         else if(rnatype == &RNA_SunLamp)
111                 return ICON_LAMP_DATA;
112         else if(rnatype == &RNA_HemiLamp)
113                 return ICON_LAMP_DATA;
114         else if(rnatype == &RNA_Lamp)
115                 return ICON_LAMP_DATA;
116         else if(rnatype == &RNA_Group)
117                 return ICON_GROUP;
118         else if(rnatype == &RNA_ParticleSystem)
119                 return ICON_PARTICLE_DATA;
120         else if(rnatype == &RNA_ParticleSettings)
121                 return ICON_PARTICLE_DATA;
122         else if(rnatype == &RNA_Material)
123                 return ICON_MATERIAL_DATA;
124         else if(rnatype == &RNA_Texture)
125                 return ICON_TEXTURE_DATA;
126         else if(rnatype == &RNA_TextureSlot)
127                 return ICON_TEXTURE_DATA;
128         else if(rnatype == &RNA_WorldTextureSlot)
129                 return ICON_TEXTURE_DATA;
130         else if(rnatype == &RNA_MaterialTextureSlot)
131                 return ICON_TEXTURE_DATA;
132         else if(rnatype == &RNA_Image)
133                 return ICON_IMAGE_DATA;
134         else if(rnatype == &RNA_Screen)
135                 return ICON_SPLITSCREEN;
136         else if(rnatype == &RNA_NodeTree)
137                 return ICON_NODE;
138         else if(rnatype == &RNA_Text)
139                 return ICON_TEXT;
140         else if(rnatype == &RNA_Sound)
141                 return ICON_SOUND;
142         else if(rnatype == &RNA_Brush)
143                 return ICON_BRUSH_DATA;
144         else if(rnatype == &RNA_VectorFont)
145                 return ICON_FONT;
146         else if(rnatype == &RNA_Library)
147                 return ICON_LIBRARY_DATA_DIRECT;
148         else if(rnatype == &RNA_Action)
149                 return ICON_ACTION;
150         else if(rnatype == &RNA_FCurve)
151                 return ICON_ANIM_DATA;
152         //else if(rnatype == &RNA_Ipo)
153         //      return ICON_ANIM_DATA;
154         else if(rnatype == &RNA_Key)
155                 return ICON_SHAPEKEY_DATA;
156         else if(rnatype == &RNA_Main)
157                 return ICON_BLENDER;
158         else if(rnatype == &RNA_Struct)
159                 return ICON_RNA;
160         else if(rnatype == &RNA_Property)
161                 return ICON_RNA;
162         else if(rnatype == &RNA_BooleanProperty)
163                 return ICON_RNA;
164         else if(rnatype == &RNA_IntProperty)
165                 return ICON_RNA;
166         else if(rnatype == &RNA_FloatProperty)
167                 return ICON_RNA;
168         else if(rnatype == &RNA_StringProperty)
169                 return ICON_RNA;
170         else if(rnatype == &RNA_EnumProperty)
171                 return ICON_RNA;
172         else if(rnatype == &RNA_EnumPropertyItem)
173                 return ICON_RNA;
174         else if(rnatype == &RNA_PointerProperty)
175                 return ICON_RNA;
176         else if(rnatype == &RNA_CollectionProperty)
177                 return ICON_RNA;
178         else if(rnatype == &RNA_GameObjectSettings)
179                 return ICON_GAME;
180         else if(rnatype == &RNA_ScriptLink)
181                 return ICON_PYTHON;
182         
183         /* modifiers */
184         else if(rnatype == &RNA_SubsurfModifier)
185                 return ICON_MOD_SUBSURF;
186         else if(rnatype == &RNA_ArmatureModifier)
187                 return ICON_MOD_ARMATURE;
188         else if(rnatype == &RNA_LatticeModifier)
189                 return ICON_MOD_LATTICE;
190         else if(rnatype == &RNA_CurveModifier)
191                 return ICON_MOD_CURVE;
192         else if(rnatype == &RNA_BuildModifier)
193                 return ICON_MOD_BUILD;
194         else if(rnatype == &RNA_MirrorModifier)
195                 return ICON_MOD_MIRROR;
196         else if(rnatype == &RNA_DecimateModifier)
197                 return ICON_MOD_DECIM;
198         else if(rnatype == &RNA_WaveModifier)
199                 return ICON_MOD_WAVE;
200         else if(rnatype == &RNA_HookModifier)
201                 return ICON_HOOK;
202         else if(rnatype == &RNA_SoftbodyModifier)
203                 return ICON_MOD_SOFT;
204         else if(rnatype == &RNA_BooleanModifier)
205                 return ICON_MOD_BOOLEAN;
206         else if(rnatype == &RNA_ParticleInstanceModifier)
207                 return ICON_MOD_PARTICLEINSTANCE;
208         else if(rnatype == &RNA_ParticleSystemModifier)
209                 return ICON_MOD_PARTICLES;
210         else if(rnatype == &RNA_EdgeSplitModifier)
211                 return ICON_MOD_EDGESPLIT;
212         else if(rnatype == &RNA_ArrayModifier)
213                 return ICON_MOD_ARRAY;
214         else if(rnatype == &RNA_UVProjectModifier)
215                 return ICON_MOD_UVPROJECT;
216         else if(rnatype == &RNA_DisplaceModifier)
217                 return ICON_MOD_DISPLACE;
218         else
219                 return ICON_DOT;
220 }
221
222 uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, char *name, int icon, int x1, int y1, int x2, int y2)
223 {
224         uiBut *but=NULL;
225         const char *propname= RNA_property_identifier(prop);
226         int arraylen= RNA_property_array_length(prop);
227
228         switch(RNA_property_type(prop)) {
229                 case PROP_BOOLEAN: {
230                         int value, length;
231
232                         if(arraylen && index == -1)
233                                 return NULL;
234
235                         length= RNA_property_array_length(prop);
236
237                         if(length)
238                                 value= RNA_property_boolean_get_index(ptr, prop, index);
239                         else
240                                 value= RNA_property_boolean_get(ptr, prop);
241
242                         if(icon && name && strcmp(name, "") == 0)
243                                 but= uiDefIconButR(block, ICONTOG, 0, icon, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
244                         else if(icon)
245                                 but= uiDefIconTextButR(block, ICONTOG, 0, icon, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
246                         else
247                                 but= uiDefButR(block, TOG, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
248                         break;
249                 }
250                 case PROP_INT:
251                 case PROP_FLOAT:
252                         if(arraylen && index == -1) {
253                                 if(RNA_property_subtype(prop) == PROP_COLOR)
254                                         but= uiDefButR(block, COL, 0, name, x1, y1, x2, y2, ptr, propname, 0, 0, 0, -1, -1, NULL);
255                         }
256                         else if(RNA_property_subtype(prop) == PROP_PERCENTAGE)
257                                 but= uiDefButR(block, NUMSLI, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
258                         else
259                                 but= uiDefButR(block, NUM, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
260                         break;
261                 case PROP_ENUM:
262                         but= uiDefButR(block, MENU, 0, NULL, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
263                         break;
264                 case PROP_STRING:
265                         but= uiDefButR(block, TEX, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
266                         break;
267                 case PROP_POINTER: {
268                         PointerRNA pptr;
269                         int icon;
270
271                         pptr= RNA_property_pointer_get(ptr, prop);
272                         if(!pptr.type)
273                                 pptr.type= RNA_property_pointer_type(prop);
274                         icon= UI_GetIconRNA(&pptr);
275
276                         but= uiDefIconTextButR(block, IDPOIN, 0, icon, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
277                         break;
278                 }
279                 case PROP_COLLECTION: {
280                         char text[256];
281                         sprintf(text, "%d items", RNA_property_collection_length(ptr, prop));
282                         but= uiDefBut(block, LABEL, 0, text, x1, y1, x2, y2, NULL, 0, 0, 0, 0, NULL);
283                         uiButSetFlag(but, UI_BUT_DISABLED);
284                         break;
285                 }
286                 default:
287                         but= NULL;
288                         break;
289         }
290
291         return but;
292 }
293
294 int uiDefAutoButsRNA(const bContext *C, uiBlock *block, PointerRNA *ptr)
295 {
296         uiStyle *style= U.uistyles.first;
297         CollectionPropertyIterator iter;
298         PropertyRNA *iterprop, *prop;
299         uiLayout *layout;
300         char *name;
301         int x= 0, y= 0;
302
303         layout= uiLayoutBegin(UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y, DEF_BUT_WIDTH*2, 20, style);
304
305         uiLayoutColumn(layout);
306         uiItemL(layout, (char*)RNA_struct_ui_name(ptr->type), 0);
307
308         iterprop= RNA_struct_iterator_property(ptr->type);
309         RNA_property_collection_begin(ptr, iterprop, &iter);
310
311         for(; iter.valid; RNA_property_collection_next(&iter)) {
312                 prop= iter.ptr.data;
313
314                 if(strcmp(RNA_property_identifier(prop), "rna_type") == 0)
315                         continue;
316
317                 uiLayoutSplit(layout, 2, 0);
318
319                 name= (char*)RNA_property_ui_name(prop);
320                 uiLayoutColumn(uiLayoutSub(layout, 0));
321                 uiItemL(uiLayoutSub(layout, 0), name, 0);
322                 uiLayoutColumn(uiLayoutSub(layout, 1));
323                 uiItemFullR(uiLayoutSub(layout, 1), "", 0, ptr, prop, -1, 0, 0);
324         }
325
326         RNA_property_collection_end(&iter);
327         uiLayoutEnd(C, block, layout, &x, &y);
328
329         return -y;
330 }
331
332 /* temp call, single collumn, test for toolbar only */
333 int uiDefAutoButsRNA_single(const bContext *C, uiBlock *block, PointerRNA *ptr)
334 {
335         uiStyle *style= U.uistyles.first;
336         CollectionPropertyIterator iter;
337         PropertyRNA *iterprop, *prop;
338         uiLayout *layout;
339         char *name;
340         int x= 0, y= 0;
341         
342         layout= uiLayoutBegin(UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y, block->panel->sizex, 20, style);
343         
344         uiLayoutColumn(layout);
345         uiItemL(layout, (char*)RNA_struct_ui_name(ptr->type), 0);
346         
347         iterprop= RNA_struct_iterator_property(ptr->type);
348         RNA_property_collection_begin(ptr, iterprop, &iter);
349         
350         for(; iter.valid; RNA_property_collection_next(&iter)) {
351                 prop= iter.ptr.data;
352                 
353                 if(strcmp(RNA_property_identifier(prop), "rna_type") == 0)
354                         continue;
355                 
356                 uiLayoutSplit(layout, 1, 0);
357                 uiLayoutColumn(uiLayoutSub(layout, 0));
358                 
359                 name= (char*)RNA_property_ui_name(prop);
360                 uiItemL(uiLayoutSub(layout, 0), name, 0);
361
362                 uiItemFullR(uiLayoutSub(layout, 0), "", 0, ptr, prop, -1, 0, 0);
363         }
364         
365         RNA_property_collection_end(&iter);
366         uiLayoutEnd(C, block, layout, &x, &y);
367         
368         return -y;
369 }
370
371
372 /***************************** ID Utilities *******************************/
373
374 typedef struct uiIDPoinParams {
375         uiIDPoinFunc func;
376         ID *id;
377         short id_code;
378         short browsenr;
379 } uiIDPoinParams;
380
381 static void idpoin_cb(bContext *C, void *arg_params, void *arg_event)
382 {
383         Main *bmain;
384         ListBase *lb;
385         uiIDPoinParams *params= (uiIDPoinParams*)arg_params;
386         uiIDPoinFunc func= params->func;
387         ID *id= params->id, *idtest;
388         int nr, event= GET_INT_FROM_POINTER(arg_event);
389
390         bmain= CTX_data_main(C);
391         lb= wich_libbase(bmain, params->id_code);
392         
393         if(event == UI_ID_BROWSE && params->browsenr == 32767)
394                 event= UI_ID_ADD_NEW;
395         else if(event == UI_ID_BROWSE && params->browsenr == 32766)
396                 event= UI_ID_OPEN;
397
398         switch(event) {
399                 case UI_ID_RENAME:
400                         if(id) test_idbutton(id->name+2);
401                         else return;
402                         break;
403                 case UI_ID_BROWSE: {
404                         if(id==0) id= lb->first;
405                         if(id==0) return;
406
407                         if(params->browsenr== -2) {
408                                 /* XXX implement or find a replacement
409                                  * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &params->browsenr, do_global_buttons); */
410                                 return;
411                         }
412                         if(params->browsenr < 0)
413                                 return;
414
415                         for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) {
416                                 if(nr==params->browsenr) {
417                                         if(id == idtest)
418                                                 return;
419
420                                         id= idtest;
421
422                                         break;
423                                 }
424                         }
425                         break;
426                 }
427                 case UI_ID_DELETE:
428                         id= NULL;
429                         break;
430                 case UI_ID_FAKE_USER:
431                         if(id) {
432                                 if(id->flag & LIB_FAKEUSER) id->us++;
433                                 else id->us--;
434                         }
435                         else return;
436                         break;
437                 case UI_ID_PIN:
438                         break;
439                 case UI_ID_ADD_NEW:
440                         break;
441                 case UI_ID_OPEN:
442                         break;
443                 case UI_ID_ALONE:
444                         if(!id || id->us < 1)
445                                 return;
446                         break;
447                 case UI_ID_LOCAL:
448                         if(!id || id->us < 1)
449                                 return;
450                         break;
451                 case UI_ID_AUTO_NAME:
452                         break;
453         }
454
455         if(func)
456                 func(C, id, event);
457 }
458
459 int uiDefIDPoinButs(uiBlock *block, Main *bmain, ID *parid, ID *id, int id_code, short *pin_p, int x, int y, uiIDPoinFunc func, int events)
460 {
461         ListBase *lb;
462         uiBut *but;
463         uiIDPoinParams *params, *dup_params;
464         char *str=NULL, str1[10];
465         int len, add_addbutton=0;
466
467         /* setup struct that we will pass on with the buttons */
468         params= MEM_callocN(sizeof(uiIDPoinParams), "uiIDPoinParams");
469         params->id= id;
470         params->id_code= id_code;
471         params->func= func;
472
473         lb= wich_libbase(bmain, id_code);
474
475         /* create buttons */
476         uiBlockBeginAlign(block);
477
478         /* XXX solve?
479         if(id && id->us>1)
480                 uiBlockSetCol(block, TH_BUT_SETTING1);
481
482         if((events & UI_ID_PIN) && *pin_p)
483                 uiBlockSetCol(block, TH_BUT_SETTING2);
484         */
485         
486         /* pin button */
487         if(id && (events & UI_ID_PIN)) {
488                 but= uiDefIconButS(block, ICONTOG, (events & UI_ID_PIN), ICON_KEY_DEHLT, x, y ,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, pin_p, 0, 0, 0, 0, "Keeps this view displaying the current data regardless of what object is selected");
489                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_PIN));
490                 x+= DEF_ICON_BUT_WIDTH;
491         }
492
493         /* browse menu */
494         if(events & UI_ID_BROWSE) {
495                 char *extrastr= NULL;
496                 
497                 if(ELEM4(id_code, ID_MA, ID_TE, ID_BR, ID_PA))
498                         add_addbutton= 1;
499                 
500                 if(ELEM8(id_code, ID_SCE, ID_SCR, ID_MA, ID_TE, ID_WO, ID_IP, ID_AC, ID_BR) || id_code == ID_PA)
501                         extrastr= "ADD NEW %x 32767";
502                 else if(id_code==ID_TXT)
503                         extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
504                 else if(id_code==ID_SO)
505                         extrastr= "OPEN NEW %x 32766";
506
507                 /* XXX should be moved out of this function
508                 uiBlockSetButLock(block, G.scene->id.lib!=0, "Can't edit external libdata");
509                 if( id_code==ID_SCE || id_code==ID_SCR ) uiBlockClearButLock(block); */
510                 
511                 /* XXX should be moved out of this function
512                 if(curarea->spacetype==SPACE_BUTS)
513                         uiBlockSetButLock(block, id_code!=ID_SCR && G.obedit!=0 && G.buts->mainb==CONTEXT_EDITING, "Cannot perform in EditMode"); */
514                 
515                 if(parid)
516                         uiBlockSetButLock(block, parid->lib!=0, "Can't edit external libdata");
517
518                 if(lb) {
519                         if(id_code!=ID_IM || (events & UI_ID_BROWSE_RENDER))
520                                 IDnames_to_pupstring(&str, NULL, extrastr, lb, id, &params->browsenr);
521                         else
522                                 IMAnames_to_pupstring(&str, NULL, extrastr, lb, id, &params->browsenr);
523                 }
524
525                 dup_params= MEM_dupallocN(params);
526                 but= uiDefButS(block, MENU, 0, str, x, y, DEF_ICON_BUT_WIDTH, DEF_BUT_HEIGHT, &dup_params->browsenr, 0, 0, 0, 0, "Browse existing choices, or add new");
527                 uiButSetNFunc(but, idpoin_cb, dup_params, SET_INT_IN_POINTER(UI_ID_BROWSE));
528                 x+= DEF_ICON_BUT_WIDTH;
529                 
530                 uiBlockClearButLock(block);
531         
532                 MEM_freeN(str);
533         }
534
535         /* text button with name */
536         if(id) {
537                 /* XXX solve?
538                 if(id->us > 1)
539                         uiBlockSetCol(block, TH_BUT_SETTING1);
540                 */
541                 /* pinned data? 
542                 if((events & UI_ID_PIN) && *pin_p)
543                         uiBlockSetCol(block, TH_BUT_SETTING2);
544                 */
545                 /* redalert overrides pin color 
546                 if(id->us<=0)
547                         uiBlockSetCol(block, TH_REDALERT);
548                 */
549                 uiBlockSetButLock(block, id->lib!=0, "Can't edit external libdata");
550                 
551                 /* name button */
552                 text_idbutton(id, str1);
553                 
554                 if(GS(id->name)==ID_IP) len= 110;
555                 else if((y) && (GS(id->name)==ID_AC)) len= 100; // comes from button panel (poselib)
556                 else if(y) len= 140;    // comes from button panel
557                 else len= 120;
558                 
559                 but= uiDefBut(block, TEX, 0, str1,x, y, (short)len, DEF_BUT_HEIGHT, id->name+2, 0.0, 21.0, 0, 0, "Displays current Datablock name. Click to change.");
560                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_RENAME));
561
562                 x+= len;
563
564                 uiBlockClearButLock(block);
565                 
566                 /* lib make local button */
567                 if(id->lib) {
568                         if(id->flag & LIB_INDIRECT) uiDefIconBut(block, BUT, 0, 0 /* XXX ICON_DATALIB */,x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Indirect Library Datablock. Cannot change.");
569                         else {
570                                 but= uiDefIconBut(block, BUT, 0, 0 /* XXX ICON_PARLIB */, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, 
571                                                           (events & UI_ID_LOCAL)? "Direct linked Library Datablock. Click to make local.": "Direct linked Library Datablock, cannot make local.");
572                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ALONE));
573                         }
574                         
575                         x+= DEF_ICON_BUT_WIDTH;
576                 }
577                 
578                 /* number of users / make local button */
579                 if((events & UI_ID_ALONE) && id->us>1) {
580                         int butwidth;
581
582                         uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't make pinned data single-user");
583                         
584                         sprintf(str1, "%d", id->us);
585                         butwidth= (id->us<10)? DEF_ICON_BUT_WIDTH: DEF_ICON_BUT_WIDTH+10;
586
587                         but= uiDefBut(block, BUT, 0, str1, x, y, butwidth, DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
588                         uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ALONE));
589                         x+= butwidth;
590                         
591                         uiBlockClearButLock(block);
592                 }
593                 
594                 /* delete button */
595                 if(events & UI_ID_DELETE) {
596                         uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't unlink pinned data");
597                         if(parid && parid->lib);
598                         else {
599                                 but= uiDefIconBut(block, BUT, 0, ICON_X, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Deletes link to this Datablock");
600                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_DELETE));
601                                 x+= DEF_ICON_BUT_WIDTH;
602                         }
603                         
604                         uiBlockClearButLock(block);
605                 }
606
607                 /* auto name button */
608                 if(events & UI_ID_AUTO_NAME) {
609                         if(parid && parid->lib);
610                         else {
611                                 but= uiDefIconBut(block, BUT, 0, ICON_AUTO,x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Generates an automatic name");
612                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_AUTO_NAME));
613                                 x+= DEF_ICON_BUT_WIDTH;
614                         }
615                 }
616
617                 /* fake user button */
618                 if(events & UI_ID_FAKE_USER) {
619                         but= uiDefButBitS(block, TOG, LIB_FAKEUSER, 0, "F", x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, &id->flag, 0, 0, 0, 0, "Saves this datablock even if it has no users");
620                         uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_FAKE_USER));
621                         x+= DEF_ICON_BUT_WIDTH;
622                 }
623         }
624         /* add new button */
625         else if(add_addbutton) {
626                 if(parid) uiBlockSetButLock(block, parid->lib!=0, "Can't edit external libdata");
627                 dup_params= MEM_dupallocN(params);
628                 but= uiDefButS(block, TOG, 0, "Add New", x, y, 110, DEF_BUT_HEIGHT, &dup_params->browsenr, params->browsenr, 32767.0, 0, 0, "Add new data block");
629                 uiButSetNFunc(but, idpoin_cb, dup_params, SET_INT_IN_POINTER(UI_ID_ADD_NEW));
630                 x+= 110;
631         }
632         
633         uiBlockEndAlign(block);
634
635         MEM_freeN(params);
636
637         return x;
638 }
639
640 /* ****************************** default button callbacks ******************* */
641 /* ************ LEGACY WARNING, only to get things work with 2.48 code! ****** */
642
643 void test_idbutton_cb(struct bContext *C, void *namev, void *arg2)
644 {
645         char *name= namev;
646         
647         test_idbutton(name+2);
648 }
649
650
651 void test_scriptpoin_but(struct bContext *C, char *name, ID **idpp)
652 {
653         ID *id;
654         
655         id= CTX_data_main(C)->text.first;
656         while(id) {
657                 if( strcmp(name, id->name+2)==0 ) {
658                         *idpp= id;
659                         return;
660                 }
661                 id= id->next;
662         }
663         *idpp= NULL;
664 }
665
666 void test_actionpoin_but(struct bContext *C, char *name, ID **idpp)
667 {
668         ID *id;
669         
670         id= CTX_data_main(C)->action.first;
671         while(id) {
672                 if( strcmp(name, id->name+2)==0 ) {
673                         id_us_plus(id);
674                         *idpp= id;
675                         return;
676                 }
677                 id= id->next;
678         }
679         *idpp= NULL;
680 }
681
682
683 void test_obpoin_but(struct bContext *C, char *name, ID **idpp)
684 {
685         ID *id;
686         
687 // XXX  if(idpp == (ID **)&(emptytex.object)) {
688 //              error("You must add a texture first");
689 //              *idpp= 0;
690 //              return;
691 //      }
692         
693         id= CTX_data_main(C)->object.first;
694         while(id) {
695                 if( strcmp(name, id->name+2)==0 ) {
696                         *idpp= id;
697                         id_lib_extern(id);      /* checks lib data, sets correct flag for saving then */
698                         return;
699                 }
700                 id= id->next;
701         }
702         *idpp= NULL;
703 }
704
705 /* tests for an object of type OB_MESH */
706 void test_meshobpoin_but(struct bContext *C, char *name, ID **idpp)
707 {
708         ID *id;
709
710         id = CTX_data_main(C)->object.first;
711         while(id) {
712                 Object *ob = (Object *)id;
713                 if(ob->type == OB_MESH && strcmp(name, id->name + 2) == 0) {
714                         *idpp = id;
715                         /* checks lib data, sets correct flag for saving then */
716                         id_lib_extern(id);
717                         return;
718                 }
719                 id = id->next;
720         }
721         *idpp = NULL;
722 }
723
724 void test_meshpoin_but(struct bContext *C, char *name, ID **idpp)
725 {
726         ID *id;
727
728         if( *idpp ) (*idpp)->us--;
729         
730         id= CTX_data_main(C)->mesh.first;
731         while(id) {
732                 if( strcmp(name, id->name+2)==0 ) {
733                         *idpp= id;
734                         id_us_plus(id);
735                         return;
736                 }
737                 id= id->next;
738         }
739         *idpp= NULL;
740 }
741
742 void test_matpoin_but(struct bContext *C, char *name, ID **idpp)
743 {
744         ID *id;
745
746         if( *idpp ) (*idpp)->us--;
747         
748         id= CTX_data_main(C)->mat.first;
749         while(id) {
750                 if( strcmp(name, id->name+2)==0 ) {
751                         *idpp= id;
752                         id_us_plus(id);
753                         return;
754                 }
755                 id= id->next;
756         }
757         *idpp= NULL;
758 }
759
760 void test_scenepoin_but(struct bContext *C, char *name, ID **idpp)
761 {
762         ID *id;
763         
764         if( *idpp ) (*idpp)->us--;
765         
766         id= CTX_data_main(C)->scene.first;
767         while(id) {
768                 if( strcmp(name, id->name+2)==0 ) {
769                         *idpp= id;
770                         id_us_plus(id);
771                         return;
772                 }
773                 id= id->next;
774         }
775         *idpp= NULL;
776 }
777
778 void test_grouppoin_but(struct bContext *C, char *name, ID **idpp)
779 {
780         ID *id;
781         
782         if( *idpp ) (*idpp)->us--;
783         
784         id= CTX_data_main(C)->group.first;
785         while(id) {
786                 if( strcmp(name, id->name+2)==0 ) {
787                         *idpp= id;
788                         id_us_plus(id);
789                         return;
790                 }
791                 id= id->next;
792         }
793         *idpp= NULL;
794 }
795
796 void test_texpoin_but(struct bContext *C, char *name, ID **idpp)
797 {
798         ID *id;
799         
800         if( *idpp ) (*idpp)->us--;
801         
802         id= CTX_data_main(C)->tex.first;
803         while(id) {
804                 if( strcmp(name, id->name+2)==0 ) {
805                         *idpp= id;
806                         id_us_plus(id);
807                         return;
808                 }
809                 id= id->next;
810         }
811         *idpp= NULL;
812 }
813
814 void test_imapoin_but(struct bContext *C, char *name, ID **idpp)
815 {
816         ID *id;
817         
818         if( *idpp ) (*idpp)->us--;
819         
820         id= CTX_data_main(C)->image.first;
821         while(id) {
822                 if( strcmp(name, id->name+2)==0 ) {
823                         *idpp= id;
824                         id_us_plus(id);
825                         return;
826                 }
827                 id= id->next;
828         }
829         *idpp= NULL;
830 }
831
832 /* autocomplete callback for  buttons */
833 void autocomplete_bone(struct bContext *C, char *str, void *arg_v)
834 {
835         Object *ob= (Object *)arg_v;
836         
837         if(ob==NULL || ob->pose==NULL) return;
838         
839         /* search if str matches the beginning of name */
840         if(str[0]) {
841                 AutoComplete *autocpl= autocomplete_begin(str, 32);
842                 bPoseChannel *pchan;
843                 
844                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
845                         autocomplete_do_name(autocpl, pchan->name);
846                 
847                 autocomplete_end(autocpl, str);
848         }
849 }
850
851 /* autocomplete callback for buttons */
852 void autocomplete_vgroup(struct bContext *C, char *str, void *arg_v)
853 {
854         Object *ob= (Object *)arg_v;
855         
856         if(ob==NULL) return;
857         
858         /* search if str matches the beginning of a name */
859         if(str[0]) {
860                 AutoComplete *autocpl= autocomplete_begin(str, 32);
861                 bDeformGroup *dg;
862                 
863                 for(dg= ob->defbase.first; dg; dg= dg->next)
864                         if(dg->name!=str)
865                                 autocomplete_do_name(autocpl, dg->name);
866                 
867                 autocomplete_end(autocpl, str);
868         }
869 }
870
871
872 /* ----------- custom button group ---------------------- */
873
874 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *unused)
875 {
876         CurveMapping *cumap = cumap_v;
877         float d;
878         
879         /* we allow 20 times zoom */
880         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
881                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
882                 cumap->curr.xmin+= d;
883                 cumap->curr.xmax-= d;
884                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
885                 cumap->curr.ymin+= d;
886                 cumap->curr.ymax-= d;
887         }
888 }
889
890 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *unused)
891 {
892         CurveMapping *cumap = cumap_v;
893         float d, d1;
894         
895         /* we allow 20 times zoom, but dont view outside clip */
896         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
897                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
898                 
899                 if(cumap->flag & CUMA_DO_CLIP) 
900                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
901                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
902                 cumap->curr.xmin-= d1;
903                 
904                 d1= d;
905                 if(cumap->flag & CUMA_DO_CLIP) 
906                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
907                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
908                 cumap->curr.xmax+= d1;
909                 
910                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
911                 
912                 if(cumap->flag & CUMA_DO_CLIP) 
913                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
914                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
915                 cumap->curr.ymin-= d1;
916                 
917                 d1= d;
918                 if(cumap->flag & CUMA_DO_CLIP) 
919                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
920                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
921                 cumap->curr.ymax+= d1;
922         }
923 }
924
925 static void curvemap_buttons_setclip(bContext *C, void *cumap_v, void *unused)
926 {
927         CurveMapping *cumap = cumap_v;
928         
929         curvemapping_changed(cumap, 0);
930 }       
931
932 static void curvemap_buttons_delete(bContext *C, void *cumap_v, void *unused)
933 {
934         CurveMapping *cumap = cumap_v;
935         
936         curvemap_remove(cumap->cm+cumap->cur, SELECT);
937         curvemapping_changed(cumap, 0);
938 }
939
940 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
941 static uiBlock *curvemap_clipping_func(struct bContext *C, struct ARegion *ar, void *cumap_v)
942 {
943         CurveMapping *cumap = cumap_v;
944         uiBlock *block;
945         uiBut *bt;
946         
947         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
948         
949         /* use this for a fake extra empy space around the buttons */
950         uiDefBut(block, LABEL, 0, "",                   -4, 16, 128, 106, NULL, 0, 0, 0, 0, "");
951         
952         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
953                                                                                 0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, "");
954         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
955
956         uiBlockBeginAlign(block);
957         uiDefButF(block, NUM, 0, "Min X ",       0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
958         uiDefButF(block, NUM, 0, "Min Y ",       0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
959         uiDefButF(block, NUM, 0, "Max X ",       0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
960         uiDefButF(block, NUM, 0, "Max Y ",       0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
961         
962         uiBlockSetDirection(block, UI_RIGHT);
963         
964         uiEndBlock(C, block);
965         return block;
966 }
967
968
969 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
970 {
971         CurveMapping *cumap = cumap_v;
972         CurveMap *cuma= cumap->cm+cumap->cur;
973         
974         switch(event) {
975                 case 0:
976                         curvemap_reset(cuma, &cumap->clipr);
977                         curvemapping_changed(cumap, 0);
978                         break;
979                 case 1:
980                         cumap->curr= cumap->clipr;
981                         break;
982                 case 2: /* set vector */
983                         curvemap_sethandle(cuma, 1);
984                         curvemapping_changed(cumap, 0);
985                         break;
986                 case 3: /* set auto */
987                         curvemap_sethandle(cuma, 0);
988                         curvemapping_changed(cumap, 0);
989                         break;
990                 case 4: /* extend horiz */
991                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
992                         curvemapping_changed(cumap, 0);
993                         break;
994                 case 5: /* extend extrapolate */
995                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
996                         curvemapping_changed(cumap, 0);
997                         break;
998         }
999         ED_region_tag_redraw(CTX_wm_region(C));
1000 }
1001
1002 static uiBlock *curvemap_tools_func(struct bContext *C, struct ARegion *ar, void *cumap_v)
1003 {
1004         uiBlock *block;
1005         short yco= 0, menuwidth=120;
1006         
1007         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1008         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1009         
1010         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1011         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1012         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1013         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
1014         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
1015         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
1016         
1017         uiBlockSetDirection(block, UI_RIGHT);
1018         uiTextBoundsBlock(block, 50);
1019         
1020         uiEndBlock(C, block);
1021         return block;
1022 }
1023
1024 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1025 void curvemap_buttons(uiBlock *block, CurveMapping *cumap, char labeltype, short event, short redraw, rctf *rect)
1026 {
1027         uiBut *bt;
1028         float dx, fy= rect->ymax-18.0f;
1029         int icon;
1030         short xco, yco;
1031         
1032         yco= (short)(rect->ymax-18.0f);
1033         
1034         /* curve choice options + tools/settings, 8 icons + spacer */
1035         dx= (rect->xmax-rect->xmin)/(9.0f);
1036         
1037         uiBlockBeginAlign(block);
1038         if(labeltype=='v') {    /* vector */
1039                 xco= (short)rect->xmin;
1040                 if(cumap->cm[0].curve)
1041                         uiDefButI(block, ROW, redraw, "X", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1042                 xco= (short)(rect->xmin+1.0f*dx);
1043                 if(cumap->cm[1].curve)
1044                         uiDefButI(block, ROW, redraw, "Y", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1045                 xco= (short)(rect->xmin+2.0f*dx);
1046                 if(cumap->cm[2].curve)
1047                         uiDefButI(block, ROW, redraw, "Z", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1048         }
1049         else if(labeltype=='c') { /* color */
1050                 xco= (short)rect->xmin;
1051                 if(cumap->cm[3].curve)
1052                         uiDefButI(block, ROW, redraw, "C", xco, yco+2, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1053                 xco= (short)(rect->xmin+1.0f*dx);
1054                 if(cumap->cm[0].curve)
1055                         uiDefButI(block, ROW, redraw, "R", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1056                 xco= (short)(rect->xmin+2.0f*dx);
1057                 if(cumap->cm[1].curve)
1058                         uiDefButI(block, ROW, redraw, "G", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1059                 xco= (short)(rect->xmin+3.0f*dx);
1060                 if(cumap->cm[2].curve)
1061                         uiDefButI(block, ROW, redraw, "B", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1062         }
1063         /* else no channels ! */
1064         uiBlockEndAlign(block);
1065
1066         xco= (short)(rect->xmin+4.5f*dx);
1067         uiBlockSetEmboss(block, UI_EMBOSSN);
1068         bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMIN, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
1069         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1070         
1071         xco= (short)(rect->xmin+5.25f*dx);
1072         bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMOUT, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
1073         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1074         
1075         xco= (short)(rect->xmin+6.0f*dx);
1076         bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, event, ICON_MODIFIER, xco, yco, dx, 18, "Tools");
1077         
1078         xco= (short)(rect->xmin+7.0f*dx);
1079         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1080         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, event, icon, xco, yco, dx, 18, "Clipping Options");
1081         
1082         xco= (short)(rect->xmin+8.0f*dx);
1083         bt= uiDefIconBut(block, BUT, event, ICON_X, xco, yco, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
1084         uiButSetFunc(bt, curvemap_buttons_delete, cumap, NULL);
1085         
1086         uiBlockSetEmboss(block, UI_EMBOSS);
1087         
1088         uiDefBut(block, BUT_CURVE, event, "", 
1089                           rect->xmin, rect->ymin, rect->xmax-rect->xmin, fy-rect->ymin, 
1090                           cumap, 0.0f, 1.0f, 0, 0, "");
1091 }
1092