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