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