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