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