2.5: ID datablock button back, previously known as std_libbuttons. The
[blender.git] / source / blender / editors / interface / interface_handlers.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) 2008 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 #include <float.h>
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_color_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_texture_types.h"
37 #include "DNA_userdef_types.h"
38 #include "DNA_windowmanager_types.h"
39
40 #include "BLI_arithb.h"
41 #include "BLI_blenlib.h"
42 #include "PIL_time.h"
43
44 #include "BKE_colortools.h"
45 #include "BKE_context.h"
46 #include "BKE_idprop.h"
47 #include "BKE_report.h"
48 #include "BKE_texture.h"
49 #include "BKE_utildefines.h"
50
51 #include "ED_screen.h"
52
53 #include "UI_interface.h"
54 #include "UI_text.h"
55 #include "interface_intern.h"
56
57 #include "RNA_access.h"
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 /***************** structs and defines ****************/
63
64 #define BUTTON_TOOLTIP_DELAY            0.500
65 #define BUTTON_FLASH_DELAY                      0.020
66 #define BUTTON_AUTO_OPEN_THRESH         0.3
67 #define BUTTON_MOUSE_TOWARDS_THRESH     1.0
68
69 typedef enum uiButtonActivateType {
70         BUTTON_ACTIVATE_OVER,
71         BUTTON_ACTIVATE,
72         BUTTON_ACTIVATE_APPLY,
73         BUTTON_ACTIVATE_TEXT_EDITING,
74         BUTTON_ACTIVATE_OPEN
75 } uiButtonActivateType;
76
77 typedef enum uiHandleButtonState {
78         BUTTON_STATE_INIT,
79         BUTTON_STATE_HIGHLIGHT,
80         BUTTON_STATE_WAIT_FLASH,
81         BUTTON_STATE_WAIT_RELEASE,
82         BUTTON_STATE_WAIT_KEY_EVENT,
83         BUTTON_STATE_NUM_EDITING,
84         BUTTON_STATE_TEXT_EDITING,
85         BUTTON_STATE_TEXT_SELECTING,
86         BUTTON_STATE_MENU_OPEN,
87         BUTTON_STATE_EXIT
88 } uiHandleButtonState;
89
90 typedef struct uiHandleButtonData {
91         wmWindow *window;
92         ARegion *region;
93
94         int interactive;
95
96         /* overall state */
97         uiHandleButtonState state;
98         int cancel, retval;
99         int applied, appliedinteractive;
100         wmTimer *flashtimer;
101
102         /* edited value */
103         char *str, *origstr;
104         double value, origvalue;
105         float vec[3], origvec[3];
106         int togdual, togonly;
107         ColorBand *coba;
108         CurveMapping *cumap;
109
110         /* tooltip */
111         ARegion *tooltip;
112         wmTimer *tooltiptimer;
113         wmTimer *autoopentimer;
114
115         /* text selection/editing */
116         int maxlen, selextend, selstartx;
117
118         /* number editing / dragging */
119         int draglastx, draglasty;
120         int dragstartx, dragstarty;
121         int dragchange, draglock, dragsel;
122         float dragf, dragfstart;
123         CBData *dragcbd;
124
125         /* menu open */
126         uiPopupBlockHandle *menu;
127         int menuretval;
128
129         /* post activate */
130         uiButtonActivateType posttype;
131         uiBut *postbut;
132 } uiHandleButtonData;
133
134 typedef struct uiAfterFunc {
135         struct uiAfterFunc *next, *prev;
136
137         uiButHandleFunc func;
138         void *func_arg1;
139         void *func_arg2;
140
141         uiButHandleNFunc funcN;
142         void *func_argN;
143
144         uiBlockHandleFunc handle_func;
145         void *handle_func_arg;
146         int retval;
147
148         uiMenuHandleFunc butm_func;
149         void *butm_func_arg;
150         int a2;
151
152         const char *opname;
153         int opcontext;
154         PointerRNA *opptr;
155
156         PointerRNA rnapoin;
157         PropertyRNA *rnaprop;
158 } uiAfterFunc;
159
160 static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
161 static int ui_handler_region_menu(bContext *C, wmEvent *event, void *userdata);
162 static int ui_handler_popup(bContext *C, wmEvent *event, void *userdata);
163 static void ui_handler_remove_popup(bContext *C, void *userdata);
164 static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
165
166 /* ******************** menu navigation helpers ************** */
167
168 static uiBut *ui_but_prev(uiBut *but)
169 {
170         while(but->prev) {
171                 but= but->prev;
172                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
173         }
174         return NULL;
175 }
176
177 static uiBut *ui_but_next(uiBut *but)
178 {
179         while(but->next) {
180                 but= but->next;
181                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
182         }
183         return NULL;
184 }
185
186 static uiBut *ui_but_first(uiBlock *block)
187 {
188         uiBut *but;
189         
190         but= block->buttons.first;
191         while(but) {
192                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
193                 but= but->next;
194         }
195         return NULL;
196 }
197
198 static uiBut *ui_but_last(uiBlock *block)
199 {
200         uiBut *but;
201         
202         but= block->buttons.last;
203         while(but) {
204                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
205                 but= but->prev;
206         }
207         return NULL;
208 }
209
210 /* ********************** button apply/revert ************************/
211
212 static ListBase UIAfterFuncs = {NULL, NULL};
213
214 static void ui_apply_but_func(bContext *C, uiBut *but)
215 {
216         uiAfterFunc *after;
217         uiBlock *block= but->block;
218
219         /* these functions are postponed and only executed after all other
220          * handling is done, i.e. menus are closed, in order to avoid conflicts
221          * with these functions removing the buttons we are working with */
222
223         if(but->func || but->funcN || block->handle_func || (but->type == BUTM && block->butm_func) || but->opname || but->rnaprop) {
224                 after= MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc");
225
226                 after->func= but->func;
227                 after->func_arg1= but->func_arg1;
228                 after->func_arg2= but->func_arg2;
229
230                 after->funcN= but->funcN;
231                 after->func_argN= but->func_argN;
232
233                 after->handle_func= block->handle_func;
234                 after->handle_func_arg= block->handle_func_arg;
235                 after->retval= but->retval;
236
237                 if(but->type == BUTM) {
238                         after->butm_func= block->butm_func;
239                         after->butm_func_arg= block->butm_func_arg;
240                         after->a2= but->a2;
241                 }
242
243                 after->opname= but->opname;
244                 after->opcontext= but->opcontext;
245                 after->opptr= but->opptr;
246
247                 after->rnapoin= but->rnapoin;
248                 after->rnaprop= but->rnaprop;
249
250                 but->opname= NULL;
251                 but->opcontext= 0;
252                 but->opptr= NULL;
253
254                 BLI_addtail(&UIAfterFuncs, after);
255         }
256 }
257
258 static void ui_apply_but_funcs_after(bContext *C)
259 {
260         uiAfterFunc *afterf, after;
261         ListBase funcs;
262
263         /* copy to avoid recursive calls */
264         funcs= UIAfterFuncs;
265         UIAfterFuncs.first= UIAfterFuncs.last= NULL;
266
267         for(afterf=funcs.first; afterf; afterf=after.next) {
268                 after= *afterf; /* copy to avoid memleak on exit() */
269                 BLI_freelinkN(&funcs, afterf);
270
271                 if(after.func)
272                         after.func(C, after.func_arg1, after.func_arg2);
273                 if(after.funcN)
274                         after.funcN(C, after.func_argN, after.func_arg2);
275                 
276                 if(after.handle_func)
277                         after.handle_func(C, after.handle_func_arg, after.retval);
278                 if(after.butm_func)
279                         after.butm_func(C, after.butm_func_arg, after.a2);
280
281                 if(after.opname)
282                         WM_operator_name_call(C, after.opname, after.opcontext, after.opptr);
283                 if(after.opptr) {
284                         WM_operator_properties_free(after.opptr);
285                         MEM_freeN(after.opptr);
286                 }
287
288                 if(after.rnapoin.data)
289                         RNA_property_update(C, &after.rnapoin, after.rnaprop);
290         }
291 }
292
293 static void ui_apply_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data)
294 {
295         ui_apply_but_func(C, but);
296
297         data->retval= but->retval;
298         data->applied= 1;
299 }
300
301 static void ui_apply_but_BUTM(bContext *C, uiBut *but, uiHandleButtonData *data)
302 {
303         ui_set_but_val(but, but->min);
304         ui_apply_but_func(C, but);
305
306         data->retval= but->retval;
307         data->applied= 1;
308 }
309
310 static void ui_apply_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data)
311 {
312         if(but->type == COL)
313                 ui_set_but_vectorf(but, data->vec);
314         else if(ELEM3(but->type, MENU, ICONROW, ICONTEXTROW))
315                 ui_set_but_val(but, data->value);
316
317         ui_check_but(but);
318         ui_apply_but_func(C, but);
319         data->retval= but->retval;
320         data->applied= 1;
321 }
322
323 static void ui_apply_but_TOG(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
324 {
325         double value;
326         int w, lvalue, push;
327         
328         /* local hack... */
329         if(but->type==BUT_TOGDUAL && data->togdual) {
330                 if(but->pointype==SHO)
331                         but->poin += 2;
332                 else if(but->pointype==INT)
333                         but->poin += 4;
334         }
335         
336         value= ui_get_but_val(but);
337         lvalue= (int)value;
338         
339         if(but->bit) {
340                 w= BTST(lvalue, but->bitnr);
341                 if(w) lvalue = BCLR(lvalue, but->bitnr);
342                 else lvalue = BSET(lvalue, but->bitnr);
343                 
344                 if(but->type==TOGR) {
345                         if(!data->togonly) {
346                                 lvalue= 1<<(but->bitnr);
347         
348                                 ui_set_but_val(but, (double)lvalue);
349                         }
350                         else {
351                                 if(lvalue==0) lvalue= 1<<(but->bitnr);
352                         }
353                 }
354                 
355                 ui_set_but_val(but, (double)lvalue);
356                 if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but);
357         }
358         else {
359                 
360                 if(value==0.0) push= 1; 
361                 else push= 0;
362                 
363                 if(but->type==TOGN || but->type==ICONTOGN) push= !push;
364                 ui_set_but_val(but, (double)push);
365                 if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but);                
366         }
367         
368         /* end local hack... */
369         if(but->type==BUT_TOGDUAL && data->togdual) {
370                 if(but->pointype==SHO)
371                         but->poin -= 2;
372                 else if(but->pointype==INT)
373                         but->poin -= 4;
374         }
375         
376         ui_apply_but_func(C, but);
377
378         data->retval= but->retval;
379         data->applied= 1;
380 }
381
382 static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
383 {
384         ui_set_but_val(but, but->max);
385         ui_apply_but_func(C, but);
386
387         data->retval= but->retval;
388         data->applied= 1;
389 }
390
391 static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
392 {
393         if(!data->str)
394                 return;
395
396         ui_set_but_string(but, data->str);
397         ui_check_but(but);
398
399         /* give butfunc the original text too */
400         /* feature used for bone renaming, channels, etc */
401         if(but->func_arg2==NULL) but->func_arg2= data->origstr;
402         ui_apply_but_func(C, but);
403         if(but->func_arg2==data->origstr) but->func_arg2= NULL;
404
405         data->retval= but->retval;
406         data->applied= 1;
407 }
408
409 static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
410 {
411         if(data->str) {
412                 /* XXX 2.50 missing python api */
413 #if 0
414                 if(BPY_button_eval(data->str, &data->value)) {
415                         BKE_report(CTX_reports(C), RPT_WARNING, "Invalid Python expression, check console");
416                         data->value = 0.0f; /* Zero out value on error */
417                         
418                         if(data->str[0]) {
419                                 data->cancel= 1; /* invalidate return value if eval failed, except when string was null */
420                                 return;
421                         }
422                 }
423 #else
424                 data->value= atof(data->str);
425 #endif
426
427                 if(!ui_is_but_float(but)) data->value= (int)data->value;
428                 if(but->type==NUMABS) data->value= fabs(data->value);
429                 if(data->value<but->min) data->value= but->min;
430                 if(data->value>but->max) data->value= but->max;
431         }
432
433         ui_set_but_val(but, data->value);
434         ui_check_but(but);
435         ui_apply_but_func(C, but);
436
437         data->retval= but->retval;
438         data->applied= 1;
439 }
440
441 static void ui_apply_but_LABEL(bContext *C, uiBut *but, uiHandleButtonData *data)
442 {
443         ui_apply_but_func(C, but);
444         data->retval= but->retval;
445         data->applied= 1;
446 }
447
448 static void ui_apply_but_TOG3(bContext *C, uiBut *but, uiHandleButtonData *data)
449
450         if(but->pointype==SHO ) {
451                 short *sp= (short *)but->poin;
452                 
453                 if( BTST(sp[1], but->bitnr)) {
454                         sp[1]= BCLR(sp[1], but->bitnr);
455                         sp[0]= BCLR(sp[0], but->bitnr);
456                 }
457                 else if( BTST(sp[0], but->bitnr)) {
458                         sp[1]= BSET(sp[1], but->bitnr);
459                 } else {
460                         sp[0]= BSET(sp[0], but->bitnr);
461                 }
462         }
463         else {
464                 if( BTST(*(but->poin+2), but->bitnr)) {
465                         *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
466                         *(but->poin)= BCLR(*(but->poin), but->bitnr);
467                 }
468                 else if( BTST(*(but->poin), but->bitnr)) {
469                         *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
470                 } else {
471                         *(but->poin)= BSET(*(but->poin), but->bitnr);
472                 }
473         }
474         
475         ui_check_but(but);
476         ui_apply_but_func(C, but);
477         data->retval= but->retval;
478         data->applied= 1;
479 }
480
481 static void ui_apply_but_VEC(bContext *C, uiBut *but, uiHandleButtonData *data)
482 {
483         ui_set_but_vectorf(but, data->vec);
484         ui_check_but(but);
485         ui_apply_but_func(C, but);
486
487         data->retval= but->retval;
488         data->applied= 1;
489 }
490
491 static void ui_apply_but_COLORBAND(bContext *C, uiBut *but, uiHandleButtonData *data)
492 {
493         ui_apply_but_func(C, but);
494         data->retval= but->retval;
495         data->applied= 1;
496 }
497
498 static void ui_apply_but_CURVE(bContext *C, uiBut *but, uiHandleButtonData *data)
499 {
500         ui_apply_but_func(C, but);
501         data->retval= but->retval;
502         data->applied= 1;
503 }
504
505 static void ui_apply_but_IDPOIN(bContext *C, uiBut *but, uiHandleButtonData *data)
506 {
507         but->idpoin_func(C, data->str, but->idpoin_idpp);
508         ui_check_but(but);
509         ui_apply_but_func(C, but);
510         data->retval= but->retval;
511         data->applied= 1;
512 }
513
514 #ifdef INTERNATIONAL
515 static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *data)
516 {
517         ui_apply_but_func(C, but);
518         data->retval= but->retval;
519         data->applied= 1;
520 }
521 #endif
522
523 static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, int interactive)
524 {
525         char *editstr;
526         double *editval;
527         float *editvec;
528         ColorBand *editcoba;
529         CurveMapping *editcumap;
530
531         data->retval= 0;
532
533         /* if we cancel and have not applied yet, there is nothing to do,
534          * otherwise we have to restore the original value again */
535         if(data->cancel) {
536                 if(!data->applied)
537                         return;
538
539                 if(data->str) MEM_freeN(data->str);
540                 data->str= data->origstr;
541                 data->origstr= NULL;
542                 data->value= data->origvalue;
543                 data->origvalue= 0.0;
544                 VECCOPY(data->vec, data->origvec);
545                 data->origvec[0]= data->origvec[1]= data->origvec[2]= 0.0f;
546         }
547         else {
548                 /* we avoid applying interactive edits a second time
549                  * at the end with the appliedinteractive flag */
550                 if(interactive)
551                         data->appliedinteractive= 1;
552                 else if(data->appliedinteractive)
553                         return;
554         }
555
556         /* ensures we are writing actual values */
557         editstr= but->editstr;
558         editval= but->editval;
559         editvec= but->editvec;
560         editcoba= but->editcoba;
561         editcumap= but->editcumap;
562         but->editstr= NULL;
563         but->editval= NULL;
564         but->editvec= NULL;
565         but->editcoba= NULL;
566         but->editcumap= NULL;
567
568         /* handle different types */
569         switch(but->type) {
570                 case BUT:
571                         ui_apply_but_BUT(C, but, data);
572                         break;
573                 case TEX:
574                         ui_apply_but_TEX(C, but, data);
575                         break;
576                 case TOG: 
577                 case TOGR: 
578                 case ICONTOG:
579                 case ICONTOGN:
580                 case TOGN:
581                 case BUT_TOGDUAL:
582                         ui_apply_but_TOG(C, block, but, data);
583                         break;
584                 case ROW:
585                         ui_apply_but_ROW(C, block, but, data);
586                         break;
587                 case SCROLL:
588                         break;
589                 case NUM:
590                 case NUMABS:
591                         ui_apply_but_NUM(C, but, data);
592                         break;
593                 case SLI:
594                 case NUMSLI:
595                         ui_apply_but_NUM(C, but, data);
596                         break;
597                 case HSVSLI:
598                         break;
599                 case ROUNDBOX:  
600                 case LABEL:     
601                         ui_apply_but_LABEL(C, but, data);
602                         break;
603                 case TOG3:      
604                         ui_apply_but_TOG3(C, but, data);
605                         break;
606                 case MENU:
607                 case ICONROW:
608                 case ICONTEXTROW:
609                 case BLOCK:
610                 case PULLDOWN:
611                 case HMENU:
612                 case COL:
613                         ui_apply_but_BLOCK(C, but, data);
614                         break;
615                 case BUTM:
616                         ui_apply_but_BUTM(C, but, data);
617                         break;
618                 case BUT_NORMAL:
619                 case HSVCUBE:
620                         ui_apply_but_VEC(C, but, data);
621                         break;
622                 case BUT_COLORBAND:
623                         ui_apply_but_COLORBAND(C, but, data);
624                         break;
625                 case BUT_CURVE:
626                         ui_apply_but_CURVE(C, but, data);
627                         break;
628                 case IDPOIN:
629                         ui_apply_but_IDPOIN(C, but, data);
630                         break;
631 #ifdef INTERNATIONAL
632                 case CHARTAB:
633                         ui_apply_but_CHARTAB(C, but, data);
634                         break;
635 #endif
636                 case LINK:
637                 case INLINK:
638                         break;
639         }
640
641         but->editstr= editstr;
642         but->editval= editval;
643         but->editvec= editvec;
644         but->editcoba= editcoba;
645         but->editcumap= editcumap;
646 }
647
648 /* ******************* copy and paste ********************  */
649
650 /* c = copy, v = paste */
651 static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode)
652 {
653         static ColorBand but_copypaste_coba = {0};
654         char buf[UI_MAX_DRAW_STR+1]= {0};
655         double val;
656         
657         if(mode=='v' && but->lock)
658                 return;
659
660         if(mode=='v') {
661                 /* extract first line from clipboard in case of multi-line copies */
662                 char *p = NULL; /* XXX 2.48 getClipboard(0); */
663                 if(p) {
664                         int i = 0;
665                         while (*p && *p!='\r' && *p!='\n' && i<UI_MAX_DRAW_STR) {
666                                 buf[i++]=*p;
667                                 p++;
668                         }
669                         buf[i]= 0;
670                 }
671         }
672         
673         /* numeric value */
674         if ELEM4(but->type, NUM, NUMABS, NUMSLI, HSVSLI) {
675                 
676                 if(but->poin==NULL && but->rnapoin.data==NULL);
677                 else if(mode=='c') {
678                         sprintf(buf, "%f", ui_get_but_val(but));
679                         /* XXX 2.48 putClipboard(buf, 0); */
680                 }
681                 else {
682                         if (sscanf(buf, " %lf ", &val) == 1) {
683                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
684                                 data->value= val;
685                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
686                         }
687                 }
688         }
689
690         /* RGB triple */
691         else if(but->type==COL) {
692                 float rgb[3];
693                 
694                 if(but->poin==NULL && but->rnapoin.data==NULL);
695                 else if(mode=='c') {
696
697                         ui_get_but_vectorf(but, rgb);
698                         sprintf(buf, "[%f, %f, %f]", rgb[0], rgb[1], rgb[2]);
699                         /* XXX 2.48 putClipboard(buf, 0); */
700                         
701                 }
702                 else {
703                         if (sscanf(buf, "[%f, %f, %f]", &rgb[0], &rgb[1], &rgb[2]) == 3) {
704                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
705                                 VECCOPY(data->vec, rgb);
706                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
707                         }
708                 }
709         }
710
711         /* text/string and ID data */
712         else if(ELEM(but->type, TEX, IDPOIN)) {
713                 uiHandleButtonData *data= but->active;
714
715                 if(but->poin==NULL && but->rnapoin.data==NULL);
716                 else if(mode=='c') {
717                         button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
718                         BLI_strncpy(buf, data->str, UI_MAX_DRAW_STR);
719                         /* XXX 2.48 putClipboard(data->str, 0); */
720                         data->cancel= 1;
721                         button_activate_state(C, but, BUTTON_STATE_EXIT);
722                 }
723                 else {
724                         button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
725                         BLI_strncpy(data->str, buf, data->maxlen);
726                         button_activate_state(C, but, BUTTON_STATE_EXIT);
727                 }
728         }
729         /* colorband (not supported by system clipboard) */
730         else if(but->type==BUT_COLORBAND) {
731                 if(mode=='c') {
732                         if(but->poin)
733                                 return;
734
735                         memcpy(&but_copypaste_coba, but->poin, sizeof(ColorBand));
736                 }
737                 else {
738                         if(but_copypaste_coba.tot==0)
739                                 return;
740
741                         if(!but->poin)
742                                 but->poin= MEM_callocN(sizeof(ColorBand), "colorband");
743
744                         button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
745                         memcpy(data->coba, &but_copypaste_coba, sizeof(ColorBand) );
746                         button_activate_state(C, but, BUTTON_STATE_EXIT);
747                 }
748         }
749 }
750
751 /* ************* in-button text selection/editing ************* */
752
753 /* return 1 if char ch is special character, otherwise return 0 */
754 static short test_special_char(char ch)
755 {
756         switch(ch) {
757                 case '\\':
758                 case '/':
759                 case '~':
760                 case '!':
761                 case '@':
762                 case '#':
763                 case '$':
764                 case '%':
765                 case '^':
766                 case '&':
767                 case '*':
768                 case '(':
769                 case ')':
770                 case '+':
771                 case '=':
772                 case '{':
773                 case '}':
774                 case '[':
775                 case ']':
776                 case ':':
777                 case ';':
778                 case '\'':
779                 case '\"':
780                 case '<':
781                 case '>':
782                 case ',':
783                 case '.':
784                 case '?':
785                 case '_':
786                 case '-':
787                 case ' ':
788                         return 1;
789                         break;
790                 default:
791                         break;
792         }
793         return 0;
794 }
795
796 static int ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
797 {
798         char *str;
799         int x, changed;
800         
801         str= data->str;
802         changed= (but->selsta != but->selend);
803         
804         for(x=0; x< strlen(str); x++) {
805                 if (but->selend + x <= strlen(str) ) {
806                         str[but->selsta + x]= str[but->selend + x];
807                 } else {
808                         str[but->selsta + x]= '\0';
809                         break;
810                 }
811         }
812
813         but->pos = but->selend = but->selsta;
814
815         return changed;
816 }
817
818 static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, short x)
819 {
820         char *origstr;
821         
822         origstr= MEM_callocN(sizeof(char)*(data->maxlen+1), "ui_textedit origstr");
823         
824         BLI_strncpy(origstr, but->drawstr, data->maxlen+1);
825         but->pos= strlen(origstr)-but->ofs;
826         
827         while((but->aspect*UI_GetStringWidth(but->font, origstr+but->ofs, 0) + but->x1) > x) {
828                 if (but->pos <= 0) break;
829                 but->pos--;
830                 origstr[but->pos+but->ofs] = 0;
831         }
832         
833         but->pos -= strlen(but->str);
834         but->pos += but->ofs;
835         if(but->pos<0) but->pos= 0;
836
837         MEM_freeN(origstr);
838 }
839
840 static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, short x)
841 {
842         if (x > data->selstartx) data->selextend = EXTEND_RIGHT;
843         else if (x < data->selstartx) data->selextend = EXTEND_LEFT;
844
845         ui_textedit_set_cursor_pos(but, data, x);
846                                                 
847         if (data->selextend == EXTEND_RIGHT) but->selend = but->pos;
848         if (data->selextend == EXTEND_LEFT) but->selsta = but->pos;
849
850         ui_check_but(but);
851 }
852
853 static int ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
854 {
855         char *str;
856         int len, x, changed= 0;
857
858         str= data->str;
859         len= strlen(str);
860
861         if(len-(but->selend - but->selsta)+1 <= data->maxlen) {
862                 /* type over the current selection */
863                 if ((but->selend - but->selsta) > 0)
864                         changed= ui_textedit_delete_selection(but, data);
865
866                 len= strlen(str);
867                 if(len < data->maxlen) {
868                         for(x= data->maxlen; x>but->pos; x--)
869                                 str[x]= str[x-1];
870                         str[but->pos]= ascii;
871                         str[len+1]= '\0';
872
873                         but->pos++; 
874                         changed= 1;
875                 }
876         }
877
878         return WM_UI_HANDLER_BREAK;
879 }
880
881 void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int select, int jump)
882 {
883         char *str;
884         int len;
885
886         str= data->str;
887         len= strlen(str);
888
889         if(direction) { /* right*/
890                 /* if there's a selection */
891                 if ((but->selend - but->selsta) > 0) {
892                         /* extend the selection based on the first direction taken */
893                         if(select) {
894                                 if (!data->selextend) {
895                                         data->selextend = EXTEND_RIGHT;
896                                 }
897                                 if (data->selextend == EXTEND_RIGHT) {
898                                         but->selend++;
899                                         if (but->selend > len) but->selend = len;
900                                 } else if (data->selextend == EXTEND_LEFT) {
901                                         but->selsta++;
902                                         /* if the selection start has gone past the end,
903                                         * flip them so they're in sync again */
904                                         if (but->selsta == but->selend) {
905                                                 but->pos = but->selsta;
906                                                 data->selextend = EXTEND_RIGHT;
907                                         }
908                                 }
909                         } else {
910                                 but->selsta = but->pos = but->selend;
911                                 data->selextend = 0;
912                         }
913                 } else {
914                         if(select) {
915                                 /* make a selection, starting from the cursor position */
916                                 but->selsta = but->pos;
917                                 
918                                 but->pos++;
919                                 if(but->pos>strlen(str)) but->pos= strlen(str);
920                                 
921                                 but->selend = but->pos;
922                         } else if(jump) {
923                                 /* jump betweenn special characters (/,\,_,-, etc.),
924                                  * look at function test_special_char() for complete
925                                  * list of special character, ctr -> */
926                                 while(but->pos < len) {
927                                         but->pos++;
928                                         if(test_special_char(str[but->pos])) break;
929                                 }
930                         } else {
931                                 but->pos++;
932                                 if(but->pos>strlen(str)) but->pos= strlen(str);
933                         }
934                 }
935         }
936         else { /* left */
937                 /* if there's a selection */
938                 if ((but->selend - but->selsta) > 0) {
939                         /* extend the selection based on the first direction taken */
940                         if(select) {
941                                 if (!data->selextend) {
942                                         data->selextend = EXTEND_LEFT;
943                                 }
944                                 if (data->selextend == EXTEND_LEFT) {
945                                         but->selsta--;
946                                         if (but->selsta < 0) but->selsta = 0;
947                                 } else if (data->selextend == EXTEND_RIGHT) {
948                                         but->selend--;
949                                         /* if the selection start has gone past the end,
950                                         * flip them so they're in sync again */
951                                         if (but->selsta == but->selend) {
952                                                 but->pos = but->selsta;
953                                                 data->selextend = EXTEND_LEFT;
954                                         }
955                                 }
956                         } else {
957                                 but->pos = but->selend = but->selsta;
958                                 data->selextend = 0;
959                         }
960                 } else {
961                         if(select) {
962                                 /* make a selection, starting from the cursor position */
963                                 but->selend = but->pos;
964                                 
965                                 but->pos--;
966                                 if(but->pos<0) but->pos= 0;
967                                 
968                                 but->selsta = but->pos;
969                         } else if(jump) {
970                                 /* jump betweenn special characters (/,\,_,-, etc.),
971                                  * look at function test_special_char() for complete
972                                  * list of special character, ctr -> */
973                                 while(but->pos > 0){
974                                         but->pos--;
975                                         if(test_special_char(str[but->pos])) break;
976                                 }
977                         } else {
978                                 if(but->pos>0) but->pos--;
979                         }
980                 }
981         }
982 }
983
984 void ui_textedit_move_end(uiBut *but, uiHandleButtonData *data, int direction, int select)
985 {
986         char *str;
987
988         str= data->str;
989
990         if(direction) { /* right */
991                 if(select) {
992                         but->selsta = but->pos;
993                         but->selend = strlen(str);
994                         data->selextend = EXTEND_RIGHT;
995                 } else {
996                         but->selsta = but->selend = but->pos= strlen(str);
997                 }
998         }
999         else { /* left */
1000                 if(select) {
1001                         but->selend = but->pos;
1002                         but->selsta = 0;
1003                         data->selextend = EXTEND_LEFT;
1004                 } else {
1005                         but->selsta = but->selend = but->pos= 0;
1006                 }
1007         }
1008 }
1009
1010 static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int direction, int all)
1011 {
1012         char *str;
1013         int len, x, changed= 0;
1014
1015         str= data->str;
1016         len= strlen(str);
1017
1018         if(all) {
1019                 if(len) changed=1;
1020                 str[0]= 0;
1021                 but->pos= 0;
1022         }
1023         else if(direction) { /* delete */
1024                 if ((but->selend - but->selsta) > 0) {
1025                         changed= ui_textedit_delete_selection(but, data);
1026                 }
1027                 else if(but->pos>=0 && but->pos<len) {
1028                         for(x=but->pos; x<len; x++)
1029                                 str[x]= str[x+1];
1030                         str[len-1]='\0';
1031                         changed= 1;
1032                 }
1033         }
1034         else { /* backspace */
1035                 if(len!=0) {
1036                         if ((but->selend - but->selsta) > 0) {
1037                                 ui_textedit_delete_selection(but, data);
1038                         }
1039                         else if(but->pos>0) {
1040                                 for(x=but->pos; x<len; x++)
1041                                         str[x-1]= str[x];
1042                                 str[len-1]='\0';
1043
1044                                 but->pos--;
1045                                 changed= 1;
1046                         }
1047                 } 
1048         }
1049
1050         return changed;
1051 }
1052
1053 static int ui_textedit_autocomplete(bContext *C, uiBut *but, uiHandleButtonData *data)
1054 {
1055         char *str;
1056         int changed= 1;
1057
1058         str= data->str;
1059         but->autocomplete_func(C, str, but->autofunc_arg);
1060         but->pos= strlen(str);
1061
1062         return changed;
1063 }
1064
1065 static int ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, int paste, int copy, int cut)
1066 {
1067         char buf[UI_MAX_DRAW_STR]={0};
1068         char *str, *p;
1069         int len, x, y, i, changed= 0;
1070
1071         str= data->str;
1072         len= strlen(str);
1073         
1074         /* paste */
1075         if (paste) {
1076                 /* extract the first line from the clipboard */
1077                 p = NULL; /* XXX 2.48 getClipboard(0); */
1078
1079                 if(p && p[0]) {
1080                         while (*p && *p!='\r' && *p!='\n' && i<UI_MAX_DRAW_STR) {
1081                                 buf[i++]=*p;
1082                                 p++;
1083                         }
1084                         buf[i]= 0;
1085
1086                         /* paste over the current selection */
1087                         if ((but->selend - but->selsta) > 0)
1088                                 ui_textedit_delete_selection(but, data);
1089                         
1090                         for (y=0; y<strlen(buf); y++)
1091                         {
1092                                 /* add contents of buffer */
1093                                 if(len < data->maxlen) {
1094                                         for(x= data->maxlen; x>but->pos; x--)
1095                                                 str[x]= str[x-1];
1096                                         str[but->pos]= buf[y];
1097                                         but->pos++; 
1098                                         len++;
1099                                         str[len]= '\0';
1100                                 }
1101                         }
1102
1103                         changed= 1;
1104                 }
1105         }
1106         /* cut & copy */
1107         else if (copy || cut) {
1108                 /* copy the contents to the copypaste buffer */
1109                 for(x= but->selsta; x <= but->selend; x++) {
1110                         if (x==but->selend)
1111                                 buf[x] = '\0';
1112                         else
1113                                 buf[(x - but->selsta)] = str[x];
1114                 }
1115                 /* XXX 2.48 putClipboard(buf, 0); */
1116                 
1117                 /* for cut only, delete the selection afterwards */
1118                 if(cut)
1119                         if((but->selend - but->selsta) > 0)
1120                                 changed= ui_textedit_delete_selection(but, data);
1121         } 
1122
1123         return changed;
1124 }
1125
1126 static void ui_textedit_begin(uiBut *but, uiHandleButtonData *data)
1127 {
1128         if(data->str) {
1129                 MEM_freeN(data->str);
1130                 data->str= NULL;
1131         }
1132
1133         /* retrieve string */
1134         if(but->type == TEX) {
1135                 data->maxlen= but->max;
1136                 data->str= MEM_callocN(sizeof(char)*(data->maxlen+1), "textedit str");
1137
1138                 ui_get_but_string(but, data->str, data->maxlen+1);
1139         }
1140         else if(but->type == IDPOIN) {
1141                 ID *id;
1142                 
1143                 data->maxlen= 22;
1144                 data->str= MEM_callocN(sizeof(char)*(data->maxlen+1), "textedit str");
1145
1146                 id= *but->idpoin_idpp;
1147                 if(id) BLI_strncpy(data->str, id->name+2, data->maxlen+1);
1148                 else data->str[0]= 0;
1149         }
1150         else {
1151                 double value;
1152
1153                 data->maxlen= UI_MAX_DRAW_STR;
1154                 data->str= MEM_callocN(sizeof(char)*(data->maxlen+1), "textedit str");
1155                 
1156                 value= ui_get_but_val(but);
1157                 if(ui_is_but_float(but)) {
1158                         if(but->a2) { /* amount of digits defined */
1159                                 if(but->a2==1) sprintf(data->str, "%.1f", value);
1160                                 else if(but->a2==2) sprintf(data->str, "%.2f", value);
1161                                 else if(but->a2==3) sprintf(data->str, "%.3f", value);
1162                                 else sprintf(data->str, "%.4f", value);
1163                         }
1164                         else sprintf(data->str, "%.3f", value);
1165                 }
1166                 else {
1167                         sprintf(data->str, "%d", (int)value);
1168                 }
1169         }
1170
1171         data->origstr= BLI_strdup(data->str);
1172         data->selextend= 0;
1173         data->selstartx= 0;
1174
1175         /* set cursor pos to the end of the text */
1176         but->editstr= data->str;
1177         but->pos= strlen(data->str);
1178         but->selsta= 0;
1179         but->selend= strlen(but->drawstr) - strlen(but->str);
1180
1181         ui_check_but(but);
1182 }
1183
1184 static void ui_textedit_end(uiBut *but, uiHandleButtonData *data)
1185 {
1186         if(but) {
1187                 but->editstr= 0;
1188                 but->pos= -1;
1189         }
1190 }
1191
1192 static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data)
1193 {
1194         uiBut *but;
1195
1196         /* label and roundbox can overlap real buttons (backdrops...) */
1197         if(actbut->type==LABEL && actbut->type==ROUNDBOX)
1198                 return;
1199
1200         for(but= actbut->next; but; but= but->next) {
1201                 if(ELEM5(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI)) {
1202                         data->postbut= but;
1203                         data->posttype= BUTTON_ACTIVATE_TEXT_EDITING;
1204                         return;
1205                 }
1206         }
1207         for(but= block->buttons.first; but!=actbut; but= but->next) {
1208                 if(ELEM5(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI)) {
1209                         data->postbut= but;
1210                         data->posttype= BUTTON_ACTIVATE_TEXT_EDITING;
1211                         return;
1212                 }
1213         }
1214 }
1215
1216 static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data)
1217 {
1218         uiBut *but;
1219
1220         /* label and roundbox can overlap real buttons (backdrops...) */
1221         if(actbut->type==LABEL && actbut->type==ROUNDBOX)
1222                 return;
1223
1224         for(but= actbut->prev; but; but= but->prev) {
1225                 if(ELEM5(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI)) {
1226                         data->postbut= but;
1227                         data->posttype= BUTTON_ACTIVATE_TEXT_EDITING;
1228                         return;
1229                 }
1230         }
1231         for(but= block->buttons.last; but!=actbut; but= but->prev) {
1232                 if(ELEM5(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI)) {
1233                         data->postbut= but;
1234                         data->posttype= BUTTON_ACTIVATE_TEXT_EDITING;
1235                         return;
1236                 }
1237         }
1238 }
1239
1240 static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1241 {
1242         int mx, my, changed= 0, retval= WM_UI_HANDLER_CONTINUE;
1243
1244         switch(event->type) {
1245                 case RIGHTMOUSE:
1246                 case ESCKEY:
1247                         data->cancel= 1;
1248                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1249                         retval= WM_UI_HANDLER_BREAK;
1250                         break;
1251                 case LEFTMOUSE: {
1252                         if(event->val==KM_PRESS) {
1253                                 mx= event->x;
1254                                 my= event->y;
1255                                 ui_window_to_block(data->region, block, &mx, &my);
1256
1257                                 if ((but->y1 <= my) && (my <= but->y2) && (but->x1 <= mx) && (mx <= but->x2)) {
1258                                         ui_textedit_set_cursor_pos(but, data, mx);
1259                                         but->selsta = but->selend = but->pos;
1260                                         data->selstartx= mx;
1261
1262                                         button_activate_state(C, but, BUTTON_STATE_TEXT_SELECTING);
1263                                         retval= WM_UI_HANDLER_BREAK;
1264                                 }
1265                                 else {
1266                                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1267                                         retval= WM_UI_HANDLER_BREAK;
1268                                 }
1269                         }
1270                         break;
1271                 }
1272         }
1273
1274         if(event->val==KM_PRESS) {
1275                 switch (event->type) {
1276                         case VKEY:
1277                         case XKEY:
1278                         case CKEY:
1279                                 if(event->ctrl || event->oskey) {
1280                                         if(event->type == VKEY)
1281                                                 changed= ui_textedit_copypaste(but, data, 1, 0, 0);
1282                                         else if(event->type == XKEY)
1283                                                 changed= ui_textedit_copypaste(but, data, 0, 1, 0);
1284                                         else if(event->type == CKEY)
1285                                                 changed= ui_textedit_copypaste(but, data, 0, 0, 1);
1286
1287                                         retval= WM_UI_HANDLER_BREAK;
1288                                 }
1289                                 break;
1290                         case RIGHTARROWKEY:
1291                                 ui_textedit_move(but, data, 1, event->shift, event->ctrl);
1292                                 retval= WM_UI_HANDLER_BREAK;
1293                                 break;
1294                         case LEFTARROWKEY:
1295                                 ui_textedit_move(but, data, 0, event->shift, event->ctrl);
1296                                 retval= WM_UI_HANDLER_BREAK;
1297                                 break;
1298                         case DOWNARROWKEY:
1299                         case ENDKEY:
1300                                 ui_textedit_move_end(but, data, 1, event->shift);
1301                                 retval= WM_UI_HANDLER_BREAK;
1302                                 break;
1303                         case UPARROWKEY:
1304                         case HOMEKEY:
1305                                 ui_textedit_move_end(but, data, 0, event->shift);
1306                                 retval= WM_UI_HANDLER_BREAK;
1307                                 break;
1308                         case PADENTER:
1309                         case RETKEY:
1310                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1311                                 retval= WM_UI_HANDLER_BREAK;
1312                                 break;
1313                         case DELKEY:
1314                                 changed= ui_textedit_delete(but, data, 1, 0);
1315                                 retval= WM_UI_HANDLER_BREAK;
1316                                 break;
1317
1318                         case BACKSPACEKEY:
1319                                 changed= ui_textedit_delete(but, data, 0, event->shift);
1320                                 retval= WM_UI_HANDLER_BREAK;
1321                                 break;
1322                                 
1323                         case TABKEY:
1324                                 /* there is a key conflict here, we can't tab with autocomplete */
1325                                 if(but->autocomplete_func) {
1326                                         changed= ui_textedit_autocomplete(C, but, data);
1327                                         retval= WM_UI_HANDLER_BREAK;
1328                                 }
1329                                 /* the hotkey here is not well defined, was G.qual so we check all */
1330                                 else if(event->shift || event->ctrl || event->alt || event->oskey) {
1331                                         ui_textedit_prev_but(block, but, data);
1332                                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1333                                 }
1334                                 else {
1335                                         ui_textedit_next_but(block, but, data);
1336                                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1337                                 }
1338                                 retval= WM_UI_HANDLER_BREAK;
1339                                 break;
1340                 }
1341
1342                 if(event->ascii && (retval == WM_UI_HANDLER_CONTINUE)) {
1343                         changed= ui_textedit_type_ascii(but, data, event->ascii);
1344                         retval= WM_UI_HANDLER_BREAK;
1345                 }
1346         }
1347
1348         if(changed) {
1349                 if(data->interactive) ui_apply_button(C, block, but, data, 1);
1350                 else ui_check_but(but);
1351         }
1352
1353         if(changed || (retval == WM_UI_HANDLER_BREAK))
1354                 ED_region_tag_redraw(data->region);
1355 }
1356
1357 static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1358 {
1359         int mx, my, retval= WM_UI_HANDLER_CONTINUE;
1360
1361         switch(event->type) {
1362                 case MOUSEMOVE: {
1363                         mx= event->x;
1364                         my= event->y;
1365                         ui_window_to_block(data->region, block, &mx, &my);
1366
1367                         ui_textedit_set_cursor_select(but, data, mx);
1368                         retval= WM_UI_HANDLER_BREAK;
1369                         break;
1370                 }
1371                 case LEFTMOUSE:
1372                         if(event->val == 0)
1373                                 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
1374                         retval= WM_UI_HANDLER_BREAK;
1375                         break;
1376         }
1377
1378         if(retval == WM_UI_HANDLER_BREAK) {
1379                 ui_check_but(but);
1380                 ED_region_tag_redraw(data->region);
1381         }
1382 }
1383
1384 /* ************* number editing for various types ************* */
1385
1386 static void but_clamped_range(uiBut *but, float *butmin, float *butmax, float *butrange)
1387 {
1388         /* clamp button range to something reasonable in case
1389          * we get -inf/inf from RNA properties */
1390         *butmin= MAX2(but->min, -1e4f);
1391         *butmax= MIN2(but->max, 1e4f);
1392         *butrange= *butmax - *butmin;
1393 }
1394
1395 static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
1396 {
1397         float butrange, butmin, butmax;
1398
1399         if(but->type == BUT_CURVE) {
1400                 data->cumap= (CurveMapping*)but->poin;
1401                 but->editcumap= data->coba;
1402         }
1403         else if(but->type == BUT_COLORBAND) {
1404                 data->coba= (ColorBand*)but->poin;
1405                 but->editcoba= data->coba;
1406         }
1407         else if(ELEM(but->type, BUT_NORMAL, HSVCUBE)) {
1408                 ui_get_but_vectorf(but, data->origvec);
1409                 VECCOPY(data->vec, data->origvec);
1410                 but->editvec= data->vec;
1411         }
1412         else {
1413                 data->origvalue= ui_get_but_val(but);
1414                 data->value= data->origvalue;
1415                 but->editval= &data->value;
1416
1417                 but_clamped_range(but, &butmin, &butmax, &butrange);
1418
1419                 data->dragfstart= (butrange == 0.0)? 0.0f: (data->value - butmin)/butrange;
1420                 data->dragf= data->dragfstart;
1421         }
1422
1423         data->dragchange= 0;
1424         data->draglock= 1;
1425 }
1426
1427 static void ui_numedit_end(uiBut *but, uiHandleButtonData *data)
1428 {
1429         but->editval= NULL;
1430         but->editvec= NULL;
1431         but->editcoba= NULL;
1432         but->editcumap= NULL;
1433
1434         data->dragstartx= 0;
1435         data->draglastx= 0;
1436         data->dragchange= 0;
1437         data->dragcbd= NULL;
1438         data->dragsel= 0;
1439 }
1440
1441 static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
1442 {
1443         if(data->interactive) ui_apply_button(C, block, but, data, 1);
1444         else ui_check_but(but);
1445
1446         ED_region_tag_redraw(data->region);
1447 }
1448
1449 /* ****************** menu opening for various types **************** */
1450
1451 static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
1452 {
1453         uiBlockCreateFunc func= NULL;
1454         uiBlockHandleCreateFunc handlefunc= NULL;
1455         uiMenuCreateFunc menufunc= NULL;
1456         void *arg= NULL;
1457
1458         switch(but->type) {
1459                 case BLOCK:
1460                 case PULLDOWN:
1461                         func= but->block_create_func;
1462                         arg= but->poin;
1463                         break;
1464                 case HMENU:
1465                         menufunc= but->menu_create_func;
1466                         arg= but->poin;
1467                         break;
1468                 case MENU:
1469                         data->origvalue= ui_get_but_val(but);
1470                         data->value= data->origvalue;
1471                         but->editval= &data->value;
1472
1473                         handlefunc= ui_block_func_MENU;
1474                         arg= but;
1475                         break;
1476                 case ICONROW:
1477                         handlefunc= ui_block_func_ICONROW;
1478                         arg= but;
1479                         break;
1480                 case ICONTEXTROW:
1481                         handlefunc= ui_block_func_ICONTEXTROW;
1482                         arg= but;
1483                         break;
1484                 case COL:
1485                         ui_get_but_vectorf(but, data->origvec);
1486                         VECCOPY(data->vec, data->origvec);
1487                         but->editvec= data->vec;
1488
1489                         handlefunc= ui_block_func_COL;
1490                         arg= but;
1491                         break;
1492         }
1493
1494         if(func || handlefunc) {
1495                 data->menu= ui_popup_block_create(C, data->region, but, func, handlefunc, arg);
1496                 if(but->block->handle)
1497                         data->menu->popup= but->block->handle->popup;
1498         }
1499         else if(menufunc) {
1500                 data->menu= ui_popup_menu_create(C, data->region, but, menufunc, arg);
1501                 if(but->block->handle)
1502                         data->menu->popup= but->block->handle->popup;
1503         }
1504
1505         /* this makes adjacent blocks auto open from now on */
1506         //if(but->block->auto_open==0) but->block->auto_open= 1;
1507 }
1508
1509 static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data)
1510 {
1511         if(but) {
1512                 but->editval= NULL;
1513                 but->editvec= NULL;
1514
1515                 but->block->auto_open_last= PIL_check_seconds_timer();
1516         }
1517
1518         if(data->menu) {
1519                 ui_popup_block_free(C, data->menu);
1520                 data->menu= NULL;
1521         }
1522 }
1523
1524 /* ***************** events for different button types *************** */
1525
1526 static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1527 {
1528         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1529                 if(event->type == LEFTMOUSE && event->val==KM_PRESS) {
1530                         button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE);
1531                         return WM_UI_HANDLER_BREAK;
1532                 }
1533                 else if(event->type == LEFTMOUSE && but->block->handle) {
1534                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1535                         return WM_UI_HANDLER_BREAK;
1536                 }
1537                 else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS) {
1538                         button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH);
1539                         return WM_UI_HANDLER_BREAK;
1540                 }
1541         }
1542         else if(data->state == BUTTON_STATE_WAIT_RELEASE) {
1543                 if(event->type == LEFTMOUSE && event->val!=KM_PRESS) {
1544                         if(!(but->flag & UI_SELECT))
1545                                 data->cancel= 1;
1546                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1547                         return WM_UI_HANDLER_BREAK;
1548                 }
1549         }
1550
1551         return WM_UI_HANDLER_CONTINUE;
1552 }
1553
1554 static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1555 {
1556         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1557                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
1558                         button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
1559                         return WM_UI_HANDLER_BREAK;
1560                 }
1561         }
1562         else if(data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
1563                 if(event->type == MOUSEMOVE)
1564                         return WM_UI_HANDLER_CONTINUE;
1565
1566                 if(event->val==KM_PRESS) {
1567                         if(WM_key_event_string(event->type)[0])
1568                                 ui_set_but_val(but, event->type);
1569                         else
1570                                 data->cancel= 1;
1571
1572                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1573                 }
1574         }
1575
1576         return WM_UI_HANDLER_CONTINUE;
1577 }
1578
1579 static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1580 {
1581         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1582                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
1583                         button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
1584                         return WM_UI_HANDLER_BREAK;
1585                 }
1586         }
1587         else if(data->state == BUTTON_STATE_TEXT_EDITING) {
1588                 ui_do_but_textedit(C, block, but, data, event);
1589                 return WM_UI_HANDLER_BREAK;
1590         }
1591         else if(data->state == BUTTON_STATE_TEXT_SELECTING) {
1592                 ui_do_but_textedit_select(C, block, but, data, event);
1593                 return WM_UI_HANDLER_BREAK;
1594         }
1595
1596         return WM_UI_HANDLER_CONTINUE;
1597 }
1598
1599 static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1600 {
1601         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1602                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
1603                         data->togdual= event->ctrl;
1604                         data->togonly= !event->shift;
1605                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1606                         return WM_UI_HANDLER_BREAK;
1607                 }
1608         }
1609         return WM_UI_HANDLER_CONTINUE;
1610 }
1611
1612 static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1613 {
1614         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1615                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
1616                         button_activate_state(C, but, BUTTON_STATE_EXIT);
1617                         return WM_UI_HANDLER_BREAK;
1618                 }
1619         }
1620
1621         return WM_UI_HANDLER_CONTINUE;
1622 }
1623
1624 static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, int snap, int mx)
1625 {
1626         float deler, tempf, butmin, butmax, butrange;
1627         int lvalue, temp, changed= 0;
1628         
1629         if(mx == data->draglastx)
1630                 return changed;
1631         
1632         /* drag-lock - prevent unwanted scroll adjustments */
1633         /* change value (now 3) to adjust threshold in pixels */
1634         if(data->draglock) {
1635                 if(abs(mx-data->dragstartx) <= 3)
1636                         return changed;
1637
1638                 data->draglock= 0;
1639                 data->dragstartx= mx;  /* ignore mouse movement within drag-lock */
1640         }
1641
1642         but_clamped_range(but, &butmin, &butmax, &butrange);
1643
1644         deler= 500;
1645         if(!ui_is_but_float(but)) {
1646                 if((butrange)<100) deler= 200.0;
1647                 if((butrange)<25) deler= 50.0;
1648         }
1649         deler /= fac;
1650
1651         if(ui_is_but_float(but) && butrange > 11) {
1652                 /* non linear change in mouse input- good for high precicsion */
1653                 data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.002);
1654         } else if (!ui_is_but_float(but) && butrange > 129) { /* only scale large int buttons */
1655                 /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */
1656                 data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.004);
1657         } else {
1658                 /*no scaling */
1659                 data->dragf+= ((float)(mx-data->draglastx))/deler ;
1660         }
1661
1662         if(data->dragf>1.0) data->dragf= 1.0;
1663         if(data->dragf<0.0) data->dragf= 0.0;
1664         data->draglastx= mx;
1665         tempf= (butmin + data->dragf*butrange);
1666         
1667         if(!ui_is_but_float(but)) {
1668                 
1669                 temp= floor(tempf+.5);
1670                 
1671                 if(tempf==but->min || tempf==but->max);
1672                 else if(snap) {
1673                         if(snap == 2) temp= 100*(temp/100);
1674                         else temp= 10*(temp/10);
1675                 }
1676                 if( temp>=but->min && temp<=but->max) {
1677                         lvalue= (int)data->value;
1678                         
1679                         if(temp != lvalue ) {
1680                                 data->dragchange= 1;
1681                                 data->value= (double)temp;
1682                                 changed= 1;
1683                         }
1684                 }
1685
1686         }
1687         else {
1688                 temp= 0;
1689                 if(snap) {
1690                         if(snap == 2) {
1691                                 if(tempf==but->min || tempf==but->max);
1692                                 else if(butrange < 2.10) tempf= 0.01*floor(100.0*tempf);
1693                                 else if(butrange < 21.0) tempf= 0.1*floor(10.0*tempf);
1694                                 else tempf= floor(tempf);
1695                         }
1696                         else {
1697                                 if(tempf==but->min || tempf==but->max);
1698                                 else if(butrange < 2.10) tempf= 0.1*floor(10*tempf);
1699                                 else if(butrange < 21.0) tempf= floor(tempf);
1700                                 else tempf= 10.0*floor(tempf/10.0);
1701                         }
1702                 }
1703
1704                 if( tempf>=but->min && tempf<=but->max) {
1705                         if(tempf != data->value) {
1706                                 data->dragchange= 1;
1707                                 data->value= tempf;
1708                                 changed= 1;
1709                         }
1710                 }
1711         }
1712
1713         return changed;
1714 }
1715
1716 static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1717 {
1718         int mx, my, click= 0;
1719         int retval= WM_UI_HANDLER_CONTINUE;
1720         
1721         mx= event->x;
1722         my= event->y;
1723         ui_window_to_block(data->region, block, &mx, &my);
1724
1725         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1726                 if(event->val==KM_PRESS) {
1727                         if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->shift) {
1728                                 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
1729                                 retval= WM_UI_HANDLER_BREAK;
1730                         }
1731                         else if(event->type == LEFTMOUSE) {
1732                                 data->dragstartx= mx;
1733                                 data->draglastx= mx;
1734                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1735                                 retval= WM_UI_HANDLER_BREAK;
1736                         }
1737                         else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS)
1738                                 click= 1;
1739                 }
1740         }
1741         else if(data->state == BUTTON_STATE_NUM_EDITING) {
1742                 if(event->type == LEFTMOUSE && event->val!=KM_PRESS) {
1743                         if(data->dragchange)
1744                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1745                         else
1746                                 click= 1;
1747                 }
1748                 else if(event->type == MOUSEMOVE) {
1749                         float fac;
1750                         int snap;
1751
1752                         fac= 1.0f;
1753                         if(event->shift) fac /= 10.0f;
1754                         if(event->alt) fac /= 20.0f;
1755
1756                         if(event->custom == EVT_DATA_TABLET) {
1757                                 wmTabletData *wmtab= event->customdata;
1758
1759                                 /* de-sensitise based on tablet pressure */
1760                                 if (ELEM(wmtab->Active, DEV_STYLUS, DEV_ERASER))
1761                                         fac *= wmtab->Pressure;
1762                         }
1763                         
1764                         snap= (event->ctrl)? (event->shift)? 2: 1: 0;
1765
1766                         if(ui_numedit_but_NUM(but, data, fac, snap, mx))
1767                                 ui_numedit_apply(C, block, but, data);
1768                 }
1769                 retval= WM_UI_HANDLER_BREAK;
1770         }
1771         else if(data->state == BUTTON_STATE_TEXT_EDITING) {
1772                 ui_do_but_textedit(C, block, but, data, event);
1773                 retval= WM_UI_HANDLER_BREAK;
1774         }
1775         else if(data->state == BUTTON_STATE_TEXT_SELECTING) {
1776                 ui_do_but_textedit_select(C, block, but, data, event);
1777                 retval= WM_UI_HANDLER_BREAK;
1778         }
1779         
1780         if(click) {
1781                 /* we can click on the side arrows to increment/decrement,
1782                  * or click inside to edit the value directly */
1783                 float tempf;
1784                 int temp;
1785
1786                 if(!ui_is_but_float(but)) {
1787                         if(mx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
1788                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1789
1790                                 temp= (int)data->value - 1;
1791                                 if(temp>=but->min && temp<=but->max)
1792                                         data->value= (double)temp;
1793                                 else
1794                                         data->cancel= 1;
1795
1796                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1797                         }
1798                         else if(mx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
1799                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1800
1801                                 temp= (int)data->value + 1;
1802                                 if(temp>=but->min && temp<=but->max)
1803                                         data->value= (double)temp;
1804                                 else
1805                                         data->cancel= 1;
1806
1807                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1808                         }
1809                         else
1810                                 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
1811                 }
1812                 else {
1813                         if(mx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
1814                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1815
1816                                 tempf= data->value - 0.01*but->a1;
1817                                 if (tempf < but->min) tempf = but->min;
1818                                 data->value= tempf;
1819
1820                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1821                         }
1822                         else if(mx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
1823                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1824
1825                                 tempf= data->value + 0.01*but->a1;
1826                                 if (tempf < but->min) tempf = but->min;
1827                                 data->value= tempf;
1828
1829                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1830                         }
1831                         else
1832                                 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
1833                 }
1834
1835                 retval= WM_UI_HANDLER_BREAK;
1836         }
1837         
1838         return retval;
1839 }
1840
1841 static int ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data, int shift, int ctrl, int mx)
1842 {
1843         float deler, f, tempf, butmin, butmax, butrange;
1844         int temp, lvalue, changed= 0;
1845
1846         but_clamped_range(but, &butmin, &butmax, &butrange);
1847
1848         if(but->type==NUMSLI) deler= ((but->x2-but->x1)/2 - 5.0*but->aspect);
1849         else if(but->type==HSVSLI) deler= ((but->x2-but->x1)/2 - 5.0*but->aspect);
1850         else deler= (but->x2-but->x1- 5.0*but->aspect);
1851
1852         f= (float)(mx-data->dragstartx)/deler + data->dragfstart;
1853         
1854         if(shift)
1855                 f= (f-data->dragfstart)/10.0 + data->dragfstart;
1856
1857         CLAMP(f, 0.0, 1.0);
1858         tempf= butmin + f*butrange;
1859         temp= floor(tempf+.5);
1860
1861         if(ctrl) {
1862                 if(tempf==but->min || tempf==but->max);
1863                 else if(ui_is_but_float(but)) {
1864
1865                         if(shift) {
1866                                 if(tempf==but->min || tempf==but->max);
1867                                 else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
1868                                 else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
1869                                 else tempf= floor(tempf);
1870                         }
1871                         else {
1872                                 if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
1873                                 else if(but->max-but->min < 21.0) tempf= floor(tempf);
1874                                 else tempf= 10.0*floor(tempf/10.0);
1875                         }
1876                 }
1877                 else {
1878                         temp= 10*(temp/10);
1879                         tempf= temp;
1880                 }
1881         }
1882
1883         if(!ui_is_but_float(but)) {
1884                 lvalue= floor(data->value+0.5);
1885
1886                 if(temp != lvalue) {
1887                         data->value= temp;
1888                         data->dragchange= 1;
1889                         changed= 1;
1890                 }
1891         }
1892         else {
1893                 if(tempf != data->value) {
1894                         data->value= tempf;
1895                         data->dragchange= 1;
1896                         changed= 1;
1897                 }
1898         }
1899
1900         return changed;
1901 }
1902
1903 static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1904 {
1905         int mx, my, click= 0;
1906         int retval= WM_UI_HANDLER_CONTINUE;
1907
1908         mx= event->x;
1909         my= event->y;
1910         ui_window_to_block(data->region, block, &mx, &my);
1911
1912         if(data->state == BUTTON_STATE_HIGHLIGHT) {
1913                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
1914                         /* start either dragging as slider, or editing as text */
1915                         if(mx>= -6+(but->x1+but->x2)/2) {
1916                                 if(event->type == LEFTMOUSE) {
1917                                         data->dragstartx= mx;
1918                                         data->draglastx= mx;
1919                                         button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1920                                 }
1921                                 else
1922                                         click= 1;
1923                         }
1924                         else
1925                                 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
1926                         
1927                         retval= WM_UI_HANDLER_BREAK;
1928                 }
1929         }
1930         else if(data->state == BUTTON_STATE_NUM_EDITING) {
1931                 if(event->type == LEFTMOUSE && event->val!=KM_PRESS) {
1932                         if(data->dragchange)
1933                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1934                         else
1935                                 click= 1;
1936                 }
1937                 else if(event->type == MOUSEMOVE) {
1938                         if(ui_numedit_but_SLI(but, data, event->shift, event->ctrl, mx))
1939                                 ui_numedit_apply(C, block, but, data);
1940                 }
1941                 retval= WM_UI_HANDLER_BREAK;
1942         }
1943         else if(data->state == BUTTON_STATE_TEXT_EDITING) {
1944                 ui_do_but_textedit(C, block, but, data, event);
1945                 retval= WM_UI_HANDLER_BREAK;
1946         }
1947         else if(data->state == BUTTON_STATE_TEXT_SELECTING) {
1948                 ui_do_but_textedit_select(C, block, but, data, event);
1949                 retval= WM_UI_HANDLER_BREAK;
1950         }
1951
1952         if(click) {
1953                 float f, h;
1954                 float tempf, butmin, butmax, butrange;
1955                 int temp;
1956                 
1957                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
1958
1959                 but_clamped_range(but, &butmin, &butmax, &butrange);
1960
1961                 tempf= data->value;
1962                 temp= (int)data->value;
1963
1964                 h= but->y2-but->y1;
1965
1966                 if(but->type==SLI) f= (float)(mx-but->x1)/(but->x2-but->x1-h);
1967                 else f= (float)(mx- (but->x1+but->x2)/2)/((but->x2-but->x1)/2 - h);
1968                 
1969                 f= butmin + f*butrange;
1970
1971                 if(!ui_is_but_float(but)) {
1972                         if(f<temp) temp--;
1973                         else temp++;
1974
1975                         if(temp>=but->min && temp<=but->max)
1976                                 data->value= temp;
1977                         else
1978                                 data->cancel= 1;
1979                 } 
1980                 else {
1981                         if(f<tempf) tempf-=.01;
1982                         else tempf+=.01;
1983
1984                         if(tempf>=but->min && tempf<=but->max)
1985                                 data->value= tempf;
1986                         else
1987                                 data->cancel= 1;
1988                 }
1989
1990                 button_activate_state(C, but, BUTTON_STATE_EXIT);
1991                 retval= WM_UI_HANDLER_BREAK;
1992         }
1993         
1994         return retval;
1995 }
1996
1997 static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
1998 {
1999         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2000                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
2001                         button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
2002                         return WM_UI_HANDLER_BREAK;
2003                 }
2004         }
2005
2006         return WM_UI_HANDLER_CONTINUE;
2007 }
2008
2009 static int ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data, int mx, int my)
2010 {
2011         float dx, dy, rad, radsq, mrad, *fp;
2012         int mdx, mdy, changed= 1;
2013         
2014         /* button is presumed square */
2015         /* if mouse moves outside of sphere, it does negative normal */
2016
2017         fp= data->origvec;
2018         rad= (but->x2 - but->x1);
2019         radsq= rad*rad;
2020         
2021         if(fp[2]>0.0f) {
2022                 mdx= (rad*fp[0]);
2023                 mdy= (rad*fp[1]);
2024         }
2025         else if(fp[2]> -1.0f) {
2026                 mrad= rad/sqrt(fp[0]*fp[0] + fp[1]*fp[1]);
2027                 
2028                 mdx= 2.0f*mrad*fp[0] - (rad*fp[0]);
2029                 mdy= 2.0f*mrad*fp[1] - (rad*fp[1]);
2030         }
2031         else mdx= mdy= 0;
2032         
2033         dx= (float)(mx+mdx-data->dragstartx);
2034         dy= (float)(my+mdy-data->dragstarty);
2035
2036         fp= data->vec;
2037         mrad= dx*dx+dy*dy;
2038         if(mrad < radsq) {      /* inner circle */
2039                 fp[0]= dx;
2040                 fp[1]= dy;
2041                 fp[2]= sqrt( radsq-dx*dx-dy*dy );
2042         }
2043         else {  /* outer circle */
2044                 
2045                 mrad= rad/sqrt(mrad);   // veclen
2046                 
2047                 dx*= (2.0f*mrad - 1.0f);
2048                 dy*= (2.0f*mrad - 1.0f);
2049                 
2050                 mrad= dx*dx+dy*dy;
2051                 if(mrad < radsq) {
2052                         fp[0]= dx;
2053                         fp[1]= dy;
2054                         fp[2]= -sqrt( radsq-dx*dx-dy*dy );
2055                 }
2056         }
2057         Normalize(fp);
2058
2059         data->draglastx= mx;
2060         data->draglasty= my;
2061
2062         return changed;
2063 }
2064
2065 static int ui_do_but_NORMAL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
2066 {
2067         int mx, my;
2068
2069         mx= event->x;
2070         my= event->y;
2071         ui_window_to_block(data->region, block, &mx, &my);
2072
2073         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2074                 if(event->type==LEFTMOUSE && event->val==KM_PRESS) {
2075                         data->dragstartx= mx;
2076                         data->dragstarty= my;
2077                         data->draglastx= mx;
2078                         data->draglasty= my;
2079                         button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
2080
2081                         /* also do drag the first time */
2082                         if(ui_numedit_but_NORMAL(but, data, mx, my))
2083                                 ui_numedit_apply(C, block, but, data);
2084                         
2085                         return WM_UI_HANDLER_BREAK;
2086                 }
2087         }
2088         else if(data->state == BUTTON_STATE_NUM_EDITING) {
2089                 if(event->type == MOUSEMOVE) {
2090                         if(mx!=data->draglastx || my!=data->draglasty) {
2091                                 if(ui_numedit_but_NORMAL(but, data, mx, my))
2092                                         ui_numedit_apply(C, block, but, data);
2093                         }
2094                 }
2095                 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS)
2096                         button_activate_state(C, but, BUTTON_STATE_EXIT);
2097
2098                 return WM_UI_HANDLER_BREAK;
2099         }
2100         
2101         return WM_UI_HANDLER_CONTINUE;
2102 }
2103
2104 static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx, int my)
2105 {
2106         float x, y;
2107         int changed= 1;
2108
2109         /* relative position within box */
2110         x= ((float)mx-but->x1)/(but->x2-but->x1);
2111         y= ((float)my-but->y1)/(but->y2-but->y1);
2112         CLAMP(x, 0.0, 1.0);
2113         CLAMP(y, 0.0, 1.0);
2114         
2115         if(but->a1==0) {
2116                 but->hsv[0]= x; 
2117                 but->hsv[2]= y; 
2118         }
2119         else if(but->a1==1) {
2120                 but->hsv[0]= x;                                 
2121                 but->hsv[1]= y;                                 
2122         }
2123         else if(but->a1==2) {
2124                 but->hsv[2]= x; 
2125                 but->hsv[1]= y; 
2126         }
2127         else
2128                 but->hsv[0]= x; 
2129
2130         ui_set_but_hsv(but);    // converts to rgb
2131         
2132         // update button values and strings
2133         ui_update_block_buts_hsv(but->block, but->hsv);
2134
2135         data->draglastx= mx;
2136         data->draglasty= my;
2137
2138         return changed;
2139 }
2140
2141 static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
2142 {
2143         int mx, my;
2144
2145         mx= event->x;
2146         my= event->y;
2147         ui_window_to_block(data->region, block, &mx, &my);
2148
2149         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2150                 if(event->type==LEFTMOUSE && event->val==KM_PRESS) {
2151                         data->dragstartx= mx;
2152                         data->dragstarty= my;
2153                         data->draglastx= mx;
2154                         data->draglasty= my;
2155                         button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
2156
2157                         /* also do drag the first time */
2158                         if(ui_numedit_but_HSVCUBE(but, data, mx, my))
2159                                 ui_numedit_apply(C, block, but, data);
2160                         
2161                         return WM_UI_HANDLER_BREAK;
2162                 }
2163         }
2164         else if(data->state == BUTTON_STATE_NUM_EDITING) {
2165                 if(event->type == MOUSEMOVE) {
2166                         if(mx!=data->draglastx || my!=data->draglasty) {
2167                                 if(ui_numedit_but_HSVCUBE(but, data, mx, my))
2168                                         ui_numedit_apply(C, block, but, data);
2169                         }
2170                 }
2171                 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS)
2172                         button_activate_state(C, but, BUTTON_STATE_EXIT);
2173                 
2174                 return WM_UI_HANDLER_BREAK;
2175         }
2176
2177         return WM_UI_HANDLER_CONTINUE;
2178 }
2179
2180 static int verg_colorband(const void *a1, const void *a2)
2181 {
2182         const CBData *x1=a1, *x2=a2;
2183         
2184         if( x1->pos > x2->pos ) return 1;
2185         else if( x1->pos < x2->pos) return -1;
2186         return WM_UI_HANDLER_CONTINUE;
2187 }
2188
2189 static void ui_colorband_update(ColorBand *coba)
2190 {
2191         int a;
2192         
2193         if(coba->tot<2) return;
2194         
2195         for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
2196                 qsort(coba->data, coba->tot, sizeof(CBData), verg_colorband);
2197         for(a=0; a<coba->tot; a++) {
2198                 if(coba->data[a].cur==coba->cur) {
2199                         coba->cur= a;
2200                         break;
2201                 }
2202         }
2203 }
2204
2205 static int ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int mx)
2206 {
2207         float dx;
2208         int changed= 0;
2209
2210         if(data->draglastx == mx)
2211                 return changed;
2212
2213         dx= ((float)(mx - data->draglastx))/(but->x2-but->x1);
2214         data->dragcbd->pos += dx;
2215         CLAMP(data->dragcbd->pos, 0.0, 1.0);
2216         
2217         ui_colorband_update(data->coba);
2218         data->dragcbd= data->coba->data + data->coba->cur;      /* because qsort */
2219         
2220         data->draglastx= mx;
2221         changed= 1;
2222
2223         return changed;
2224 }
2225
2226 static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
2227 {
2228         ColorBand *coba;
2229         CBData *cbd;
2230         int mx, my, a, xco, mindist= 12;
2231
2232         mx= event->x;
2233         my= event->y;
2234         ui_window_to_block(data->region, block, &mx, &my);
2235
2236         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2237                 if(event->type==LEFTMOUSE && event->val==KM_PRESS) {
2238                         coba= (ColorBand*)but->poin;
2239
2240                         if(event->ctrl) {
2241                                 /* insert new key on mouse location */
2242                                 if(coba->tot < MAXCOLORBAND-1) {
2243                                         float pos= ((float)(mx - but->x1))/(but->x2-but->x1);
2244                                         float col[4];
2245                                         
2246                                         do_colorband(coba, pos, col);   /* executes it */
2247                                         
2248                                         coba->tot++;
2249                                         coba->cur= coba->tot-1;
2250                                         
2251                                         coba->data[coba->cur].r= col[0];
2252                                         coba->data[coba->cur].g= col[1];
2253                                         coba->data[coba->cur].b= col[2];
2254                                         coba->data[coba->cur].a= col[3];
2255                                         coba->data[coba->cur].pos= pos;
2256
2257                                         ui_colorband_update(coba);
2258                                 }
2259
2260                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
2261                         }
2262                         else {
2263                                 data->dragstartx= mx;
2264                                 data->dragstarty= my;
2265                                 data->draglastx= mx;
2266                                 data->draglasty= my;
2267
2268                                 /* activate new key when mouse is close */
2269                                 for(a=0, cbd= coba->data; a<coba->tot; a++, cbd++) {
2270                                         xco= but->x1 + (cbd->pos*(but->x2-but->x1));
2271                                         xco= ABS(xco-mx);
2272                                         if(a==coba->cur) xco+= 5; // selected one disadvantage
2273                                         if(xco<mindist) {
2274                                                 coba->cur= a;
2275                                                 mindist= xco;
2276                                         }
2277                                 }
2278                 
2279                                 data->dragcbd= coba->data + coba->cur;
2280                                 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
2281                         }
2282
2283                         return WM_UI_HANDLER_BREAK;
2284                 }
2285         }
2286         else if(data->state == BUTTON_STATE_NUM_EDITING) {
2287                 if(event->type == MOUSEMOVE) {
2288                         if(mx!=data->draglastx || my!=data->draglasty) {
2289                                 if(ui_numedit_but_COLORBAND(but, data, mx))
2290                                         ui_numedit_apply(C, block, but, data);
2291                         }
2292                 }
2293                 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS)
2294                         button_activate_state(C, but, BUTTON_STATE_EXIT);
2295                 
2296                 return WM_UI_HANDLER_BREAK;
2297         }
2298
2299         return WM_UI_HANDLER_CONTINUE;
2300 }
2301
2302 static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap, int mx, int my)
2303 {
2304         CurveMapping *cumap= data->cumap;
2305         CurveMap *cuma= cumap->cm+cumap->cur;
2306         CurveMapPoint *cmp= cuma->curve;
2307         float fx, fy, zoomx, zoomy, offsx, offsy;
2308         int a, changed= 0;
2309
2310         zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin);
2311         zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin);
2312         offsx= cumap->curr.xmin;
2313         offsy= cumap->curr.ymin;
2314
2315         if(data->dragsel != -1) {
2316                 int moved_point= 0;             /* for ctrl grid, can't use orig coords because of sorting */
2317                 
2318                 fx= (mx-data->draglastx)/zoomx;
2319                 fy= (my-data->draglasty)/zoomy;
2320                 for(a=0; a<cuma->totpoint; a++) {
2321                         if(cmp[a].flag & SELECT) {
2322                                 float origx= cmp[a].x, origy= cmp[a].y;
2323                                 cmp[a].x+= fx;
2324                                 cmp[a].y+= fy;
2325                                 if(snap) {
2326                                         cmp[a].x= 0.125f*floor(0.5f + 8.0f*cmp[a].x);
2327                                         cmp[a].y= 0.125f*floor(0.5f + 8.0f*cmp[a].y);
2328                                 }
2329                                 if(cmp[a].x!=origx || cmp[a].y!=origy)
2330                                         moved_point= 1;
2331                         }
2332                 }
2333
2334                 curvemapping_changed(cumap, 0); /* no remove doubles */
2335                 
2336                 if(moved_point) {
2337                         data->draglastx= mx;
2338                         data->draglasty= my;
2339                         changed= 1;
2340                 }
2341
2342                 data->dragchange= 1; /* mark for selection */
2343         }
2344         else {
2345                 fx= (mx-data->draglastx)/zoomx;
2346                 fy= (my-data->draglasty)/zoomy;
2347                 
2348                 /* clamp for clip */
2349                 if(cumap->flag & CUMA_DO_CLIP) {
2350                         if(cumap->curr.xmin-fx < cumap->clipr.xmin)
2351                                 fx= cumap->curr.xmin - cumap->clipr.xmin;
2352                         else if(cumap->curr.xmax-fx > cumap->clipr.xmax)
2353                                 fx= cumap->curr.xmax - cumap->clipr.xmax;
2354                         if(cumap->curr.ymin-fy < cumap->clipr.ymin)
2355                                 fy= cumap->curr.ymin - cumap->clipr.ymin;
2356                         else if(cumap->curr.ymax-fy > cumap->clipr.ymax)
2357                                 fy= cumap->curr.ymax - cumap->clipr.ymax;
2358                 }                               
2359
2360                 cumap->curr.xmin-=fx;
2361                 cumap->curr.ymin-=fy;
2362                 cumap->curr.xmax-=fx;
2363                 cumap->curr.ymax-=fy;
2364                 
2365                 data->draglastx= mx;
2366                 data->draglasty= my;
2367
2368                 changed= 1;
2369         }
2370
2371         return changed;
2372 }
2373
2374 static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
2375 {
2376         int mx, my, a, changed= 0;
2377
2378         mx= event->x;
2379         my= event->y;
2380         ui_window_to_block(data->region, block, &mx, &my);
2381
2382         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2383                 if(event->type==LEFTMOUSE && event->val==KM_PRESS) {
2384                         CurveMapping *cumap= (CurveMapping*)but->poin;
2385                         CurveMap *cuma= cumap->cm+cumap->cur;
2386                         CurveMapPoint *cmp= cuma->curve;
2387                         float fx, fy, zoomx, zoomy, offsx, offsy;
2388                         float dist, mindist= 200.0f; // 14 pixels radius
2389                         int sel= -1;
2390
2391                         zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin);
2392                         zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin);
2393                         offsx= cumap->curr.xmin;
2394                         offsy= cumap->curr.ymin;
2395
2396                         if(event->ctrl) {
2397                                 fx= ((float)my - but->x1)/zoomx + offsx;
2398                                 fy= ((float)my - but->y1)/zoomy + offsy;
2399                                 
2400                                 curvemap_insert(cuma, fx, fy);
2401                                 curvemapping_changed(cumap, 0);
2402                                 changed= 1;
2403                         }
2404
2405                         /* check for selecting of a point */
2406                         cmp= cuma->curve;       /* ctrl adds point, new malloc */
2407                         for(a=0; a<cuma->totpoint; a++) {
2408                                 fx= but->x1 + zoomx*(cmp[a].x-offsx);
2409                                 fy= but->y1 + zoomy*(cmp[a].y-offsy);
2410                                 dist= (fx-mx)*(fx-mx) + (fy-my)*(fy-my);
2411                                 if(dist < mindist) {
2412                                         sel= a;
2413                                         mindist= dist;
2414                                 }
2415                         }
2416
2417                         if (sel == -1) {
2418                                 /* if the click didn't select anything, check if it's clicked on the 
2419                                  * curve itself, and if so, add a point */
2420                                 fx= ((float)mx - but->x1)/zoomx + offsx;
2421                                 fy= ((float)my - but->y1)/zoomy + offsy;
2422                                 
2423                                 cmp= cuma->table;
2424
2425                                 /* loop through the curve segment table and find what's near the mouse.
2426                                  * 0.05 is kinda arbitrary, but seems to be what works nicely. */
2427                                 for(a=0; a<=CM_TABLE; a++) {                    
2428                                         if ( ( fabs(fx - cmp[a].x) < (0.05) ) && ( fabs(fy - cmp[a].y) < (0.05) ) ) {
2429                                         
2430                                                 curvemap_insert(cuma, fx, fy);
2431                                                 curvemapping_changed(cumap, 0);
2432
2433                                                 changed= 1;
2434                                                 
2435                                                 /* reset cmp back to the curve points again, rather than drawing segments */            
2436                                                 cmp= cuma->curve;
2437                                                 
2438                                                 /* find newly added point and make it 'sel' */
2439                                                 for(a=0; a<cuma->totpoint; a++)
2440                                                         if(cmp[a].x == fx)
2441                                                                 sel = a;
2442                                                         
2443                                                 break;
2444                                         }
2445                                 }
2446                         }
2447
2448                         if(sel!= -1) {
2449                                 /* ok, we move a point */
2450                                 /* deselect all if this one is deselect. except if we hold shift */
2451                                 if(event->shift==0 && (cmp[sel].flag & SELECT)==0)
2452                                         for(a=0; a<cuma->totpoint; a++)
2453                                                 cmp[a].flag &= ~SELECT;
2454                                 cmp[sel].flag |= SELECT;
2455                         }
2456                         else {
2457                                 /* move the view */
2458                                 data->cancel= 1;
2459                         }
2460
2461                         data->dragsel= sel;
2462
2463                         data->dragstartx= mx;
2464                         data->dragstarty= my;
2465                         data->draglastx= mx;
2466                         data->draglasty= my;
2467
2468                         button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
2469                         return WM_UI_HANDLER_BREAK;
2470                 }
2471         }
2472         else if(data->state == BUTTON_STATE_NUM_EDITING) {
2473                 if(event->type == MOUSEMOVE) {
2474                         if(mx!=data->draglastx || my!=data->draglasty) {
2475                                 if(ui_numedit_but_CURVE(but, data, event->shift, mx, my))
2476                                         ui_numedit_apply(C, block, but, data);
2477                         }
2478                 }
2479                 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) {
2480                         if(data->dragsel != -1) {
2481                                 CurveMapping *cumap= data->cumap;
2482                                 CurveMap *cuma= cumap->cm+cumap->cur;
2483                                 CurveMapPoint *cmp= cuma->curve;
2484
2485                                 if(!data->dragchange) {
2486                                         /* deselect all, select one */
2487                                         if(event->shift==0) {
2488                                                 for(a=0; a<cuma->totpoint; a++)
2489                                                         cmp[a].flag &= ~SELECT;
2490                                                 cmp[data->dragsel].flag |= SELECT;
2491                                         }
2492                                 }
2493                                 else
2494                                         curvemapping_changed(cumap, 1); /* remove doubles */
2495                         }
2496
2497                         button_activate_state(C, but, BUTTON_STATE_EXIT);
2498                 }
2499
2500                 return WM_UI_HANDLER_BREAK;
2501         }
2502
2503         return WM_UI_HANDLER_CONTINUE;
2504 }
2505
2506 #ifdef INTERNATIONAL
2507 static int ui_do_but_CHARTAB(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
2508 {
2509         /* XXX 2.50 bad global and state access */
2510 #if 0
2511         float sx, sy, ex, ey;
2512         float width, height;
2513         float butw, buth;
2514         int mx, my, x, y, cs, che;
2515
2516         mx= event->x;
2517         my= event->y;
2518         ui_window_to_block(data->region, block, &mx, &my);
2519
2520         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2521                 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
2522                         /* Calculate the size of the button */
2523                         width = abs(but->x2 - but->x1);
2524                         height = abs(but->y2 - but->y1);
2525
2526                         butw = floor(width / 12);
2527                         buth = floor(height / 6);
2528
2529                         /* Initialize variables */
2530                         sx = but->x1;
2531                         ex = but->x1 + butw;
2532                         sy = but->y1 + height - buth;
2533                         ey = but->y1 + height;
2534
2535                         cs = G.charstart;
2536
2537                         /* And the character is */
2538                         x = (int) ((mx / butw) - 0.5);
2539                         y = (int) (6 - ((my / buth) - 0.5));
2540
2541                         che = cs + (y*12) + x;
2542
2543                         if(che > G.charmax)
2544                                 che = 0;
2545
2546                         if(G.obedit)
2547                         {
2548                                 do_textedit(0,0,che);
2549                         }
2550
2551                         button_activate_state(C, but, BUTTON_STATE_EXIT);
2552                         return WM_UI_HANDLER_BREAK;
2553                 }
2554                 else if(ELEM(event->type, WHEELUPMOUSE, PAGEUPKEY)) {
2555                         for(but= block->buttons.first; but; but= but->next) {
2556                                 if(but->type == CHARTAB) {
2557                                         G.charstart = G.charstart - (12*6);
2558                                         if(G.charstart < 0)
2559                                                 G.charstart = 0;
2560                                         if(G.charstart < G.charmin)
2561                                                 G.charstart = G.charmin;
2562                                         ui_draw_but(but);
2563
2564                                         //Really nasty... to update the num button from the same butblock
2565                                         for(bt= block->buttons.first; bt; bt= bt->next)
2566                                         {
2567                                                 if(ELEM(bt->type, NUM, NUMABS)) {
2568                                                         ui_check_but(bt);
2569                                                         ui_draw_but(bt);
2570                                                 }
2571                                         }
2572                                         retval=UI_CONT;
2573                                         break;
2574                                 }
2575                         }
2576
2577                         return WM_UI_HANDLER_BREAK;
2578                 }
2579                 else if(ELEM(event->type, WHEELDOWNMOUSE, PAGEDOWNKEY)) {
2580                         for(but= block->buttons.first; but; but= but->next)
2581                         {
2582                                 if(but->type == CHARTAB)
2583                                 {
2584                                         G.charstart = G.charstart + (12*6);
2585                                         if(G.charstart > (0xffff - 12*6))
2586                                                 G.charstart = 0xffff - (12*6);
2587                                         if(G.charstart > G.charmax - 12*6)
2588                                                 G.charstart = G.charmax - 12*6;
2589                                         ui_draw_but(but);
2590
2591                                         for(bt= block->buttons.first; bt; bt= bt->next)
2592                                         {
2593                                                 if(ELEM(bt->type, NUM, NUMABS)) {
2594                                                         ui_check_but(bt);
2595                                                         ui_draw_but(bt);
2596                                                 }
2597                                         }
2598                                         
2599                                         but->flag |= UI_ACTIVE;
2600                                         retval=UI_RETURN_OK;
2601                                         break;
2602                                 }
2603                         }
2604
2605                         return WM_UI_HANDLER_BREAK;
2606                 }
2607         }
2608 #endif
2609
2610         return WM_UI_HANDLER_CONTINUE;
2611 }
2612 #endif
2613
2614 static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
2615 {
2616         uiHandleButtonData *data;
2617         int retval;
2618
2619         data= but->active;
2620         retval= WM_UI_HANDLER_CONTINUE;
2621
2622         if(but->flag & UI_BUT_DISABLED)
2623                 return WM_UI_HANDLER_BREAK;
2624
2625         /* handle copy-paste */
2626         if(data->state == BUTTON_STATE_HIGHLIGHT) {
2627                 if(ELEM(event->type, CKEY, VKEY) && event->val==KM_PRESS && (event->ctrl || event->oskey)) {
2628                         ui_but_copy_paste(C, but, data, (event->type == CKEY)? 'c': 'v');
2629                         return WM_UI_HANDLER_BREAK;
2630                 }
2631         }
2632
2633         /* verify if we can edit this button */
2634         if(ELEM(event->type, LEFTMOUSE, RETKEY)) {
2635                 if(but->lock) {
2636                         if(but->lockstr) {
2637                                 BKE_report(CTX_reports(C), RPT_WARNING, but->lockstr);
2638                                 button_activate_state(C, but, BUTTON_STATE_EXIT);
2639                                 return WM_UI_HANDLER_BREAK;
2640                         }
2641                 } 
2642                 else if(but->pointype && but->poin==0) {
2643                         /* there's a pointer needed */
2644                         BKE_reportf(CTX_reports(C), RPT_WARNING, "DoButton pointer error: %s", but->str);
2645                         button_activate_state(C, but, BUTTON_STATE_EXIT);
2646                         return WM_UI_HANDLER_BREAK;
2647                 }
2648         }
2649
2650         switch(but->type) {
2651         case BUT:
2652                 retval= ui_do_but_BUT(C, but, data, event);
2653                 break;
2654         case KEYEVT:
2655                 retval= ui_do_but_KEYEVT(C, but, data, event);
2656                 break;
2657         case TOG: 
2658         case TOGR: 
2659         case ICONTOG:
2660         case ICONTOGN:
2661         case TOGN:
2662         case BUT_TOGDUAL:
2663                 retval= ui_do_but_TOG(C, but, data, event);
2664                 break;
2665 #if 0
2666         case SCROLL:
2667                 /* DrawBut(b, 1); */
2668                 /* do_scrollbut(b); */
2669                 /* DrawBut(b,0); */
2670                 break;
2671 #endif
2672         case NUM:
2673         case NUMABS:
2674                 retval= ui_do_but_NUM(C, block, but, data, event);
2675                 break;
2676         case SLI:
2677         case NUMSLI:
2678         case HSVSLI:
2679                 retval= ui_do_but_SLI(C, block, but, data, event);
2680                 break;
2681         case ROUNDBOX:  
2682         case LABEL:     
2683         case TOG3:      
2684         case ROW:
2685                 retval= ui_do_but_EXIT(C, but, data, event);
2686                 break;
2687         case TEX:
2688         case IDPOIN:
2689                 retval= ui_do_but_TEX(C, block, but, data, event);
2690                 break;
2691         case MENU:
2692                 retval= ui_do_but_BLOCK(C, but, data, event);
2693                 break;
2694         case ICONROW:
2695                 retval= ui_do_but_BLOCK(C, but, data, event);
2696                 break;
2697         case ICONTEXTROW:
2698                 retval= ui_do_but_BLOCK(C, but, data, event);
2699                 break;
2700         case BLOCK:
2701         case PULLDOWN:
2702         case HMENU:
2703                 retval= ui_do_but_BLOCK(C, but, data, event);
2704                 break;
2705         case BUTM:
2706                 retval= ui_do_but_BUT(C, but, data, event);
2707                 break;
2708         case COL:
2709                 if(but->a1 == -1)  // signal to prevent calling up color picker
2710                         retval= ui_do_but_EXIT(C, but, data, event);
2711                 else
2712                         retval= ui_do_but_BLOCK(C, but, data, event);
2713                 break;
2714         case BUT_NORMAL:
2715                 retval= ui_do_but_NORMAL(C, block, but, data, event);
2716                 break;
2717         case BUT_COLORBAND:
2718                 retval= ui_do_but_COLORBAND(C, block, but, data, event);
2719                 break;
2720         case BUT_CURVE:
2721                 retval= ui_do_but_CURVE(C, block, but, data, event);
2722                 break;
2723         case HSVCUBE:
2724                 retval= ui_do_but_HSVCUBE(C, block, but, data, event);
2725                 break;
2726 #ifdef INTERNATIONAL
2727         case CHARTAB:
2728                 retval= ui_do_but_CHARTAB(C, block, but, data, event);
2729                 break;
2730 #endif
2731         /* XXX 2.50 links not implemented yet */
2732 #if 0
2733         case LINK:
2734         case INLINK:
2735                 retval= retval= ui_do_but_LINK(block, but);
2736                 break;
2737 #endif
2738         }
2739         
2740         return retval;
2741 }
2742
2743 /* ************************ button utilities *********************** */
2744
2745 static int ui_but_contains_pt(uiBut *but, int mx, int my)
2746 {
2747         return ((but->x1<mx && but->x2>=mx) && (but->y1<my && but->y2>=my));
2748 }
2749
2750 static uiBut *ui_but_find_activated(ARegion *ar)
2751 {
2752         uiBlock *block;
2753         uiBut *but;
2754
2755         for(block=ar->uiblocks.first; block; block=block->next)
2756                 for(but=block->buttons.first; but; but= but->next)
2757                         if(but->active)
2758                                 return but;
2759
2760         return NULL;
2761 }
2762
2763 static void ui_blocks_set_tooltips(ARegion *ar, int enable)
2764 {
2765         uiBlock *block;
2766
2767         if(!ar)
2768                 return;
2769
2770         /* we disabled buttons when when they were already shown, and
2771          * re-enable them on mouse move */
2772         for(block=ar->uiblocks.first; block; block=block->next)
2773                 block->tooltipdisabled= !enable;
2774 }
2775
2776 static int ui_mouse_inside_region(ARegion *ar, int x, int y)
2777 {
2778         uiBlock *block;
2779         int mx, my;
2780
2781         /* check if the mouse is in the region, and in case of a view2d also check
2782          * if it is inside the view2d itself, not over scrollbars for example */
2783         if(!BLI_in_rcti(&ar->winrct, x, y)) {
2784                 for(block=ar->uiblocks.first; block; block=block->next)
2785                         block->auto_open= 0;
2786
2787                 return 0;
2788         }
2789
2790         if(ar->v2d.mask.xmin!=ar->v2d.mask.xmax) {
2791                 mx= x;
2792                 my= y;
2793                 ui_window_to_region(ar, &mx, &my);
2794
2795                 if(!BLI_in_rcti(&ar->v2d.mask, mx, my))
2796                         return 0;
2797         }
2798
2799         return 1;
2800 }
2801
2802 static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
2803 {
2804         if(!ui_mouse_inside_region(ar, x, y))
2805                 return 0;
2806
2807         ui_window_to_block(ar, but->block, &x, &y);
2808
2809         if(!ui_but_contains_pt(but, x, y))
2810                 return 0;
2811         
2812         return 1;
2813 }
2814
2815 static uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
2816 {
2817         uiBlock *block;
2818         uiBut *but, *butover= NULL;
2819         int mx, my;
2820
2821         if(!ui_mouse_inside_region(ar, x, y))
2822                 return NULL;
2823
2824         for(block=ar->uiblocks.first; block; block=block->next) {
2825                 mx= x;
2826                 my= y;
2827                 ui_window_to_block(ar, block, &mx, &my);
2828
2829                 for(but=block->buttons.first; but; but= but->next) {
2830                         /* give precedence to already activated buttons */
2831                         if(ui_but_contains_pt(but, mx, my))
2832                                 if(!butover || (!butover->active && but->active))
2833                                         butover= but;
2834                 }
2835         }
2836
2837         return butover;
2838 }
2839
2840 /* ****************** button state handling **************************/
2841
2842 static int button_modal_state(uiHandleButtonState state)
2843 {
2844         return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT,
2845                 BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING,
2846                 BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN);
2847 }
2848
2849 static void button_tooltip_timer_reset(uiBut *but)
2850 {
2851         uiHandleButtonData *data;
2852
2853         data= but->active;
2854
2855         if(data->tooltiptimer) {
2856                 WM_event_remove_window_timer(data->window, data->tooltiptimer);
2857                 data->tooltiptimer= NULL;
2858         }
2859
2860         if(U.flag & USER_TOOLTIPS)
2861                 if(!but->block->tooltipdisabled)
2862                         data->tooltiptimer= WM_event_add_window_timer(data->window, TIMER, BUTTON_TOOLTIP_DELAY);
2863 }
2864
2865 static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state)
2866 {
2867         uiHandleButtonData *data;
2868
2869         data= but->active;
2870         if(data->state == state)
2871                 return;
2872
2873         /* highlight has timers for tooltips and auto open */
2874         if(state == BUTTON_STATE_HIGHLIGHT) {
2875                 but->flag &= ~UI_SELECT;
2876
2877                 button_tooltip_timer_reset(but);
2878
2879                 /* automatic open pulldown block timer */
2880                 if(ELEM4(but->type, BLOCK, PULLDOWN, HMENU, ICONTEXTROW)) {
2881                         if(!data->autoopentimer) {
2882                                 int time;
2883
2884                                 if(but->block->auto_open==2) time= 1;    // test for toolbox
2885                                 else if(but->block->flag & UI_BLOCK_LOOP || but->block->auto_open) time= 5*U.menuthreshold2;
2886                                 else if(U.uiflag & USER_MENUOPENAUTO) time= 5*U.menuthreshold1;
2887                                 else time= -1;
2888
2889                                 if(time >= 0)
2890                                         data->autoopentimer= WM_event_add_window_timer(data->window, TIMER, 0.02*(double)time);
2891                         }
2892                 }
2893         }
2894         else {
2895                 but->flag |= UI_SELECT;
2896
2897                 if(data->tooltiptimer) {
2898                         WM_event_remove_window_timer(data->window, data->tooltiptimer);
2899                         data->tooltiptimer= NULL;
2900                 }
2901                 if(data->tooltip) {
2902                         ui_tooltip_free(C, data->tooltip);
2903                         data->tooltip= NULL;
2904                 }
2905
2906                 if(data->autoopentimer) {
2907                         WM_event_remove_window_timer(data->window, data->autoopentimer);
2908                         data->autoopentimer= NULL;
2909                 }
2910         }
2911
2912         /* text editing */
2913         if(state == BUTTON_STATE_TEXT_EDITING && data->state != BUTTON_STATE_TEXT_SELECTING)
2914                 ui_textedit_begin(but, data);
2915         else if(data->state == BUTTON_STATE_TEXT_EDITING && state != BUTTON_STATE_TEXT_SELECTING)
2916                 ui_textedit_end(but, data);
2917         
2918         /* number editing */
2919         if(state == BUTTON_STATE_NUM_EDITING)
2920                 ui_numedit_begin(but, data);
2921         else if(data->state == BUTTON_STATE_NUM_EDITING)
2922                 ui_numedit_end(but, data);
2923
2924         /* menu open */
2925         if(state == BUTTON_STATE_MENU_OPEN)
2926                 ui_blockopen_begin(C, but, data);
2927         else if(data->state == BUTTON_STATE_MENU_OPEN)
2928                 ui_blockopen_end(C, but, data);
2929
2930         /* add a short delay before exiting, to ensure there is some feedback */
2931         if(state == BUTTON_STATE_WAIT_FLASH) {
2932                 data->flashtimer= WM_event_add_window_timer(data->window, TIMER, BUTTON_FLASH_DELAY);
2933         }
2934         else if(data->flashtimer) {
2935                 WM_event_remove_window_timer(data->window, data->flashtimer);
2936                 data->flashtimer= NULL;
2937         }
2938
2939         /* add a blocking ui handler at the window handler for blocking, modal states
2940          * but not for popups, because we already have a window level handler*/
2941         if(!(but->block->handle && but->block->handle->popup)) {
2942                 if(button_modal_state(state)) {
2943                         if(!button_modal_state(data->state))
2944                                 WM_event_add_ui_handler(C, &data->window->handlers, ui_handler_region_menu, NULL, data);
2945                 }
2946                 else {
2947                         if(button_modal_state(data->state))
2948                                 WM_event_remove_ui_handler(&data->window->handlers, ui_handler_region_menu, NULL, data);
2949                 }
2950         }
2951
2952         data->state= state;
2953
2954         /* redraw */
2955         ED_region_tag_redraw(data->region);
2956 }
2957
2958 static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type)
2959 {
2960         uiHandleButtonData *data;
2961
2962         /* setup struct */
2963         data= MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData");
2964         data->window= CTX_wm_window(C);
2965         data->region= ar;
2966         data->interactive= 1;
2967         data->state = BUTTON_STATE_INIT;
2968
2969         /* activate button */
2970         but->flag |= UI_ACTIVE;
2971         but->active= data;
2972
2973         /* we disable auto_open in the block after a threshold, because we still
2974          * want to allow auto opening adjacent menus even if no button is activated
2975          * inbetween going over to the other button, but only for a short while */
2976         if(type == BUTTON_ACTIVATE_OVER && but->block->auto_open)
2977                 if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer())
2978                         but->block->auto_open= 0;
2979
2980         button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
2981
2982         if(type == BUTTON_ACTIVATE_OPEN) {
2983                 button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
2984
2985                 /* activate first button in submenu */
2986                 if(data->menu && data->menu->region) {
2987                         ARegion *subar= data->menu->region;
2988                         uiBlock *subblock= subar->uiblocks.first;
2989                         uiBut *subbut;
2990                         
2991                         if(subblock) {
2992                                 subbut= ui_but_first(subblock);
2993
2994                                 if(subbut)
2995                                         ui_handle_button_activate(C, subar, subbut, BUTTON_ACTIVATE);
2996                         }
2997                 }
2998         }
2999         else if(type == BUTTON_ACTIVATE_TEXT_EDITING)
3000                 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
3001         else if(type == BUTTON_ACTIVATE_APPLY)
3002                 button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH);
3003 }