Implemented dynamic and multidimensional array support in RNA.
[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_texture_types.h"
39 #include "DNA_windowmanager_types.h"
40
41 #include "BLI_blenlib.h"
42
43 #include "BKE_colortools.h"
44 #include "BKE_context.h"
45 #include "BKE_idprop.h"
46 #include "BKE_icons.h"
47 #include "BKE_library.h"
48 #include "BKE_main.h"
49 #include "BKE_texture.h"
50 #include "BKE_utildefines.h"
51
52 #include "RNA_access.h"
53
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56
57 #include "ED_screen.h"
58 #include "ED_util.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "interface_intern.h"
64
65 #define DEF_BUT_WIDTH           150
66 #define DEF_ICON_BUT_WIDTH      20
67 #define DEF_BUT_HEIGHT          20
68
69 /*************************** RNA Utilities ******************************/
70
71 uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, char *name, int icon, int x1, int y1, int x2, int y2)
72 {
73         uiBut *but=NULL;
74         const char *propname= RNA_property_identifier(prop);
75         int arraylen= RNA_property_array_length(ptr, prop);
76
77         switch(RNA_property_type(prop)) {
78                 case PROP_BOOLEAN: {
79                         int value, length;
80
81                         if(arraylen && index == -1)
82                                 return NULL;
83
84                         length= RNA_property_array_length(ptr, prop);
85
86                         if(length)
87                                 value= RNA_property_boolean_get_index(ptr, prop, index);
88                         else
89                                 value= RNA_property_boolean_get(ptr, prop);
90
91                         if(icon && name && strcmp(name, "") == 0)
92                                 but= uiDefIconButR(block, ICONTOG, 0, icon, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
93                         else if(icon)
94                                 but= uiDefIconTextButR(block, ICONTOG, 0, icon, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
95                         else
96                                 but= uiDefButR(block, OPTION, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
97                         break;
98                 }
99                 case PROP_INT:
100                 case PROP_FLOAT:
101                         if(arraylen && index == -1) {
102                                 if(RNA_property_subtype(prop) == PROP_COLOR)
103                                         but= uiDefButR(block, COL, 0, name, x1, y1, x2, y2, ptr, propname, 0, 0, 0, -1, -1, NULL);
104                         }
105                         else if(RNA_property_subtype(prop) == PROP_PERCENTAGE)
106                                 but= uiDefButR(block, NUMSLI, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
107                         else
108                                 but= uiDefButR(block, NUM, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
109                         break;
110                 case PROP_ENUM:
111                         but= uiDefButR(block, MENU, 0, NULL, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
112                         break;
113                 case PROP_STRING:
114                         if(icon && name && strcmp(name, "") == 0)
115                                 but= uiDefIconButR(block, TEX, 0, icon, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
116                         else if(icon)
117                                 but= uiDefIconTextButR(block, TEX, 0, icon, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
118                         else
119                                 but= uiDefButR(block, TEX, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
120                         break;
121                 case PROP_POINTER: {
122                         PointerRNA pptr;
123                         int icon;
124
125                         pptr= RNA_property_pointer_get(ptr, prop);
126                         if(!pptr.type)
127                                 pptr.type= RNA_property_pointer_type(ptr, prop);
128                         icon= RNA_struct_ui_icon(pptr.type);
129                         if(icon == ICON_DOT)
130                                 icon= 0;
131
132                         but= uiDefIconTextButR(block, IDPOIN, 0, icon, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL);
133                         break;
134                 }
135                 case PROP_COLLECTION: {
136                         char text[256];
137                         sprintf(text, "%d items", RNA_property_collection_length(ptr, prop));
138                         but= uiDefBut(block, LABEL, 0, text, x1, y1, x2, y2, NULL, 0, 0, 0, 0, NULL);
139                         uiButSetFlag(but, UI_BUT_DISABLED);
140                         break;
141                 }
142                 default:
143                         but= NULL;
144                         break;
145         }
146
147         return but;
148 }
149
150 void uiDefAutoButsRNA(const bContext *C, uiLayout *layout, PointerRNA *ptr, int columns)
151 {
152         uiLayout *split, *col;
153         char *name;
154
155         RNA_STRUCT_BEGIN(ptr, prop) {
156                 if(strcmp(RNA_property_identifier(prop), "rna_type") == 0)
157                         continue;
158
159                 name= (char*)RNA_property_ui_name(prop);
160
161                 if(columns == 1) {
162                         col= uiLayoutColumn(layout, 1);
163                         uiItemL(col, name, 0);
164                 }
165                 else if(columns == 2) {
166                         split = uiLayoutSplit(layout, 0.5f);
167
168                         uiItemL(uiLayoutColumn(split, 0), name, 0);
169                         col= uiLayoutColumn(split, 0);
170                 }
171                 else
172                         col= NULL;
173
174                 /* temp hack to show normal button for spin/screw */
175                 if(strcmp(name, "Axis")==0) {
176                         uiDefButR(uiLayoutGetBlock(col), BUT_NORMAL, 0, name, 0, 0, 100, 100, ptr, "axis", -1, 0, 0, -1, -1, NULL);
177                 }
178                 else uiItemFullR(col, "", 0, ptr, prop, -1, 0, 0);
179         }
180         RNA_STRUCT_END;
181 }
182
183 /***************************** ID Utilities *******************************/
184 /* note, C code version, will be replaced with version in interface_templates.c */
185
186 typedef struct uiIDPoinParams {
187         uiIDPoinFunc func;
188         ListBase *lb;
189         ID *id;
190         short id_code;
191         short browsenr;
192 } uiIDPoinParams;
193
194 static void idpoin_cb(bContext *C, void *arg_params, void *arg_event)
195 {
196         uiIDPoinParams *params= (uiIDPoinParams*)arg_params;
197         ListBase *lb= params->lb;
198         uiIDPoinFunc func= params->func;
199         ID *id= params->id, *idtest;
200         int nr, event= GET_INT_FROM_POINTER(arg_event);
201
202         if(event == UI_ID_BROWSE && params->browsenr == 32767)
203                 event= UI_ID_ADD_NEW;
204         else if(event == UI_ID_BROWSE && params->browsenr == 32766)
205                 event= UI_ID_OPEN;
206
207         switch(event) {
208                 case UI_ID_RENAME:
209                         if(id) test_idbutton(id->name+2);
210                         else return;
211                         break;
212                 case UI_ID_BROWSE: {
213                         /* ID can be NULL, if nothing was assigned yet */
214                         if(lb->first==NULL) return;
215
216                         if(params->browsenr== -2) {
217                                 /* XXX implement or find a replacement (ID can be NULL!)
218                                  * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &params->browsenr, do_global_buttons); */
219                                 return;
220                         }
221                         if(params->browsenr < 0)
222                                 return;
223
224                         for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) {
225                                 if(nr==params->browsenr) {
226                                         if(id == idtest)
227                                                 return;
228
229                                         id= idtest;
230
231                                         break;
232                                 }
233                         }
234                         break;
235                 }
236                 case UI_ID_DELETE:
237                         id= NULL;
238                         break;
239                 case UI_ID_FAKE_USER:
240                         if(id) {
241                                 if(id->flag & LIB_FAKEUSER) id->us++;
242                                 else id->us--;
243                         }
244                         else return;
245                         break;
246                 case UI_ID_PIN:
247                         break;
248                 case UI_ID_ADD_NEW:
249                         break;
250                 case UI_ID_OPEN:
251                         break;
252                 case UI_ID_ALONE:
253                         if(!id || id->us < 1)
254                                 return;
255                         break;
256                 case UI_ID_LOCAL:
257                         if(!id || id->us < 1)
258                                 return;
259                         break;
260                 case UI_ID_AUTO_NAME:
261                         break;
262         }
263
264         if(func)
265                 func(C, id, event);
266 }
267
268 /* ***************************** ID Search browse menu ********************** */
269
270 static void id_search_call_cb(struct bContext *C, void *arg_params, void *item)
271 {
272         uiIDPoinParams *params= (uiIDPoinParams*)arg_params;
273
274         if(item && params->func)
275                 params->func(C, item, UI_ID_BROWSE);
276
277 }
278
279 static void id_search_cb(const struct bContext *C, void *arg_params, char *str, uiSearchItems *items)
280 {
281         uiIDPoinParams *params= (uiIDPoinParams*)arg_params;
282         ID *id;
283         
284         for(id= params->lb->first; id; id= id->next) {
285                 int iconid= 0;
286                 
287                 
288                 /* icon */
289                 switch(GS(id->name))
290                 {
291                         case ID_MA: /* fall through */
292                         case ID_TE: /* fall through */
293                         case ID_IM: /* fall through */
294                         case ID_WO: /* fall through */
295                         case ID_LA: /* fall through */
296                                 iconid= BKE_icon_getid(id);
297                                 break;
298                         default:
299                                 break;
300                 }
301                 
302                 if(BLI_strcasestr(id->name+2, str)) {
303                         if(0==uiSearchItemAdd(items, id->name+2, id, iconid))
304                                 break;
305                 }
306         }
307 }
308
309 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_params)
310 {
311         static char search[256];
312         static uiIDPoinParams params;
313         wmEvent event;
314         wmWindow *win= CTX_wm_window(C);
315         uiBlock *block;
316         uiBut *but;
317         
318         /* clear initial search string, then all items show */
319         search[0]= 0;
320         /* params is malloced, can be freed by parent button */
321         params= *((uiIDPoinParams*)arg_params);
322         
323         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
324         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
325         
326         /* fake button, it holds space for search items */
327         uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
328         
329         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, "");
330         uiButSetSearchFunc(but, id_search_cb, &params, id_search_call_cb, NULL);
331         
332         uiBoundsBlock(block, 6);
333         uiBlockSetDirection(block, UI_DOWN);    
334         uiEndBlock(C, block);
335         
336         event= *(win->eventstate);      /* XXX huh huh? make api call */
337         event.type= EVT_BUT_OPEN;
338         event.val= KM_PRESS;
339         event.customdata= but;
340         event.customdatafree= FALSE;
341         wm_event_add(win, &event);
342         
343         return block;
344 }
345
346 /* ****************** */
347
348 int uiDefIDPoinButs(uiBlock *block, Main *bmain, ID *parid, ID *id, int id_code, short *pin_p, int x, int y, uiIDPoinFunc func, int events)
349 {
350         uiBut *but;
351         uiIDPoinParams *params, *dup_params;
352         char str1[10];
353         int len, add_addbutton=0;
354
355         /* setup struct that we will pass on with the buttons */
356         params= MEM_callocN(sizeof(uiIDPoinParams), "uiIDPoinParams");
357         params->lb= wich_libbase(bmain, id_code);
358         params->id= id;
359         params->id_code= id_code;
360         params->func= func;
361
362         /* create buttons */
363         uiBlockBeginAlign(block);
364
365         /* XXX solve?
366         if(id && id->us>1)
367                 uiBlockSetCol(block, TH_BUT_SETTING1);
368
369         if((events & UI_ID_PIN) && *pin_p)
370                 uiBlockSetCol(block, TH_BUT_SETTING2);
371         */
372         
373         /* pin button */
374         if(id && (events & UI_ID_PIN)) {
375                 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");
376                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_PIN));
377                 x+= DEF_ICON_BUT_WIDTH;
378         }
379
380         /* browse menu */
381         if(events & UI_ID_BROWSE) {
382                 uiDefBlockButN(block, id_search_menu, MEM_dupallocN(params), "", x, y, DEF_ICON_BUT_WIDTH, DEF_BUT_HEIGHT, "Browse ID data");
383                 x+= DEF_ICON_BUT_WIDTH;
384         }
385         
386         
387
388         /* text button with name */
389         if(id) {
390                 /* XXX solve?
391                 if(id->us > 1)
392                         uiBlockSetCol(block, TH_BUT_SETTING1);
393                 */
394                 /* pinned data? 
395                 if((events & UI_ID_PIN) && *pin_p)
396                         uiBlockSetCol(block, TH_BUT_SETTING2);
397                 */
398                 /* redalert overrides pin color 
399                 if(id->us<=0)
400                         uiBlockSetCol(block, TH_REDALERT);
401                 */
402                 uiBlockSetButLock(block, id->lib!=0, "Can't edit external libdata");
403                 
404                 /* name button */
405                 text_idbutton(id, str1);
406                 
407                 if(GS(id->name)==ID_IP) len= 110;
408                 else if((y) && (GS(id->name)==ID_AC)) len= 100; // comes from button panel (poselib)
409                 else if(y) len= 140;    // comes from button panel
410                 else len= 120;
411                 
412                 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.");
413                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_RENAME));
414
415                 x+= len;
416
417                 uiBlockClearButLock(block);
418                 
419                 /* lib make local button */
420                 if(id->lib) {
421                         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.");
422                         else {
423                                 but= uiDefIconBut(block, BUT, 0, 0 /* XXX ICON_PARLIB */, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, 
424                                                           (events & UI_ID_LOCAL)? "Direct linked Library Datablock. Click to make local.": "Direct linked Library Datablock, cannot make local.");
425                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ALONE));
426                         }
427                         
428                         x+= DEF_ICON_BUT_WIDTH;
429                 }
430                 
431                 /* number of users / make local button */
432                 if((events & UI_ID_ALONE) && id->us>1) {
433                         int butwidth;
434
435                         uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't make pinned data single-user");
436                         
437                         sprintf(str1, "%d", id->us);
438                         butwidth= (id->us<10)? DEF_ICON_BUT_WIDTH: DEF_ICON_BUT_WIDTH+10;
439
440                         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.");
441                         uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ALONE));
442                         x+= butwidth;
443                         
444                         uiBlockClearButLock(block);
445                 }
446                 
447                 /* add button */
448                 if(events & UI_ID_ADD_NEW) {
449                         uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't unlink pinned data");
450                         if(parid && parid->lib);
451                         else {
452                                 dup_params= MEM_dupallocN(params);
453                                 but= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, &dup_params->browsenr, params->browsenr, 32767.0, 0, 0, "Add new data block");
454                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
455                                 x+= DEF_ICON_BUT_WIDTH;
456                         }
457                         
458                         uiBlockClearButLock(block);
459                 }
460                 
461                 /* delete button */
462                 if(events & UI_ID_DELETE) {
463                         uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't unlink pinned data");
464                         if(parid && parid->lib);
465                         else {
466                                 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");
467                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_DELETE));
468                                 x+= DEF_ICON_BUT_WIDTH;
469                         }
470                         
471                         uiBlockClearButLock(block);
472                 }
473
474                 /* auto name button */
475                 if(events & UI_ID_AUTO_NAME) {
476                         if(parid && parid->lib);
477                         else {
478                                 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");
479                                 uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_AUTO_NAME));
480                                 x+= DEF_ICON_BUT_WIDTH;
481                         }
482                 }
483
484                 /* fake user button */
485                 if(events & UI_ID_FAKE_USER) {
486                         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");
487                         uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_FAKE_USER));
488                         x+= DEF_ICON_BUT_WIDTH;
489                 }
490         }
491         /* add new button */
492         else if(add_addbutton) {
493                 if(parid) uiBlockSetButLock(block, parid->lib!=0, "Can't edit external libdata");
494                 dup_params= MEM_dupallocN(params);
495                 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");
496                 uiButSetNFunc(but, idpoin_cb, dup_params, SET_INT_IN_POINTER(UI_ID_ADD_NEW));
497                 x+= 110;
498         }
499         
500         uiBlockEndAlign(block);
501
502         MEM_freeN(params);
503
504         return x;
505 }
506
507 /* ****************************** default button callbacks ******************* */
508 /* ************ LEGACY WARNING, only to get things work with 2.48 code! ****** */
509
510 void test_idbutton_cb(struct bContext *C, void *namev, void *arg2)
511 {
512         char *name= namev;
513         
514         test_idbutton(name+2);
515 }
516
517
518 void test_scriptpoin_but(struct bContext *C, char *name, ID **idpp)
519 {
520         ID *id;
521         
522         id= CTX_data_main(C)->text.first;
523         while(id) {
524                 if( strcmp(name, id->name+2)==0 ) {
525                         *idpp= id;
526                         return;
527                 }
528                 id= id->next;
529         }
530         *idpp= NULL;
531 }
532
533 void test_actionpoin_but(struct bContext *C, char *name, ID **idpp)
534 {
535         ID *id;
536         
537         id= CTX_data_main(C)->action.first;
538         while(id) {
539                 if( strcmp(name, id->name+2)==0 ) {
540                         id_us_plus(id);
541                         *idpp= id;
542                         return;
543                 }
544                 id= id->next;
545         }
546         *idpp= NULL;
547 }
548
549
550 void test_obpoin_but(struct bContext *C, char *name, ID **idpp)
551 {
552         ID *id;
553         
554 // XXX  if(idpp == (ID **)&(emptytex.object)) {
555 //              error("You must add a texture first");
556 //              *idpp= 0;
557 //              return;
558 //      }
559         
560         id= CTX_data_main(C)->object.first;
561         while(id) {
562                 if( strcmp(name, id->name+2)==0 ) {
563                         *idpp= id;
564                         id_lib_extern(id);      /* checks lib data, sets correct flag for saving then */
565                         return;
566                 }
567                 id= id->next;
568         }
569         *idpp= NULL;
570 }
571
572 /* tests for an object of type OB_MESH */
573 void test_meshobpoin_but(struct bContext *C, char *name, ID **idpp)
574 {
575         ID *id;
576
577         id = CTX_data_main(C)->object.first;
578         while(id) {
579                 Object *ob = (Object *)id;
580                 if(ob->type == OB_MESH && strcmp(name, id->name + 2) == 0) {
581                         *idpp = id;
582                         /* checks lib data, sets correct flag for saving then */
583                         id_lib_extern(id);
584                         return;
585                 }
586                 id = id->next;
587         }
588         *idpp = NULL;
589 }
590
591 void test_meshpoin_but(struct bContext *C, char *name, ID **idpp)
592 {
593         ID *id;
594
595         if( *idpp ) (*idpp)->us--;
596         
597         id= CTX_data_main(C)->mesh.first;
598         while(id) {
599                 if( strcmp(name, id->name+2)==0 ) {
600                         *idpp= id;
601                         id_us_plus(id);
602                         return;
603                 }
604                 id= id->next;
605         }
606         *idpp= NULL;
607 }
608
609 void test_matpoin_but(struct bContext *C, char *name, ID **idpp)
610 {
611         ID *id;
612
613         if( *idpp ) (*idpp)->us--;
614         
615         id= CTX_data_main(C)->mat.first;
616         while(id) {
617                 if( strcmp(name, id->name+2)==0 ) {
618                         *idpp= id;
619                         id_us_plus(id);
620                         return;
621                 }
622                 id= id->next;
623         }
624         *idpp= NULL;
625 }
626
627 void test_scenepoin_but(struct bContext *C, char *name, ID **idpp)
628 {
629         ID *id;
630         
631         if( *idpp ) (*idpp)->us--;
632         
633         id= CTX_data_main(C)->scene.first;
634         while(id) {
635                 if( strcmp(name, id->name+2)==0 ) {
636                         *idpp= id;
637                         id_us_plus(id);
638                         return;
639                 }
640                 id= id->next;
641         }
642         *idpp= NULL;
643 }
644
645 void test_grouppoin_but(struct bContext *C, char *name, ID **idpp)
646 {
647         ID *id;
648         
649         if( *idpp ) (*idpp)->us--;
650         
651         id= CTX_data_main(C)->group.first;
652         while(id) {
653                 if( strcmp(name, id->name+2)==0 ) {
654                         *idpp= id;
655                         id_us_plus(id);
656                         return;
657                 }
658                 id= id->next;
659         }
660         *idpp= NULL;
661 }
662
663 void test_texpoin_but(struct bContext *C, char *name, ID **idpp)
664 {
665         ID *id;
666         
667         if( *idpp ) (*idpp)->us--;
668         
669         id= CTX_data_main(C)->tex.first;
670         while(id) {
671                 if( strcmp(name, id->name+2)==0 ) {
672                         *idpp= id;
673                         id_us_plus(id);
674                         return;
675                 }
676                 id= id->next;
677         }
678         *idpp= NULL;
679 }
680
681 void test_imapoin_but(struct bContext *C, char *name, ID **idpp)
682 {
683         ID *id;
684         
685         if( *idpp ) (*idpp)->us--;
686         
687         id= CTX_data_main(C)->image.first;
688         while(id) {
689                 if( strcmp(name, id->name+2)==0 ) {
690                         *idpp= id;
691                         id_us_plus(id);
692                         return;
693                 }
694                 id= id->next;
695         }
696         *idpp= NULL;
697 }
698
699 /* autocomplete callback for  buttons */
700 void autocomplete_bone(struct bContext *C, char *str, void *arg_v)
701 {
702         Object *ob= (Object *)arg_v;
703         
704         if(ob==NULL || ob->pose==NULL) return;
705         
706         /* search if str matches the beginning of name */
707         if(str[0]) {
708                 AutoComplete *autocpl= autocomplete_begin(str, 32);
709                 bPoseChannel *pchan;
710                 
711                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
712                         autocomplete_do_name(autocpl, pchan->name);
713                 
714                 autocomplete_end(autocpl, str);
715         }
716 }
717
718 /* autocomplete callback for buttons */
719 void autocomplete_vgroup(struct bContext *C, char *str, void *arg_v)
720 {
721         Object *ob= (Object *)arg_v;
722         
723         if(ob==NULL) return;
724         
725         /* search if str matches the beginning of a name */
726         if(str[0]) {
727                 AutoComplete *autocpl= autocomplete_begin(str, 32);
728                 bDeformGroup *dg;
729                 
730                 for(dg= ob->defbase.first; dg; dg= dg->next)
731                         if(dg->name!=str)
732                                 autocomplete_do_name(autocpl, dg->name);
733                 
734                 autocomplete_end(autocpl, str);
735         }
736 }
737
738
739 /* ----------- custom button group ---------------------- */
740
741 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *unused)
742 {
743         CurveMapping *cumap = cumap_v;
744         float d;
745         
746         /* we allow 20 times zoom */
747         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
748                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
749                 cumap->curr.xmin+= d;
750                 cumap->curr.xmax-= d;
751                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
752                 cumap->curr.ymin+= d;
753                 cumap->curr.ymax-= d;
754         }
755 }
756
757 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *unused)
758 {
759         CurveMapping *cumap = cumap_v;
760         float d, d1;
761         
762         /* we allow 20 times zoom, but dont view outside clip */
763         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
764                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
765                 
766                 if(cumap->flag & CUMA_DO_CLIP) 
767                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
768                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
769                 cumap->curr.xmin-= d1;
770                 
771                 d1= d;
772                 if(cumap->flag & CUMA_DO_CLIP) 
773                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
774                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
775                 cumap->curr.xmax+= d1;
776                 
777                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
778                 
779                 if(cumap->flag & CUMA_DO_CLIP) 
780                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
781                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
782                 cumap->curr.ymin-= d1;
783                 
784                 d1= d;
785                 if(cumap->flag & CUMA_DO_CLIP) 
786                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
787                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
788                 cumap->curr.ymax+= d1;
789         }
790 }
791
792 static void curvemap_buttons_setclip(bContext *C, void *cumap_v, void *unused)
793 {
794         CurveMapping *cumap = cumap_v;
795         
796         curvemapping_changed(cumap, 0);
797 }       
798
799 static void curvemap_buttons_delete(bContext *C, void *cumap_v, void *unused)
800 {
801         CurveMapping *cumap = cumap_v;
802         
803         curvemap_remove(cumap->cm+cumap->cur, SELECT);
804         curvemapping_changed(cumap, 0);
805 }
806
807 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
808 static uiBlock *curvemap_clipping_func(struct bContext *C, struct ARegion *ar, void *cumap_v)
809 {
810         CurveMapping *cumap = cumap_v;
811         uiBlock *block;
812         uiBut *bt;
813         
814         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
815         
816         /* use this for a fake extra empy space around the buttons */
817         uiDefBut(block, LABEL, 0, "",                   -4, 16, 128, 106, NULL, 0, 0, 0, 0, "");
818         
819         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
820                                                                                 0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, "");
821         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
822
823         uiBlockBeginAlign(block);
824         uiDefButF(block, NUM, 0, "Min X ",       0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
825         uiDefButF(block, NUM, 0, "Min Y ",       0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
826         uiDefButF(block, NUM, 0, "Max X ",       0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
827         uiDefButF(block, NUM, 0, "Max Y ",       0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
828         
829         uiBlockSetDirection(block, UI_RIGHT);
830         
831         uiEndBlock(C, block);
832         return block;
833 }
834
835
836 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
837 {
838         CurveMapping *cumap = cumap_v;
839         CurveMap *cuma= cumap->cm+cumap->cur;
840         
841         switch(event) {
842                 case 0:
843                         curvemap_reset(cuma, &cumap->clipr);
844                         curvemapping_changed(cumap, 0);
845                         break;
846                 case 1:
847                         cumap->curr= cumap->clipr;
848                         break;
849                 case 2: /* set vector */
850                         curvemap_sethandle(cuma, 1);
851                         curvemapping_changed(cumap, 0);
852                         break;
853                 case 3: /* set auto */
854                         curvemap_sethandle(cuma, 0);
855                         curvemapping_changed(cumap, 0);
856                         break;
857                 case 4: /* extend horiz */
858                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
859                         curvemapping_changed(cumap, 0);
860                         break;
861                 case 5: /* extend extrapolate */
862                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
863                         curvemapping_changed(cumap, 0);
864                         break;
865         }
866         ED_region_tag_redraw(CTX_wm_region(C));
867 }
868
869 static uiBlock *curvemap_tools_func(struct bContext *C, struct ARegion *ar, void *cumap_v)
870 {
871         uiBlock *block;
872         short yco= 0, menuwidth=120;
873         
874         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
875         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
876         
877         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
878         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
879         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
880         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
881         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
882         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
883         
884         uiBlockSetDirection(block, UI_RIGHT);
885         uiTextBoundsBlock(block, 50);
886         
887         uiEndBlock(C, block);
888         return block;
889 }
890
891 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
892 void curvemap_buttons(uiBlock *block, CurveMapping *cumap, char labeltype, short event, short redraw, rctf *rect)
893 {
894         uiBut *bt;
895         float dx, fy= rect->ymax-18.0f;
896         int icon;
897         short xco, yco;
898         
899         yco= (short)(rect->ymax-18.0f);
900         
901         /* curve choice options + tools/settings, 8 icons + spacer */
902         dx= (rect->xmax-rect->xmin)/(9.0f);
903         
904         uiBlockBeginAlign(block);
905         if(labeltype=='v') {    /* vector */
906                 xco= (short)rect->xmin;
907                 if(cumap->cm[0].curve)
908                         uiDefButI(block, ROW, redraw, "X", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
909                 xco= (short)(rect->xmin+1.0f*dx);
910                 if(cumap->cm[1].curve)
911                         uiDefButI(block, ROW, redraw, "Y", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
912                 xco= (short)(rect->xmin+2.0f*dx);
913                 if(cumap->cm[2].curve)
914                         uiDefButI(block, ROW, redraw, "Z", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
915         }
916         else if(labeltype=='c') { /* color */
917                 xco= (short)rect->xmin;
918                 if(cumap->cm[3].curve)
919                         uiDefButI(block, ROW, redraw, "C", xco, yco+2, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
920                 xco= (short)(rect->xmin+1.0f*dx);
921                 if(cumap->cm[0].curve)
922                         uiDefButI(block, ROW, redraw, "R", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
923                 xco= (short)(rect->xmin+2.0f*dx);
924                 if(cumap->cm[1].curve)
925                         uiDefButI(block, ROW, redraw, "G", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
926                 xco= (short)(rect->xmin+3.0f*dx);
927                 if(cumap->cm[2].curve)
928                         uiDefButI(block, ROW, redraw, "B", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
929         }
930         /* else no channels ! */
931         uiBlockEndAlign(block);
932
933         xco= (short)(rect->xmin+4.5f*dx);
934         uiBlockSetEmboss(block, UI_EMBOSSN);
935         bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMIN, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
936         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
937         
938         xco= (short)(rect->xmin+5.25f*dx);
939         bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMOUT, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
940         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
941         
942         xco= (short)(rect->xmin+6.0f*dx);
943         bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, event, ICON_MODIFIER, xco, yco, dx, 18, "Tools");
944         
945         xco= (short)(rect->xmin+7.0f*dx);
946         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
947         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, event, icon, xco, yco, dx, 18, "Clipping Options");
948         
949         xco= (short)(rect->xmin+8.0f*dx);
950         bt= uiDefIconBut(block, BUT, event, ICON_X, xco, yco, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
951         uiButSetFunc(bt, curvemap_buttons_delete, cumap, NULL);
952         
953         uiBlockSetEmboss(block, UI_EMBOSS);
954         
955         uiDefBut(block, BUT_CURVE, event, "", 
956                           rect->xmin, rect->ymin, rect->xmax-rect->xmin, fy-rect->ymin, 
957                           cumap, 0.0f, 1.0f, 0, 0, "");
958 }
959
960 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
961 void curvemap_layout(uiLayout *layout, CurveMapping *cumap, char labeltype, short event, short redraw, rctf *rect)
962 {
963         uiLayout *row;
964         uiBlock *block;
965         uiBut *bt;
966         float dx, fy= rect->ymax-18.0f;
967         int icon;
968         
969         block= uiLayoutGetBlock(layout);
970         
971         /* curve choice options + tools/settings, 8 icons + spacer */
972         dx= UI_UNIT_X;
973         
974         row= uiLayoutRow(layout, 0);
975         uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
976
977         if(labeltype=='v') {    /* vector */
978                 row= uiLayoutRow(layout, 1);
979
980                 if(cumap->cm[0].curve)
981                         uiDefButI(block, ROW, redraw, "X", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
982                 if(cumap->cm[1].curve)
983                         uiDefButI(block, ROW, redraw, "Y", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
984                 if(cumap->cm[2].curve)
985                         uiDefButI(block, ROW, redraw, "Z", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
986         }
987         else if(labeltype=='c') { /* color */
988                 row= uiLayoutRow(layout, 1);
989
990                 if(cumap->cm[3].curve)
991                         uiDefButI(block, ROW, redraw, "C", 0, 0, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
992                 if(cumap->cm[0].curve)
993                         uiDefButI(block, ROW, redraw, "R", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
994                 if(cumap->cm[1].curve)
995                         uiDefButI(block, ROW, redraw, "G", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
996                 if(cumap->cm[2].curve)
997                         uiDefButI(block, ROW, redraw, "B", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
998         }
999
1000         row= uiLayoutRow(row, 1);
1001
1002         uiBlockSetEmboss(block, UI_EMBOSSN);
1003         bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMIN, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
1004         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1005         
1006         bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMOUT, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
1007         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1008         
1009         bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, event, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1010         
1011         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1012         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, event, icon, 0, 0, dx, 18, "Clipping Options");
1013         
1014         bt= uiDefIconBut(block, BUT, event, ICON_X, 0, 0, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
1015         uiButSetFunc(bt, curvemap_buttons_delete, cumap, NULL);
1016         
1017         uiBlockSetEmboss(block, UI_EMBOSS);
1018         
1019         row= uiLayoutRow(layout, 0);
1020         uiDefBut(block, BUT_CURVE, event, "", 
1021                           rect->xmin, rect->ymin, rect->xmax-rect->xmin, fy-rect->ymin, 
1022                           cumap, 0.0f, 1.0f, 0, 0, "");
1023 }
1024
1025
1026 #define B_BANDCOL 1
1027
1028 static int vergcband(const void *a1, const void *a2)
1029 {
1030         const CBData *x1=a1, *x2=a2;
1031
1032         if( x1->pos > x2->pos ) return 1;
1033         else if( x1->pos < x2->pos) return -1;
1034         return 0;
1035 }
1036
1037 static void colorband_pos_cb(bContext *C, void *coba_v, void *unused_v)
1038 {
1039         ColorBand *coba= coba_v;
1040         int a;
1041         
1042         if(coba->tot<2) return;
1043         
1044         for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
1045         qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
1046         for(a=0; a<coba->tot; a++) {
1047                 if(coba->data[a].cur==coba->cur) {
1048                         // XXX if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0);      /* button cur */
1049                         coba->cur= a;
1050                         break;
1051                 }
1052         }
1053
1054         WM_event_add_notifier(C, NC_TEXTURE, NULL);
1055 }
1056
1057 static void colorband_cb(bContext *C, void *coba_v, void *unused_v)
1058 {
1059         WM_event_add_notifier(C, NC_TEXTURE, NULL);
1060 }
1061
1062 static void colorband_add_cb(bContext *C, void *coba_v, void *unused_v)
1063 {
1064         ColorBand *coba= coba_v;
1065         
1066         if(coba->tot < MAXCOLORBAND-1) coba->tot++;
1067         coba->cur= coba->tot-1;
1068         
1069         colorband_pos_cb(C, coba, NULL);
1070         ED_undo_push(C, "Add colorband");
1071         WM_event_add_notifier(C, NC_TEXTURE, NULL);
1072 }
1073
1074 static void colorband_del_cb(bContext *C, void *coba_v, void *unused_v)
1075 {
1076         ColorBand *coba= coba_v;
1077         int a;
1078         
1079         if(coba->tot<2) return;
1080         
1081         for(a=coba->cur; a<coba->tot; a++) {
1082                 coba->data[a]= coba->data[a+1];
1083         }
1084         if(coba->cur) coba->cur--;
1085         coba->tot--;
1086         
1087         ED_undo_push(C, "Delete colorband");
1088         // XXX BIF_preview_changed(ID_TE);
1089         WM_event_add_notifier(C, NC_TEXTURE, NULL);
1090 }
1091
1092
1093 /* offset aligns from bottom, standard width 300, height 115 */
1094 static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, int redraw)
1095 {
1096         CBData *cbd;
1097         uiBut *bt;
1098         
1099         if(coba==NULL) return;
1100         
1101         bt= uiDefBut(block, BUT, redraw,        "Add",                  0+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Add a new color stop to the colorband");
1102         uiButSetFunc(bt, colorband_add_cb, coba, NULL);
1103         bt= uiDefBut(block, BUT, redraw,        "Delete",               60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position");
1104         uiDefButS(block, NUM, redraw,           "",                             120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Choose active color stop");
1105         
1106         uiButSetFunc(bt, colorband_del_cb, coba, NULL);
1107         
1108         bt= uiDefButS(block, MENU, redraw,              "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1109                 210+xoffs, 100+yoffs, 90, 20,           &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1110         uiButSetFunc(bt, colorband_cb, coba, NULL);
1111         uiBlockEndAlign(block);
1112
1113         bt= uiDefBut(block, BUT_COLORBAND, redraw, "",  xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, "");
1114         uiButSetFunc(bt, colorband_cb, coba, NULL);
1115         
1116         cbd= coba->data + coba->cur;
1117         
1118         bt= uiDefButF(block, NUM, redraw, "Pos:",                       0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop");
1119         uiButSetFunc(bt, colorband_pos_cb, coba, NULL);
1120         bt= uiDefButF(block, COL, redraw,               "",                             110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop");
1121         uiButSetFunc(bt, colorband_cb, coba, NULL);
1122         bt= uiDefButF(block, NUMSLI, redraw,    "A ",                   200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop");
1123         uiButSetFunc(bt, colorband_cb, coba, NULL);
1124
1125 }
1126
1127 static void colorband_buttons_small(uiBlock *block, ColorBand *coba, rctf *butr, int event)
1128 {
1129         CBData *cbd;
1130         uiBut *bt;
1131         float unit= (butr->xmax-butr->xmin)/14.0f;
1132         float xs= butr->xmin;
1133         
1134         cbd= coba->data + coba->cur;
1135         
1136         
1137         bt= uiDefBut(block, BUT, event, "Add",                  xs,butr->ymin+20.0f,2.0f*unit,20,       NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1138         uiButSetFunc(bt, colorband_add_cb, coba, NULL);
1139         bt= uiDefBut(block, BUT, event, "Delete",               xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20,     NULL, 0, 0, 0, 0, "Delete the active position");
1140         uiButSetFunc(bt, colorband_del_cb, coba, NULL);
1141         
1142         uiDefButF(block, COL, event,            "",                     xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20,                             &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop");
1143         uiDefButF(block, NUMSLI, event,         "A:",           xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20,     &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop");
1144         
1145         uiDefButS(block, MENU, event,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1146                 xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20,            &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1147
1148         uiDefBut(block, BUT_COLORBAND, event, "",               xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, "");
1149         uiBlockEndAlign(block);
1150 }
1151
1152 void colorband_buttons(uiBlock *block, ColorBand *coba, rctf *butr, int small)
1153 {
1154         if(small)
1155                 colorband_buttons_small(block, coba, butr, 0);
1156         else
1157                 colorband_buttons_large(block, coba, 0, 0, 0);
1158 }
1159