merge with/from trunk at r35190
[blender.git] / source / blender / editors / interface / interface_handlers.c
index ff56b14c653c26b69543b992367598cda66981ac..a556d8322b24d059e1dcc8ebca6fd4ec7f94131b 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  */
 
 #include <float.h>
+#include <limits.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
+#include <assert.h>
 
 #include "MEM_guardedalloc.h"
 
@@ -35,6 +38,8 @@
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
 #include "PIL_time.h"
 
 #include "BKE_colortools.h"
@@ -42,7 +47,7 @@
 #include "BKE_idprop.h"
 #include "BKE_report.h"
 #include "BKE_texture.h"
-#include "BKE_utildefines.h"
+#include "BKE_unit.h"
 
 #include "ED_screen.h"
 #include "ED_util.h"
@@ -176,6 +181,7 @@ typedef struct uiAfterFunc {
        int autokey;
 } uiAfterFunc;
 
+static int ui_but_contains_pt(uiBut *but, int mx, int my);
 static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y);
 static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
 static int ui_handler_region_menu(bContext *C, wmEvent *event, void *userdata);
@@ -184,11 +190,16 @@ static void button_timers_tooltip_remove(bContext *C, uiBut *but);
 
 /* ******************** menu navigation helpers ************** */
 
+static int ui_but_editable(uiBut *but)
+{
+       return ELEM5(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX, PROGRESSBAR);
+}
+
 static uiBut *ui_but_prev(uiBut *but)
 {
        while(but->prev) {
                but= but->prev;
-               if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
+               if(!ui_but_editable(but)) return but;
        }
        return NULL;
 }
@@ -197,7 +208,7 @@ static uiBut *ui_but_next(uiBut *but)
 {
        while(but->next) {
                but= but->next;
-               if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
+               if(!ui_but_editable(but)) return but;
        }
        return NULL;
 }
@@ -208,7 +219,7 @@ static uiBut *ui_but_first(uiBlock *block)
        
        but= block->buttons.first;
        while(but) {
-               if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
+               if(!ui_but_editable(but)) return but;
                but= but->next;
        }
        return NULL;
@@ -220,7 +231,7 @@ static uiBut *ui_but_last(uiBlock *block)
        
        but= block->buttons.last;
        while(but) {
-               if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
+               if(!ui_but_editable(but)) return but;
                but= but->prev;
        }
        return NULL;
@@ -229,12 +240,26 @@ static uiBut *ui_but_last(uiBlock *block)
 static int ui_is_a_warp_but(uiBut *but)
 {
        if(U.uiflag & USER_CONTINUOUS_MOUSE)
-               if(ELEM(but->type, NUM, NUMABS))
+               if(ELEM3(but->type, NUM, NUMABS, HSVCIRCLE))
                        return TRUE;
 
        return FALSE;
 }
 
+/* file selectors are exempt from utf-8 checks */
+static int ui_is_utf8_but(uiBut *but)
+{
+       if (but->rnaprop) {
+               int subtype= RNA_property_subtype(but->rnaprop);
+               
+               if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
+                       return TRUE;
+               }
+       }
+
+       return !(but->flag & UI_BUT_NO_UTF8);
+}
+
 /* ********************** button apply/revert ************************/
 
 static ListBase UIAfterFuncs = {NULL, NULL};
@@ -301,18 +326,22 @@ static void ui_apply_autokey_undo(bContext *C, uiBut *but)
 {
        Scene *scene= CTX_data_scene(C);
        uiAfterFunc *after;
-       char *str= NULL;
 
        if(but->flag & UI_BUT_UNDO) {
+               const char *str= NULL;
+
                /* define which string to use for undo */
                if ELEM(but->type, LINK, INLINK) str= "Add button link";
                else if ELEM(but->type, MENU, ICONTEXTROW) str= but->drawstr;
                else if(but->drawstr[0]) str= but->drawstr;
                else str= but->tip;
-       }
 
-       /* delayed, after all other funcs run, popups are closed, etc */
-       if(str) {
+               /* fallback, else we dont get an undo! */
+               if(str == NULL || str[0] == '\0') {
+                       str= "Unknown Action";
+               }
+
+               /* delayed, after all other funcs run, popups are closed, etc */
                after= MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc");
                BLI_strncpy(after->undostr, str, sizeof(after->undostr));
                BLI_addtail(&UIAfterFuncs, after);
@@ -407,7 +436,7 @@ static void ui_apply_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data
        data->applied= 1;
 }
 
-static void ui_apply_but_TOG(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
+static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
 {
        double value;
        int w, lvalue, push;
@@ -623,13 +652,12 @@ static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, wmEvent *event)
        return BLI_in_rcti(&rect, x, y);
 }
 
-#define UI_DRAG_THRESHOLD      3
 static int ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
 {
        /* prevent other WM gestures to start while we try to drag */
        WM_gestures_remove(C);
 
-       if( ABS(data->dragstartx - event->x) + ABS(data->dragstarty - event->y) > UI_DRAG_THRESHOLD ) {
+       if( ABS(data->dragstartx - event->x) + ABS(data->dragstarty - event->y) > U.dragthreshold ) {
                wmDrag *drag;
                
                button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -874,7 +902,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
                case BUT_TOGDUAL:
                case OPTION:
                case OPTIONN:
-                       ui_apply_but_TOG(C, block, but, data);
+                       ui_apply_but_TOG(C, but, data);
                        break;
                case ROW:
                case LISTROW:
@@ -1045,19 +1073,19 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
 
        /* text/string and ID data */
        else if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) {
-               uiHandleButtonData *data= but->active;
+               uiHandleButtonData *active_data= but->active;
 
                if(but->poin==NULL && but->rnapoin.data==NULL);
                else if(mode=='c') {
                        button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
-                       BLI_strncpy(buf, data->str, UI_MAX_DRAW_STR);
-                       WM_clipboard_text_set(data->str, 0);
-                       data->cancel= 1;
+                       BLI_strncpy(buf, active_data->str, UI_MAX_DRAW_STR);
+                       WM_clipboard_text_set(active_data->str, 0);
+                       active_data->cancel= 1;
                        button_activate_state(C, but, BUTTON_STATE_EXIT);
                }
                else {
                        button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
-                       BLI_strncpy(data->str, buf, data->maxlen);
+                       BLI_strncpy(active_data->str, buf, active_data->maxlen);
                        button_activate_state(C, but, BUTTON_STATE_EXIT);
                }
        }
@@ -1148,7 +1176,7 @@ static int ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
        int len= strlen(str);
        int change= 0;
        if(but->selsta != but->selend && len) {
-               memmove( str+but->selsta, str+but->selend, len+1 );
+               memmove( str+but->selsta, str+but->selend, len-but->selsta+1 );
                change= 1;
        }
        
@@ -1258,7 +1286,7 @@ static int ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char asc
        return changed;
 }
 
-void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int select, int jump)
+static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int select, int jump)
 {
        char *str;
        int len;
@@ -1293,10 +1321,11 @@ void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int s
                } else {
                        if(select) {
                                /* make a selection, starting from the cursor position */
+                               int tlen;
                                but->selsta = but->pos;
                                
                                but->pos++;
-                               if(but->pos>strlen(str)) but->pos= strlen(str);
+                               if(but->pos > (tlen= strlen(str))) but->pos= tlen;
                                
                                but->selend = but->pos;
                        } else if(jump) {
@@ -1308,8 +1337,9 @@ void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int s
                                        if(test_special_char(str[but->pos])) break;
                                }
                        } else {
+                               int tlen;
                                but->pos++;
-                               if(but->pos>strlen(str)) but->pos= strlen(str);
+                               if(but->pos > (tlen= strlen(str))) but->pos= tlen;
                        }
                }
        }
@@ -1361,7 +1391,7 @@ void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int s
        }
 }
 
-void ui_textedit_move_end(uiBut *but, uiHandleButtonData *data, int direction, int select)
+static void ui_textedit_move_end(uiBut *but, uiHandleButtonData *data, int direction, int select)
 {
        char *str;
 
@@ -1528,6 +1558,20 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
        data->str= MEM_callocN(sizeof(char)*data->maxlen + 1, "textedit str");
        ui_get_but_string(but, data->str, data->maxlen);
 
+       if(ELEM3(but->type, NUM, NUMABS, NUMSLI)) {
+               /* XXX: we dont have utf editing yet so for numbers its best to strip out utf chars 
+                * this is so the deg' synbol isnt included in number editing fields: bug 22274 */
+               int i;
+               for(i=0; data->str[i]; i++) {
+                       if(!isascii(data->str[i])) {
+                               /* no stripping actually: just convert to alt name */
+                               ui_convert_to_unit_alt_name(but, data->str, data->maxlen);
+                               break;
+                       }
+               }
+       }
+       
+       
        data->origstr= BLI_strdup(data->str);
        data->selextend= 0;
        data->selstartx= 0;
@@ -1552,6 +1596,15 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
 static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
 {
        if(but) {
+               if(!ui_is_utf8_but(but)) {
+                       int strip= BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
+                       /* not a file?, strip non utf-8 chars */
+                       if(strip) {
+                               /* wont happen often so isnt that annoying to keep it here for a while */
+                               printf("invalid utf8 - stripped chars %d\n", strip);
+                       }
+               }
+               
                if(data->searchbox) {
                        if(data->cancel==0)
                                ui_searchbox_apply(but, data->searchbox);
@@ -1654,7 +1707,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                my= event->y;
                                ui_window_to_block(data->region, block, &mx, &my);
 
-                               if ((but->y1 <= my) && (my <= but->y2) && (but->x1 <= mx) && (mx <= but->x2)) {
+                               if (ui_but_contains_pt(but, mx, my)) {
                                        ui_textedit_set_cursor_pos(but, data, mx);
                                        but->selsta = but->selend = but->pos;
                                        data->selstartx= mx;
@@ -1771,6 +1824,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                /* only update when typing for TAB key */
                if(update && data->interactive) ui_apply_button(C, block, but, data, 1);
                else ui_check_but(but);
+               but->changed= TRUE;
                
                if(data->searchbox)
                        ui_searchbox_update(C, data->searchbox, but, 1); /* 1 = reset */
@@ -1994,14 +2048,17 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
                if(event->type == MOUSEMOVE)
                        return WM_UI_HANDLER_CONTINUE;
                
-               if(event->type == ESCKEY) {
-                       /* data->cancel doesnt work, this button opens immediate */
-                       if(but->flag & UI_BUT_IMMEDIATE)
-                               ui_set_but_val(but, 0);
-                       else
-                               data->cancel= 1;
-                       button_activate_state(C, but, BUTTON_STATE_EXIT);
-                       return WM_UI_HANDLER_BREAK;
+               if(event->type == LEFTMOUSE && event->val==KM_PRESS) {
+                       /* only cancel if click outside the button */
+                       if(ui_mouse_inside_button(but->active->region, but, event->x, event->y) == 0) {
+                               /* data->cancel doesnt work, this button opens immediate */
+                               if(but->flag & UI_BUT_IMMEDIATE)
+                                       ui_set_but_val(but, 0);
+                               else
+                                       data->cancel= 1;
+                               button_activate_state(C, but, BUTTON_STATE_EXIT);
+                               return WM_UI_HANDLER_BREAK;
+                       }
                }
                
                /* always set */
@@ -2029,21 +2086,23 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
                                button_activate_state(C, but, BUTTON_STATE_EXIT);
                                return WM_UI_HANDLER_BREAK;
                        }
+                       else if(event->type == ESCKEY) {
+                               data->cancel= 1;
+                               data->escapecancel= 1;
+                               button_activate_state(C, but, BUTTON_STATE_EXIT);
+                       }
+                       
                }
        }
        
        return WM_UI_HANDLER_CONTINUE;
 }
 
-
 static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
 {
        if(data->state == BUTTON_STATE_HIGHLIGHT) {
                if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
-                       short event= (short)ui_get_but_val(but);
-                       /* hardcoded prevention from editing or assigning ESC */
-                       if(event!=ESCKEY)
-                               button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
+                       button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
                        return WM_UI_HANDLER_BREAK;
                }
        }
@@ -2052,7 +2111,7 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, w
                        return WM_UI_HANDLER_CONTINUE;
 
                if(event->val==KM_PRESS) {
-                       if(event->type!=ESCKEY && WM_key_event_string(event->type)[0])
+                       if(WM_key_event_string(event->type)[0])
                                ui_set_but_val(but, event->type);
                        else
                                data->cancel= 1;
@@ -2119,8 +2178,13 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, wmE
                }
                
                if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
+                       int ret = WM_UI_HANDLER_BREAK;
+                       /* XXX (a bit ugly) Special case handling for filebrowser drag button */
+                       if(but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) {
+                               ret = WM_UI_HANDLER_CONTINUE;
+                       }
                        button_activate_state(C, but, BUTTON_STATE_EXIT);
-                       return WM_UI_HANDLER_BREAK;
+                       return ret;
                }
        }
        else if(data->state == BUTTON_STATE_WAIT_DRAG) {
@@ -2147,26 +2211,47 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, wmE
 }
 
 /* var names match ui_numedit_but_NUM */
-static float ui_numedit_apply_snapf(float tempf, float softmin, float softmax, float softrange, int snap)
+static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, float softmax, float softrange, int snap)
 {
-       if(tempf==softmin || tempf==softmax)
-               return tempf;
+       if(tempf==softmin || tempf==softmax || snap==0) {
+               /* pass */
+       }
+       else {
+               float fac= 1.0f;
+               
+               if(ui_is_but_unit(but)) {
+                       Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
+                       int unit_type= uiButGetUnitType(but)>>16;
+
+                       if(bUnit_IsValid(scene->unit.system, unit_type)) {
+                               fac= (float)bUnit_BaseScalar(scene->unit.system, unit_type);
+                               if(ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
+                                       fac /= scene->unit.scale_length;
+                               }
+                       }
+               }
 
-       switch(snap) {
-       case 0:
-               break;
-       case 1:
-               if(tempf==softmin || tempf==softmax) { }
-               else if(softrange < 2.10) tempf= 0.1*floor(10*tempf);
-               else if(softrange < 21.0) tempf= floor(tempf);
-               else tempf= 10.0*floor(tempf/10.0);
-               break;
-       case 2:
-               if(tempf==softmin || tempf==softmax) { }
-               else if(softrange < 2.10) tempf= 0.01*floor(100.0*tempf);
-               else if(softrange < 21.0) tempf= 0.1*floor(10.0*tempf);
-               else tempf= floor(tempf);
-               break;
+               if(fac != 1.0f) {
+                       /* snap in unit-space */
+                       tempf /= fac;
+                       softmin /= fac;
+                       softmax /= fac;
+                       softrange /= fac;
+               }
+
+               if(snap==1) {
+                       if(softrange < 2.10) tempf= 0.1*floor(10*tempf);
+                       else if(softrange < 21.0) tempf= floor(tempf);
+                       else tempf= 10.0*floor(tempf/10.0);
+               }
+               else if(snap==2) {
+                       if(softrange < 2.10) tempf= 0.01*floor(100.0*tempf);
+                       else if(softrange < 21.0) tempf= 0.1*floor(10.0*tempf);
+                       else tempf= floor(tempf);
+               }
+               
+               if(fac != 1.0f)
+                       tempf *= fac;
        }
 
        return tempf;
@@ -2213,14 +2298,13 @@ static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, i
        softmax= but->softmax;
        softrange= softmax - softmin;
 
-
        if(ui_is_a_warp_but(but)) {
                /* Mouse location isn't screen clamped to the screen so use a linear mapping
                 * 2px == 1-int, or 1px == 1-ClickStep */
                if(ui_is_but_float(but)) {
                        fac *= 0.01*but->a1;
                        tempf = data->startvalue + ((mx - data->dragstartx) * fac);
-                       tempf= ui_numedit_apply_snapf(tempf, softmin, softmax, softrange, snap);
+                       tempf= ui_numedit_apply_snapf(but, tempf, softmin, softmax, softrange, snap);
 
 #if 1          /* fake moving the click start, nicer for dragging back after passing the limit */
                        if(tempf < softmin) {
@@ -2273,15 +2357,18 @@ static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, i
                /* Use a non-linear mapping of the mouse drag especially for large floats (normal behavior) */
                deler= 500;
                if(!ui_is_but_float(but)) {
-                       if((softrange)<100) deler= 200.0;
-                       if((softrange)<25) deler= 50.0;
+                       /* prevent large ranges from getting too out of control */
+                       if (softrange > 600) deler = powf(softrange, 0.75);
+                       
+                       if (softrange < 100) deler= 200.0;
+                       if (softrange < 25) deler= 50.0;
                }
                deler /= fac;
 
-               if(ui_is_but_float(but) && softrange > 11) {
+               if(softrange > 11) {
                        /* non linear change in mouse input- good for high precicsion */
                        data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.002);
-               } else if (!ui_is_but_float(but) && softrange > 129) { /* only scale large int buttons */
+               } else if (softrange > 129) { /* only scale large int buttons */
                        /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */
                        data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.004);
                } else {
@@ -2289,8 +2376,7 @@ static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, i
                        data->dragf+= ((float)(mx-data->draglastx))/deler ;
                }
        
-               if(data->dragf>1.0) data->dragf= 1.0;
-               if(data->dragf<0.0) data->dragf= 0.0;
+               CLAMP(data->dragf, 0.0, 1.0);
                data->draglastx= mx;
                tempf= (softmin + data->dragf*softrange);
 
@@ -2302,7 +2388,7 @@ static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, i
 
                        CLAMP(temp, softmin, softmax);
                        lvalue= (int)data->value;
-
+                       
                        if(temp != lvalue) {
                                data->dragchange= 1;
                                data->value= (double)temp;
@@ -2311,7 +2397,7 @@ static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, i
                }
                else {
                        temp= 0;
-                       tempf= ui_numedit_apply_snapf(tempf, softmin, softmax, softrange, snap);
+                       tempf= ui_numedit_apply_snapf(but, tempf, softmin, softmax, softrange, snap);
 
                        CLAMP(tempf, softmin, softmax);
 
@@ -2758,17 +2844,18 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm
                }
                else if(but->type==COL) {
                        if( ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+                               float *hsv= ui_block_hsv_get(but->block);
                                float col[3];
                                
                                ui_get_but_vectorf(but, col);
-                               rgb_to_hsv(col[0], col[1], col[2], but->hsv, but->hsv+1, but->hsv+2);
+                               rgb_to_hsv_compat(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
 
                                if(event->type==WHEELDOWNMOUSE)
-                                       but->hsv[2]= CLAMPIS(but->hsv[2]-0.05f, 0.0f, 1.0f);
+                                       hsv[2]= CLAMPIS(hsv[2]-0.05f, 0.0f, 1.0f);
                                else
-                                       but->hsv[2]= CLAMPIS(but->hsv[2]+0.05f, 0.0f, 1.0f);
+                                       hsv[2]= CLAMPIS(hsv[2]+0.05f, 0.0f, 1.0f);
                                
-                               hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], data->vec, data->vec+1, data->vec+2);
+                               hsv_to_rgb(hsv[0], hsv[1], hsv[2], data->vec, data->vec+1, data->vec+2);
                                ui_set_but_vectorf(but, data->vec);
                                
                                button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -2898,7 +2985,8 @@ static int ui_do_but_NORMAL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
 
 static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx, int my)
 {
-       float rgb[3], hsv[3];
+       float rgb[3];
+       float *hsv= ui_block_hsv_get(but->block);
        float x, y;
        int changed= 1;
        int color_profile = but->block->color_profile;
@@ -2907,51 +2995,53 @@ static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx,
                if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
                        color_profile = BLI_PR_NONE;
        }
-       
+
        ui_get_but_vectorf(but, rgb);
-       rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
-               
+
+       rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
+
        /* relative position within box */
        x= ((float)mx-but->x1)/(but->x2-but->x1);
        y= ((float)my-but->y1)/(but->y2-but->y1);
        CLAMP(x, 0.0, 1.0);
        CLAMP(y, 0.0, 1.0);
-       
-       if(but->a1==0) {
-               hsv[2]= x; 
-               hsv[1]= y; 
-       }
-       else if(but->a1==1) {
-               hsv[0]= x;                              
-               hsv[2]= y;                              
-       }
-       else if(but->a1==2) {
-               hsv[0]= x; 
-               hsv[1]= y; 
-       }
-       else if(but->a1==3) {
-               hsv[0]= x; 
-       }
-       else if(but->a1==4) {
-               hsv[1]= x; 
-       }
-       else if(but->a1==5) {
-               hsv[2]= x; 
-       }
-       else if (but->a1==9){
-               float range;
-               
-               /* vertical 'value' strip */
 
+       switch((int)but->a1) {
+       case UI_GRAD_SV:
+               hsv[2]= x;
+               hsv[1]= y;
+               break;
+       case UI_GRAD_HV:
+               hsv[0]= x;
+               hsv[2]= y;
+               break;
+       case UI_GRAD_HS:
+               hsv[0]= x;
+               hsv[1]= y;
+               break;
+       case UI_GRAD_H:
+               hsv[0]= x;
+               break;
+       case UI_GRAD_S:
+               hsv[1]= x;
+               break;
+       case UI_GRAD_V:
+               hsv[2]= x;
+               break;
+       case UI_GRAD_V_ALT:     
+               /* vertical 'value' strip */
+       
                /* exception only for value strip - use the range set in but->min/max */
-               range = but->softmax - but->softmin;
-               hsv[2] = y*range + but->softmin;
+               hsv[2] = y * (but->softmax - but->softmin) + but->softmin;
                
                if (color_profile)
                        hsv[2] = srgb_to_linearrgb(hsv[2]);
                
                if (hsv[2] > but->softmax)
                        hsv[2] = but->softmax;
+               break;
+       default:
+               assert(!"invalid hsv type");
        }
 
        hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
@@ -2985,23 +3075,25 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
                        
                        return WM_UI_HANDLER_BREAK;
                }
-               else if (event->type == ZEROKEY && event->val == KM_PRESS) {
-                       if (but->a1==9){
-                               float rgb[3], hsv[3], def_hsv[3];
-                               float *def;
+               /* XXX hardcoded keymap check.... */
+               else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) {
+                       if (but->a1==UI_GRAD_V_ALT){
                                int len;
                                
                                /* reset only value */
                                
                                len= RNA_property_array_length(&but->rnapoin, but->rnaprop);
                                if (len >= 3) {
+                                       float rgb[3], def_hsv[3];
+                                       float *def;
+                                       float *hsv= ui_block_hsv_get(but->block);
                                        def= MEM_callocN(sizeof(float)*len, "reset_defaults - float");
                                        
                                        RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def);
                                        rgb_to_hsv(def[0], def[1], def[2], def_hsv, def_hsv+1, def_hsv+2);
                                        
                                        ui_get_but_vectorf(but, rgb);
-                                       rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
+                                       rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
                                        
                                        hsv_to_rgb(hsv[0], hsv[1], def_hsv[2], rgb, rgb+1, rgb+2);
                                        ui_set_but_vectorf(but, rgb);
@@ -3035,27 +3127,45 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
        return WM_UI_HANDLER_CONTINUE;
 }
 
-static int ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data, int mx, int my)
+static int ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data, int mx, int my, int shift)
 {
        rcti rect;
        int changed= 1;
-       float rgb[3], hsv[3];
+       float rgb[3];
+       float hsv[3];
        
        rect.xmin= but->x1; rect.xmax= but->x2;
        rect.ymin= but->y1; rect.ymax= but->y2;
        
        ui_get_but_vectorf(but, rgb);
-       rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
+       copy_v3_v3(hsv, ui_block_hsv_get(but->block));
+       rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
        
        /* exception, when using color wheel in 'locked' value state:
         * allow choosing a hue for black values, by giving a tiny increment */
-       if (but->a2 == 1) { // lock
+       if (but->flag & UI_BUT_COLOR_LOCK) { // lock
                if (hsv[2] == 0.f) hsv[2] = 0.0001f;
        }
-               
+
+       if(U.uiflag & USER_CONTINUOUS_MOUSE) {
+               float fac= shift ? 0.05 : 1.0f;
+               /* slow down the mouse, this is fairly picky */
+               mx = (data->dragstartx*(1.0f-fac) + mx*fac);
+               my = (data->dragstarty*(1.0f-fac) + my*fac);
+       }
+
        ui_hsvcircle_vals_from_pos(hsv, hsv+1, &rect, (float)mx, (float)my);
-       
+
+       if(but->flag & UI_BUT_COLOR_CUBIC)
+               hsv[1]= 1.0f - sqrt3f(1.0f - hsv[1]);
+
        hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
+
+       if((but->flag & UI_BUT_VEC_SIZE_LOCK) && (rgb[0] || rgb[1] || rgb[2])) {
+               normalize_v3(rgb);
+               mul_v3_fl(rgb, but->a2);
+       }
+
        ui_set_but_vectorf(but, rgb);
        
        data->draglastx= mx;
@@ -3082,27 +3192,29 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
                        button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
                        
                        /* also do drag the first time */
-                       if(ui_numedit_but_HSVCIRCLE(but, data, mx, my))
+                       if(ui_numedit_but_HSVCIRCLE(but, data, mx, my, event->shift))
                                ui_numedit_apply(C, block, but, data);
                        
                        return WM_UI_HANDLER_BREAK;
                }
-               else if (event->type == ZEROKEY && event->val == KM_PRESS) {
-                       float rgb[3], hsv[3], def_hsv[3];
-                       float *def;
+               /* XXX hardcoded keymap check.... */
+               else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) {
                        int len;
                        
                        /* reset only saturation */
                        
                        len= RNA_property_array_length(&but->rnapoin, but->rnaprop);
                        if (len >= 3) {
+                               float rgb[3], def_hsv[3];
+                               float *def;
+                               float *hsv= ui_block_hsv_get(but->block);
                                def= MEM_callocN(sizeof(float)*len, "reset_defaults - float");
                                
                                RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def);
                                rgb_to_hsv(def[0], def[1], def[2], def_hsv, def_hsv+1, def_hsv+2);
                                
                                ui_get_but_vectorf(but, rgb);
-                               rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
+                               rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
                                
                                hsv_to_rgb(hsv[0], def_hsv[1], hsv[2], rgb, rgb+1, rgb+2);
                                ui_set_but_vectorf(but, rgb);
@@ -3122,18 +3234,20 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
                }
                /* XXX hardcoded keymap check.... */
                else if(event->type == WHEELDOWNMOUSE) {
-                       but->hsv[2]= CLAMPIS(but->hsv[2]-0.05f, 0.0f, 1.0f);
+                       float *hsv= ui_block_hsv_get(but->block);
+                       hsv[2]= CLAMPIS(hsv[2]-0.05f, 0.0f, 1.0f);
                        ui_set_but_hsv(but);    // converts to rgb
                        ui_numedit_apply(C, block, but, data);
                }
                else if(event->type == WHEELUPMOUSE) {
-                       but->hsv[2]= CLAMPIS(but->hsv[2]+0.05f, 0.0f, 1.0f);
+                       float *hsv= ui_block_hsv_get(but->block);
+                       hsv[2]= CLAMPIS(hsv[2]+0.05f, 0.0f, 1.0f);
                        ui_set_but_hsv(but);    // converts to rgb
                        ui_numedit_apply(C, block, but, data);
                }
                else if(event->type == MOUSEMOVE) {
                        if(mx!=data->draglastx || my!=data->draglasty) {
-                               if(ui_numedit_but_HSVCIRCLE(but, data, mx, my))
+                               if(ui_numedit_but_HSVCIRCLE(but, data, mx, my, event->shift))
                                        ui_numedit_apply(C, block, but, data);
                        }
                }
@@ -3209,24 +3323,8 @@ static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandle
 
                        if(event->ctrl) {
                                /* insert new key on mouse location */
-                               if(coba->tot < MAXCOLORBAND-1) {
-                                       float pos= ((float)(mx - but->x1))/(but->x2-but->x1);
-                                       float col[4];
-                                       
-                                       do_colorband(coba, pos, col);   /* executes it */
-                                       
-                                       coba->tot++;
-                                       coba->cur= coba->tot-1;
-                                       
-                                       coba->data[coba->cur].r= col[0];
-                                       coba->data[coba->cur].g= col[1];
-                                       coba->data[coba->cur].b= col[2];
-                                       coba->data[coba->cur].a= col[3];
-                                       coba->data[coba->cur].pos= pos;
-
-                                       ui_colorband_update(coba);
-                               }
-
+                               float pos= ((float)(mx - but->x1))/(but->x2-but->x1);
+                               colorband_element_add(coba, pos);
                                button_activate_state(C, but, BUTTON_STATE_EXIT);
                        }
                        else {
@@ -3363,7 +3461,7 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
                if(event->type==LEFTMOUSE && event->val==KM_PRESS) {
                        CurveMapping *cumap= (CurveMapping*)but->poin;
                        CurveMap *cuma= cumap->cm+cumap->cur;
-                       CurveMapPoint *cmp= cuma->curve;
+                       CurveMapPoint *cmp;
                        float fx, fy, zoomx, zoomy, offsx, offsy;
                        float dist, mindist= 200.0f; // 14 pixels radius
                        int sel= -1;
@@ -3486,7 +3584,7 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
        return WM_UI_HANDLER_CONTINUE;
 }
 
-static int in_scope_resize_zone(uiBut *but, int x, int y)
+static int in_scope_resize_zone(uiBut *but, int UNUSED(x), int y)
 {
        // bottom corner return (x > but->x2 - SCOPE_RESIZE_PAD) && (y < but->y1 + SCOPE_RESIZE_PAD);
        return (y < but->y1 + SCOPE_RESIZE_PAD);
@@ -3545,7 +3643,8 @@ static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandle
                        
                        return WM_UI_HANDLER_BREAK;
                }
-               else if (event->type == ZEROKEY && event->val == KM_PRESS) {
+               /* XXX hardcoded keymap check.... */
+               else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) {
                        Histogram *hist = (Histogram *)but->poin;
                        hist->ymax = 1.f;
                        
@@ -3627,7 +3726,8 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB
 
                        return WM_UI_HANDLER_BREAK;
                }
-               else if (event->type == ZEROKEY && event->val == KM_PRESS) {
+               /* XXX hardcoded keymap check.... */
+               else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) {
                        Scopes *scopes = (Scopes *)but->poin;
                        scopes->wavefrm_yfac = 1.f;
 
@@ -3661,13 +3761,13 @@ static int ui_numedit_but_VECTORSCOPE(uiBut *but, uiHandleButtonData *data, int
        Scopes *scopes = (Scopes *)but->poin;
        rcti rect;
        int changed= 1;
-       float dx, dy;
+       /* float dx, dy; */
 
        rect.xmin= but->x1; rect.xmax= but->x2;
        rect.ymin= but->y1; rect.ymax= but->y2;
 
-       dx = mx - data->draglastx;
-       dy = my - data->draglasty;
+       /* dx = mx - data->draglastx; */
+       /* dy = my - data->draglasty; */
 
        if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
                 /* resize vectorscope widget itself */
@@ -3725,7 +3825,7 @@ static int ui_do_but_VECTORSCOPE(bContext *C, uiBlock *block, uiBut *but, uiHand
 }
 
 #ifdef INTERNATIONAL
-static int ui_do_but_CHARTAB(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
+static int ui_do_but_CHARTAB(bContext *UNUSED(C), uiBlock *UNUSED(block), uiBut *UNUSED(but), uiHandleButtonData *UNUSED(data), wmEvent *UNUSED(event))
 {
        /* XXX 2.50 bad global and state access */
 #if 0
@@ -3863,34 +3963,36 @@ static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, wmE
        return WM_UI_HANDLER_CONTINUE;
 }
 
-static void but_shortcut_name_func(bContext *C, void *arg1, int event)
+static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
 {
        uiBut *but = (uiBut *)arg1;
-       
-       char buf[512], *butstr, *cpoin;
-       
+
        if (but->optype) {
+               char buf[512], *cpoin;
+
                IDProperty *prop= (but->opptr)? but->opptr->data: NULL;
                
                /* complex code to change name of button */
                if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
-                       
-                       butstr= MEM_mallocN(strlen(but->str)+strlen(buf)+2, "menu_block_set_keymaps");
-                       
+                       wmKeyMap *km= NULL;
+                       char *butstr_orig;
+
                        // XXX but->str changed... should not, remove the hotkey from it
                        cpoin= strchr(but->str, '|');
                        if(cpoin) *cpoin= 0;            
-                       
-                       strcpy(butstr, but->str);
-                       strcat(butstr, "|");
-                       strcat(butstr, buf);
-                       
+
+                       butstr_orig= BLI_strdup(but->str);
+                       BLI_snprintf(but->strdata, sizeof(but->strdata), "%s|%s", butstr_orig, buf);
+                       MEM_freeN(butstr_orig);
                        but->str= but->strdata;
-                       BLI_strncpy(but->str, butstr, sizeof(but->strdata));
-                       MEM_freeN(butstr);
-                       
+
                        ui_check_but(but);
-               } else {
+
+                       /* set the keymap editable else the key wont save */
+                       WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, 1, &km);
+                       WM_keymap_copy_to_user(km);
+               }
+               else {
                        /* shortcut was removed */
                        cpoin= strchr(but->str, '|');
                        if(cpoin) *cpoin= 0;
@@ -3916,14 +4018,14 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
        
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
-       uiBlockSetFlag(block, UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
+       uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
        uiBlockSetDirection(block, UI_CENTER);
        
        layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, style);
        
-       uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT|UI_ITEM_R_IMMEDIATE, "", 0);
+       uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT|UI_ITEM_R_IMMEDIATE, "", ICON_NULL);
        
-       uiPopupBoundsBlock(block, 6, 100, 10);
+       uiPopupBoundsBlock(block, 6, -50, 26);
        uiEndBlock(C, block);
        
        return block;
@@ -3942,35 +4044,39 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
        
        km = WM_keymap_guess_opname(C, but->optype->idname);            
        kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0);
-       MEM_freeN(kmi->properties);
-       if (prop)
-               kmi->properties= IDP_CopyProperty(prop);
-       
+
+       if (prop) {
+               prop= IDP_CopyProperty(prop);
+       }
+
+       /* prop can be NULL */  
+       WM_keymap_properties_reset(kmi, prop);
+
        RNA_pointer_create(NULL, &RNA_KeyMapItem, kmi, &ptr);
-       
+
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
        uiBlockSetFlag(block, UI_BLOCK_RET_1);
        uiBlockSetDirection(block, UI_CENTER);
-       
+
        layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, style);
 
-       uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT|UI_ITEM_R_IMMEDIATE, "", 0);
+       uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT|UI_ITEM_R_IMMEDIATE, "", ICON_NULL);
        
-       uiPopupBoundsBlock(block, 6, 100, 10);
+       uiPopupBoundsBlock(block, 6, -50, 26);
        uiEndBlock(C, block);
        
        return block;
 }
 
-static void popup_change_shortcut_func(bContext *C, void *arg1, void *arg2)
+static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
 {
        uiBut *but = (uiBut *)arg1;
        button_timers_tooltip_remove(C, but);
        uiPupBlock(C, menu_change_shortcut, but);
 }
 
-static void remove_shortcut_func(bContext *C, void *arg1, void *arg2)
+static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
 {
        uiBut *but = (uiBut *)arg1;
        wmKeyMap *km;
@@ -3984,7 +4090,7 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *arg2)
        but_shortcut_name_func(C, but, 0);
 }
 
-static void popup_add_shortcut_func(bContext *C, void *arg1, void *arg2)
+static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
 {
        uiBut *but = (uiBut *)arg1;
        button_timers_tooltip_remove(C, but);
@@ -3997,7 +4103,7 @@ static int ui_but_menu(bContext *C, uiBut *but)
        uiPopupMenu *pup;
        uiLayout *layout;
        int length;
-       char *name;
+       const char *name;
 
        if((but->rnapoin.data && but->rnaprop)==0 && but->optype==NULL)
                return 0;
@@ -4005,42 +4111,47 @@ static int ui_but_menu(bContext *C, uiBut *but)
        button_timers_tooltip_remove(C, but);
 
        if(but->rnaprop)
-               name= (char*)RNA_property_ui_name(but->rnaprop);
+               name= RNA_property_ui_name(but->rnaprop);
        else if (but->optype)
                name= but->optype->name;
        else
                name= "<needs_name>"; // XXX - should never happen.
 
-       pup= uiPupMenuBegin(C, name, 0);
+       pup= uiPupMenuBegin(C, name, ICON_NULL);
        layout= uiPupMenuLayout(pup);
        
        uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
 
        if(but->rnapoin.data && but->rnaprop) {
+               short is_anim= RNA_property_animateable(&but->rnapoin, but->rnaprop);
+
+               /* second slower test, saved people finding keyframe items in menus when its not possible */
+               if(is_anim)
+                       is_anim= RNA_property_path_from_ID_check(&but->rnapoin, but->rnaprop);
 
                length= RNA_property_array_length(&but->rnapoin, but->rnaprop);
                
                /* Keyframes */
                if(but->flag & UI_BUT_ANIMATED_KEY) {
                        if(length) {
-                               uiItemBooleanO(layout, "Replace Keyframes", 0, "ANIM_OT_keyframe_insert_button", "all", 1);
-                               uiItemBooleanO(layout, "Replace Single Keyframe", 0, "ANIM_OT_keyframe_insert_button", "all", 0);
-                               uiItemBooleanO(layout, "Delete Keyframes", 0, "ANIM_OT_keyframe_delete_button", "all", 1);
-                               uiItemBooleanO(layout, "Delete Single Keyframe", 0, "ANIM_OT_keyframe_delete_button", "all", 0);
+                               uiItemBooleanO(layout, "Replace Keyframes", ICON_NULL, "ANIM_OT_keyframe_insert_button", "all", 1);
+                               uiItemBooleanO(layout, "Replace Single Keyframe", ICON_NULL, "ANIM_OT_keyframe_insert_button", "all", 0);
+                               uiItemBooleanO(layout, "Delete Keyframes", ICON_NULL, "ANIM_OT_keyframe_delete_button", "all", 1);
+                               uiItemBooleanO(layout, "Delete Single Keyframe", ICON_NULL, "ANIM_OT_keyframe_delete_button", "all", 0);
                        }
                        else {
-                               uiItemBooleanO(layout, "Replace Keyframe", 0, "ANIM_OT_keyframe_insert_button", "all", 0);
-                               uiItemBooleanO(layout, "Delete Keyframe", 0, "ANIM_OT_keyframe_delete_button", "all", 0);
+                               uiItemBooleanO(layout, "Replace Keyframe", ICON_NULL, "ANIM_OT_keyframe_insert_button", "all", 0);
+                               uiItemBooleanO(layout, "Delete Keyframe", ICON_NULL, "ANIM_OT_keyframe_delete_button", "all", 0);
                        }
                }
                else if(but->flag & UI_BUT_DRIVEN);
-               else if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) {
+               else if(is_anim) {
                        if(length) {
-                               uiItemBooleanO(layout, "Insert Keyframes", 0, "ANIM_OT_keyframe_insert_button", "all", 1);
-                               uiItemBooleanO(layout, "Insert Single Keyframe", 0, "ANIM_OT_keyframe_insert_button", "all", 0);
+                               uiItemBooleanO(layout, "Insert Keyframes", ICON_NULL, "ANIM_OT_keyframe_insert_button", "all", 1);
+                               uiItemBooleanO(layout, "Insert Single Keyframe", ICON_NULL, "ANIM_OT_keyframe_insert_button", "all", 0);
                        }
                        else
-                               uiItemBooleanO(layout, "Insert Keyframe", 0, "ANIM_OT_keyframe_insert_button", "all", 0);
+                               uiItemBooleanO(layout, "Insert Keyframe", ICON_NULL, "ANIM_OT_keyframe_insert_button", "all", 0);
                }
                
                /* Drivers */
@@ -4048,43 +4159,43 @@ static int ui_but_menu(bContext *C, uiBut *but)
                        uiItemS(layout);
 
                        if(length) {
-                               uiItemBooleanO(layout, "Delete Drivers", 0, "ANIM_OT_driver_button_remove", "all", 1);
-                               uiItemBooleanO(layout, "Delete Single Driver", 0, "ANIM_OT_driver_button_remove", "all", 0);
+                               uiItemBooleanO(layout, "Delete Drivers", ICON_NULL, "ANIM_OT_driver_button_remove", "all", 1);
+                               uiItemBooleanO(layout, "Delete Single Driver", ICON_NULL, "ANIM_OT_driver_button_remove", "all", 0);
                        }
                        else
-                               uiItemBooleanO(layout, "Delete Driver", 0, "ANIM_OT_driver_button_remove", "all", 0);
+                               uiItemBooleanO(layout, "Delete Driver", ICON_NULL, "ANIM_OT_driver_button_remove", "all", 0);
 
-                       uiItemO(layout, "Copy Driver", 0, "ANIM_OT_copy_driver_button");
+                       uiItemO(layout, "Copy Driver", ICON_NULL, "ANIM_OT_copy_driver_button");
                        if (ANIM_driver_can_paste())
-                               uiItemO(layout, "Paste Driver", 0, "ANIM_OT_paste_driver_button");
+                               uiItemO(layout, "Paste Driver", ICON_NULL, "ANIM_OT_paste_driver_button");
                }
-               else if(but->flag & UI_BUT_ANIMATED_KEY);
-               else if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) {
+               else if(but->flag & (UI_BUT_ANIMATED_KEY|UI_BUT_ANIMATED));
+               else if(is_anim) {
                        uiItemS(layout);
 
                        if(length) {
-                               uiItemBooleanO(layout, "Add Drivers", 0, "ANIM_OT_driver_button_add", "all", 1);
-                               uiItemBooleanO(layout, "Add Single Driver", 0, "ANIM_OT_driver_button_add", "all", 0);
+                               uiItemBooleanO(layout, "Add Drivers", ICON_NULL, "ANIM_OT_driver_button_add", "all", 1);
+                               uiItemBooleanO(layout, "Add Single Driver", ICON_NULL, "ANIM_OT_driver_button_add", "all", 0);
                        }
                        else
-                               uiItemBooleanO(layout, "Add Driver", 0, "ANIM_OT_driver_button_add", "all", 0);
+                               uiItemBooleanO(layout, "Add Driver", ICON_NULL, "ANIM_OT_driver_button_add", "all", 0);
 
                        if (ANIM_driver_can_paste())
-                               uiItemO(layout, "Paste Driver", 0, "ANIM_OT_paste_driver_button");
+                               uiItemO(layout, "Paste Driver", ICON_NULL, "ANIM_OT_paste_driver_button");
                }
                
                /* Keying Sets */
-               if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) {
+               if(is_anim) {
                        uiItemS(layout);
 
                        if(length) {
-                               uiItemBooleanO(layout, "Add All to Keying Set", 0, "ANIM_OT_keyingset_button_add", "all", 1);
-                               uiItemBooleanO(layout, "Add Single to Keying Set", 0, "ANIM_OT_keyingset_button_add", "all", 0);
-                               uiItemO(layout, "Remove from Keying Set", 0, "ANIM_OT_keyingset_button_remove");
+                               uiItemBooleanO(layout, "Add All to Keying Set", ICON_NULL, "ANIM_OT_keyingset_button_add", "all", 1);
+                               uiItemBooleanO(layout, "Add Single to Keying Set", ICON_NULL, "ANIM_OT_keyingset_button_add", "all", 0);
+                               uiItemO(layout, "Remove from Keying Set", ICON_NULL, "ANIM_OT_keyingset_button_remove");
                        }
                        else {
-                               uiItemBooleanO(layout, "Add to Keying Set", 0, "ANIM_OT_keyingset_button_add", "all", 0);
-                               uiItemO(layout, "Remove from Keying Set", 0, "ANIM_OT_keyingset_button_remove");
+                               uiItemBooleanO(layout, "Add to Keying Set", ICON_NULL, "ANIM_OT_keyingset_button_add", "all", 0);
+                               uiItemO(layout, "Remove from Keying Set", ICON_NULL, "ANIM_OT_keyingset_button_remove");
                        }
                }
                
@@ -4096,14 +4207,14 @@ static int ui_but_menu(bContext *C, uiBut *but)
                //Paste Property Value
                
                if(length) {
-                       uiItemBooleanO(layout, "Reset All to Default Values", 0, "UI_OT_reset_default_button", "all", 1);
-                       uiItemBooleanO(layout, "Reset Single to Default Value", 0, "UI_OT_reset_default_button", "all", 0);
+                       uiItemBooleanO(layout, "Reset All to Default Values", ICON_NULL, "UI_OT_reset_default_button", "all", 1);
+                       uiItemBooleanO(layout, "Reset Single to Default Value", ICON_NULL, "UI_OT_reset_default_button", "all", 0);
                }
                else
-                       uiItemO(layout, "Reset to Default Value", 0, "UI_OT_reset_default_button");
+                       uiItemO(layout, "Reset to Default Value", ICON_NULL, "UI_OT_reset_default_button");
                
-               uiItemO(layout, "Copy Data Path", 0, "UI_OT_copy_data_path_button");
-               uiItemO(layout, "Copy To Selected", 0, "UI_OT_copy_to_selected_button");
+               uiItemO(layout, "Copy Data Path", ICON_NULL, "UI_OT_copy_data_path_button");
+               uiItemO(layout, "Copy To Selected", ICON_NULL, "UI_OT_copy_to_selected_button");
 
                uiItemS(layout);
        }
@@ -4152,28 +4263,29 @@ static int ui_but_menu(bContext *C, uiBut *but)
 
                        WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
                        RNA_string_set(&ptr_props, "doc_id", buf);
-                       uiItemFullO(layout, "WM_OT_doc_view", "View Docs", 0, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
-
+                       uiItemFullO(layout, "WM_OT_doc_view", "View Docs", ICON_NULL, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
 
-                       WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
+                       /* XXX inactive option, not for public! */
+/*                     WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
                        RNA_string_set(&ptr_props, "doc_id", buf);
                        RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop));
 
-                       uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", 0, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
+                       uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NULL, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
+ */
                }
                else if (but->optype) {
                        WM_operator_py_idname(buf, but->optype->idname);
 
                        WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
                        RNA_string_set(&ptr_props, "doc_id", buf);
-                       uiItemFullO(layout, "WM_OT_doc_view", "View Docs", 0, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
+                       uiItemFullO(layout, "WM_OT_doc_view", "View Docs", ICON_NULL, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
 
 
                        WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
                        RNA_string_set(&ptr_props, "doc_id", buf);
                        RNA_string_set(&ptr_props, "doc_new", but->optype->description);
 
-                       uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", 0, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
+                       uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NULL, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
                }
        }
 
@@ -4184,6 +4296,7 @@ static int ui_but_menu(bContext *C, uiBut *but)
 
 static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
 {
+//     Scene *scene= CTX_data_scene(C);
        uiHandleButtonData *data;
        int retval;
 
@@ -4193,7 +4306,12 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
        if(but->flag & UI_BUT_DISABLED)
                return WM_UI_HANDLER_CONTINUE;
 
-       if(data->state == BUTTON_STATE_HIGHLIGHT) {
+       if(     (data->state == BUTTON_STATE_HIGHLIGHT) &&
+               /* check prevval because of modal operators [#24016],
+                * modifier check is to allow Ctrl+C for copy.
+                * if this causes other problems, remove this check and suffer the bug :) - campbell */
+               (event->prevval != KM_PRESS || ISKEYMODIFIER(event->prevtype))
+       ) {
                /* handle copy-paste */
                if(ELEM(event->type, CKEY, VKEY) && event->val==KM_PRESS && (event->ctrl || event->oskey)) {
                        ui_but_copy_paste(C, but, data, (event->type == CKEY)? 'c': 'v');
@@ -4237,18 +4355,20 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                        return WM_UI_HANDLER_BREAK;
                }
                /* reset to default */
-               else if(event->type == ZEROKEY && event->val == KM_PRESS) {
+               /* XXX hardcoded keymap check.... */
+               else if(ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) {
+                       /* ctrl-0 = for arrays, only the active one gets done (vs whole array for just 0) */
                        if (!(ELEM3(but->type, HSVCIRCLE, HSVCUBE, HISTOGRAM)))
-                               ui_set_but_default(C, but);
+                               ui_set_but_default(C, but, !event->ctrl);
                }
                /* handle menu */
                else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) {
                        /* RMB has two options now */
                        if (ui_but_menu(C, but)) {
                                return WM_UI_HANDLER_BREAK;
-                       }
                }
        }
+       }
 
        /* verify if we can edit this button */
        if(ELEM(event->type, LEFTMOUSE, RETKEY)) {
@@ -4308,6 +4428,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
        case ROW:
        case LISTROW:
        case BUT_IMAGE:
+       case PROGRESSBAR:
                retval= ui_do_but_EXIT(C, but, data, event);
                break;
        case HISTOGRAM:
@@ -4335,7 +4456,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                retval= ui_do_but_BUT(C, but, data, event);
                break;
        case COL:
-               if(but->a1 == 9)  // signal to prevent calling up color picker
+               if(but->a1 == UI_GRAD_V_ALT)  // signal to prevent calling up color picker
                        retval= ui_do_but_EXIT(C, but, data, event);
                else
                        retval= ui_do_but_BLOCK(C, but, data, event);
@@ -4490,7 +4611,7 @@ static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
        return 1;
 }
 
-static uiBut *ui_but_find_mouse_over(wmWindow *win, ARegion *ar, int x, int y)
+static uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
 {
        uiBlock *block;
        uiBut *but, *butover= NULL;
@@ -4522,7 +4643,7 @@ static uiBut *ui_but_find_mouse_over(wmWindow *win, ARegion *ar, int x, int y)
        return butover;
 }
 
-static uiBut *ui_list_find_mouse_over(wmWindow *win, ARegion *ar, int x, int y)
+static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
 {
        uiBlock *block;
        uiBut *but;
@@ -4560,19 +4681,21 @@ static void button_timers_tooltip_remove(bContext *C, uiBut *but)
        uiHandleButtonData *data;
 
        data= but->active;
+       if(data) {
 
-       if(data->tooltiptimer) {
-               WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
-               data->tooltiptimer= NULL;
-       }
-       if(data->tooltip) {
-               ui_tooltip_free(C, data->tooltip);
-               data->tooltip= NULL;
-       }
+               if(data->tooltiptimer) {
+                       WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
+                       data->tooltiptimer= NULL;
+               }
+               if(data->tooltip) {
+                       ui_tooltip_free(C, data->tooltip);
+                       data->tooltip= NULL;
+               }
 
-       if(data->autoopentimer) {
-               WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
-               data->autoopentimer= NULL;
+               if(data->autoopentimer) {
+                       WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
+                       data->autoopentimer= NULL;
+               }
        }
 }
 
@@ -4711,7 +4834,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
 
        /* we disable auto_open in the block after a threshold, because we still
         * want to allow auto opening adjacent menus even if no button is activated
-        * inbetween going over to the other button, but only for a short while */
+        * in between going over to the other button, but only for a short while */
        if(type == BUTTON_ACTIVATE_OVER && but->block->auto_open)
                if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer())
                        but->block->auto_open= 0;
@@ -4751,7 +4874,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
                button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH);
 }
 
-static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *but, int mousemove)
+static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *but, int mousemove, int onfree)
 {
        uiBlock *block= but->block;
        uiBut *bt;
@@ -4761,7 +4884,8 @@ static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *b
                button_activate_state(C, but, BUTTON_STATE_EXIT);
 
        /* apply the button action or value */
-       ui_apply_button(C, block, but, data, 0);
+       if(!onfree)
+               ui_apply_button(C, block, but, data, 0);
 
        /* if this button is in a menu, this will set the button return
         * value to the button value and the menu return value to ok, the
@@ -4776,7 +4900,7 @@ static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *b
                }
        }
 
-       if(!data->cancel) {
+       if(!onfree && !data->cancel) {
                /* autokey & undo push */
                ui_apply_autokey_undo(C, but);
 
@@ -4809,7 +4933,8 @@ static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *b
        but->active= NULL;
        but->flag &= ~(UI_ACTIVE|UI_SELECT);
        but->flag |= UI_BUT_LAST_ACTIVE;
-       ui_check_but(but);
+       if(!onfree)
+               ui_check_but(but);
 
        /* adds empty mousemove in queue for re-init handler, in case mouse is
         * still over a button. we cannot just check for this ourselfs because
@@ -4818,7 +4943,7 @@ static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *b
                WM_event_add_mousemove(C);
 }
 
-void ui_button_active_cancel(const bContext *C, uiBut *but)
+void ui_button_active_free(const bContext *C, uiBut *but)
 {
        uiHandleButtonData *data;
 
@@ -4828,7 +4953,92 @@ void ui_button_active_cancel(const bContext *C, uiBut *but)
        if(but->active) {
                data= but->active;
                data->cancel= 1;
-               button_activate_exit((bContext*)C, data, but, 0);
+               button_activate_exit((bContext*)C, data, but, 0, 1);
+       }
+}
+
+/* helper function for insert keyframe, reset to default, etc operators */
+void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+{
+       ARegion *ar= CTX_wm_region(C);
+
+       memset(ptr, 0, sizeof(*ptr));
+       *prop= NULL;
+       *index= 0;
+
+       while(ar) {
+               uiBlock *block;
+               uiBut *but, *activebut= NULL;
+       
+               /* find active button */
+               for(block=ar->uiblocks.first; block; block=block->next) {
+                       for(but=block->buttons.first; but; but= but->next) {
+                               if(but->active)
+                                       activebut= but;
+                               else if(!activebut && (but->flag & UI_BUT_LAST_ACTIVE))
+                                       activebut= but;
+                       }
+               }
+
+               if(activebut && activebut->rnapoin.data) {
+                       uiHandleButtonData *data= activebut->active;
+
+                       /* found RNA button */
+                       *ptr= activebut->rnapoin;
+                       *prop= activebut->rnaprop;
+                       *index= activebut->rnaindex;
+
+                       /* recurse into opened menu, like colorpicker case */
+                       if(data && data->menu && (ar != data->menu->region)) {
+                               ar = data->menu->region;
+                       }
+                       else {
+                               return;
+                       }
+               }
+               else {
+                       /* no active button */
+                       return;
+               }
+       }
+}
+
+/* helper function for insert keyframe, reset to default, etc operators */
+void uiContextAnimUpdate(const bContext *C)
+{
+       Scene *scene= CTX_data_scene(C);
+       ARegion *ar= CTX_wm_region(C);
+       uiBlock *block;
+       uiBut *but, *activebut;
+
+       while(ar) {
+               /* find active button */
+               activebut= NULL;
+
+               for(block=ar->uiblocks.first; block; block=block->next) {
+                       for(but=block->buttons.first; but; but= but->next) {
+                               ui_but_anim_flag(but, (scene)? scene->r.cfra: 0.0f);
+                               ED_region_tag_redraw(ar);
+                               
+                               if(but->active)
+                                       activebut= but;
+                               else if(!activebut && (but->flag & UI_BUT_LAST_ACTIVE))
+                                       activebut= but;
+                       }
+               }
+
+               if(activebut) {
+                       /* always recurse into opened menu, so all buttons update (like colorpicker) */
+                       uiHandleButtonData *data= activebut->active;
+                       if(data && data->menu)
+                               ar = data->menu->region;
+                       else
+                               return;
+               }
+               else {
+                       /* no active button */
+                       return;
+               }
        }
 }
 
@@ -4849,11 +5059,10 @@ static uiBut *uit_but_find_open_event(ARegion *ar, wmEvent *event)
 
 static int ui_handle_button_over(bContext *C, wmEvent *event, ARegion *ar)
 {
-       wmWindow *win= CTX_wm_window(C);
        uiBut *but;
 
        if(event->type == MOUSEMOVE) {
-               but= ui_but_find_mouse_over(win, ar, event->x, event->y);
+               but= ui_but_find_mouse_over(ar, event->x, event->y);
                if(but)
                        button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
        }
@@ -4894,7 +5103,7 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu
        if(oldbut) {
                data= oldbut->active;
                data->cancel= 1;
-               button_activate_exit(C, data, oldbut, 0);
+               button_activate_exit(C, data, oldbut, 0, 0);
        }
 
        button_activate_init(C, ar, but, type);
@@ -4931,7 +5140,7 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but)
                                        data->cancel= 1;
                                        button_activate_state(C, but, BUTTON_STATE_EXIT);
                                }
-                               else if(ui_but_find_mouse_over(data->window, ar, event->x, event->y) != but) {
+                               else if(ui_but_find_mouse_over(ar, event->x, event->y) != but) {
                                        data->cancel= 1;
                                        button_activate_state(C, but, BUTTON_STATE_EXIT);
                                }
@@ -4992,16 +5201,17 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but)
                                }
                                else {
                                        /* deselect the button when moving the mouse away */
+                                       /* also de-activate for buttons that only show higlights */
                                        if(ui_mouse_inside_button(ar, but, event->x, event->y)) {
                                                if(!(but->flag & UI_SELECT)) {
-                                                       but->flag |= UI_SELECT;
+                                                       but->flag |= (UI_SELECT|UI_ACTIVE);
                                                        data->cancel= 0;
                                                        ED_region_tag_redraw(data->region);
                                                }
                                        }
                                        else {
                                                if(but->flag & UI_SELECT) {
-                                                       but->flag &= ~UI_SELECT;
+                                                       but->flag &= ~(UI_SELECT|UI_ACTIVE);
                                                        data->cancel= 1;
                                                        ED_region_tag_redraw(data->region);
                                                }
@@ -5027,9 +5237,16 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but)
                retval= WM_UI_HANDLER_CONTINUE;
        }
        else if(data->state == BUTTON_STATE_MENU_OPEN) {
+               /* check for exit because of mouse-over another button */
                switch(event->type) {
-                       case MOUSEMOVE: {
-                               uiBut *bt= ui_but_find_mouse_over(data->window, ar, event->x, event->y);
+                       case MOUSEMOVE:
+                               
+                               if(data->menu && data->menu->region)
+                                       if(ui_mouse_inside_region(data->menu->region, event->x, event->y))
+                                               break;
+                       
+                       {
+                               uiBut *bt= ui_but_find_mouse_over(ar, event->x, event->y);
 
                                if(bt && bt->active != data) {
                                        if(but->type != COL) /* exception */
@@ -5052,7 +5269,7 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but)
                postbut= data->postbut;
                posttype= data->posttype;
 
-               button_activate_exit(C, data, but, (postbut == NULL));
+               button_activate_exit(C, data, but, (postbut == NULL), 0);
 
                /* for jumping to the next button with tab while text editing */
                if(postbut)
@@ -5064,8 +5281,7 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but)
 
 static int ui_handle_list_event(bContext *C, wmEvent *event, ARegion *ar)
 {
-       wmWindow *win= CTX_wm_window(C);
-       uiBut *but= ui_list_find_mouse_over(win, ar, event->x, event->y);
+       uiBut *but= ui_list_find_mouse_over(ar, event->x, event->y);
        int retval= WM_UI_HANDLER_CONTINUE;
        int value, min, max;
 
@@ -5156,20 +5372,21 @@ static void ui_handle_button_return_submenu(bContext *C, wmEvent *event, uiBut *
                if(menu->menuretval != UI_RETURN_OK)
                        data->cancel= 1;
 
-               button_activate_exit(C, data, but, 1);
+               button_activate_exit(C, data, but, 1, 0);
        }
        else if(menu->menuretval == UI_RETURN_OUT) {
                if(event->type==MOUSEMOVE && ui_mouse_inside_button(data->region, but, event->x, event->y)) {
                        button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
                }
                else {
-                       if(event->type != MOUSEMOVE) {
+                       if (ISKEYBOARD(event->type)) {
+                               /* keyboard menu hierarchy navigation, going back to previous level */
                                but->active->used_mouse= 0;
                                button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
                        }
                        else {
                                data->cancel= 1;
-                               button_activate_exit(C, data, but, 1);
+                               button_activate_exit(C, data, but, 1, 0);
                        }
                }
        }
@@ -5251,7 +5468,7 @@ static int ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *men
        return menu->dotowards;
 }
 
-int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int topmenu)
+static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int UNUSED(topmenu))
 {
        ARegion *ar;
        uiBlock *block;
@@ -5329,20 +5546,49 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
                                                if(event->val==KM_PRESS) {
                                                        but= ui_but_find_activated(ar);
                                                        if(but) {
-                                                               if(ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) 
-                                                                       but= ui_but_next(but);
-                                                               else
-                                                                       but= ui_but_prev(but);
+                                                               /* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */
+                                                               if(     ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) ||
+                                                                       ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) ||
+                                                                       ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP))
+                                                               ) {
+                                                                       /* the following is just a hack - uiBut->type set to BUT and BUTM have there menus built 
+                                                                        * opposite ways - this should be changed so that all popup-menus use the same uiBlock->direction */
+                                                                       if(but->type & BUT)
+                                                                               but= ui_but_next(but);
+                                                                       else
+                                                                               but= ui_but_prev(but);
+                                                               }
+                                                               else {
+                                                                       if(but->type & BUT)
+                                                                               but= ui_but_prev(but);
+                                                                       else
+                                                                               but= ui_but_next(but);
+                                                               }
 
                                                                if(but)
                                                                        ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
                                                        }
 
                                                        if(!but) {
-                                                               if(ELEM(event->type, UPARROWKEY, WHEELUPMOUSE))
-                                                                       bt= ui_but_last(block);
-                                                               else
-                                                                       bt= ui_but_first(block);
+                                                               if(     ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) ||
+                                                                       ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) ||
+                                                                       ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP))
+                                                               ) {
+                                                                       if((bt= ui_but_first(block)) && (bt->type & BUT)) {
+                                                                               bt= ui_but_last(block);
+                                                                       }
+                                                                       else {
+                                                                               /* keep ui_but_first() */
+                                                                       }
+                                                               }
+                                                               else {
+                                                                       if((bt= ui_but_first(block)) && (bt->type & BUT)) {
+                                                                               /* keep ui_but_first() */
+                                                                       }
+                                                                       else {
+                                                                               bt= ui_but_last(block);
+                                                                       }
+                                                               }
 
                                                                if(bt)
                                                                        ui_handle_button_activate(C, ar, bt, BUTTON_ACTIVATE);
@@ -5354,25 +5600,25 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
 
                                        break;
 
-                               case ONEKEY:    case PAD1: 
+                               case ONEKEY:    case PAD1:
                                        act= 1;
-                               case TWOKEY:    case PAD2: 
+                               case TWOKEY:    case PAD2:
                                        if(act==0) act= 2;
-                               case THREEKEY:  case PAD3: 
+                               case THREEKEY:  case PAD3:
                                        if(act==0) act= 3;
-                               case FOURKEY:   case PAD4: 
+                               case FOURKEY:   case PAD4:
                                        if(act==0) act= 4;
-                               case FIVEKEY:   case PAD5: 
+                               case FIVEKEY:   case PAD5:
                                        if(act==0) act= 5;
-                               case SIXKEY:    case PAD6: 
+                               case SIXKEY:    case PAD6:
                                        if(act==0) act= 6;
-                               case SEVENKEY:  case PAD7: 
+                               case SEVENKEY:  case PAD7:
                                        if(act==0) act= 7;
-                               case EIGHTKEY:  case PAD8: 
+                               case EIGHTKEY:  case PAD8:
                                        if(act==0) act= 8;
-                               case NINEKEY:   case PAD9: 
+                               case NINEKEY:   case PAD9:
                                        if(act==0) act= 9;
-                               case ZEROKEY:   case PAD0: 
+                               case ZEROKEY:   case PAD0:
                                        if(act==0) act= 10;
                                
                                        if((block->flag & UI_BLOCK_NUMSELECT) && event->val==KM_PRESS) {
@@ -5408,8 +5654,68 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
 
                                                retval= WM_UI_HANDLER_BREAK;
                                        }
+                                       break;
+
+                               /* Handle keystrokes on menu items */
+                               case AKEY:
+                               case BKEY:
+                               case CKEY:
+                               case DKEY:
+                               case EKEY:
+                               case FKEY:
+                               case GKEY:
+                               case HKEY:
+                               case IKEY:
+                               case JKEY:
+                               case KKEY:
+                               case LKEY:
+                               case MKEY:
+                               case NKEY:
+                               case OKEY:
+                               case PKEY:
+                               case QKEY:
+                               case RKEY:
+                               case SKEY:
+                               case TKEY:
+                               case UKEY:
+                               case VKEY:
+                               case WKEY:
+                               case XKEY:
+                               case YKEY:
+                               case ZKEY:
+                               {
+                                       if(     (event->val == KM_PRESS) &&
+                                               (event->shift == FALSE) &&
+                                               (event->ctrl == FALSE) &&
+                                               (event->oskey == FALSE)
+                                       ) {
+                                               for(but= block->buttons.first; but; but= but->next) {
+
+                                                       if(but->menu_key==event->type) {
+                                                               if(but->type == BUT) {
+                                                                       /* mainly for operator buttons */
+                                                                       ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_APPLY);
+                                                               }
+                                                               else if(ELEM(but->type, BLOCK, PULLDOWN)) {
+                                                                       /* open submenus (like right arrow key) */
+                                                                       ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_OPEN);
+                                                               }
+                                                               else if (but->type == MENU) {
+                                                                       /* activate menu items */
+                                                                       ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
+                                                               }
+                                                               else {
+                                                                       printf("Error, but->menu_key type: %d\n", but->type);
+                                                               }
 
+                                                               break;
+                                                       }
+                                               }
+
+                                               retval= WM_UI_HANDLER_BREAK;
+                                       }
                                        break;
+                               }
                        }
                }
                
@@ -5422,7 +5728,7 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
 
                                if(ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) && event->val==KM_PRESS) {
                                        if(saferct && !BLI_in_rctf(&saferct->parent, event->x, event->y)) {
-                                               if(block->flag & (UI_BLOCK_OUT_1|UI_BLOCK_KEEP_OPEN))
+                                               if(block->flag & (UI_BLOCK_OUT_1))
                                                        menu->menuretval= UI_RETURN_OK;
                                                else
                                                        menu->menuretval= UI_RETURN_OUT;
@@ -5436,10 +5742,10 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
                                menu->menuretval= UI_RETURN_CANCEL;
                        }
                        else if(ELEM(event->type, RETKEY, PADENTER) && event->val==KM_PRESS) {
-                               /* enter will always close this block, but we let the event
-                                * get handled by the button if it is activated */
+                               /* enter will always close this block, we let the event
+                                * get handled by the button if it is activated, otherwise we cancel */
                                if(!ui_but_find_activated(ar))
-                                       menu->menuretval= UI_RETURN_OK;
+                                       menu->menuretval= UI_RETURN_CANCEL;
                        }
                        else {
                                ui_mouse_motion_towards_check(block, menu, mx, my);
@@ -5463,7 +5769,7 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
 
                                        /* strict check, and include the parent rect */
                                        if(!menu->dotowards && !saferct) {
-                                               if(block->flag & (UI_BLOCK_OUT_1|UI_BLOCK_KEEP_OPEN))
+                                               if(block->flag & (UI_BLOCK_OUT_1))
                                                        menu->menuretval= UI_RETURN_OK;
                                                else
                                                        menu->menuretval= UI_RETURN_OUT;
@@ -5586,7 +5892,7 @@ static int ui_handle_menus_recursive(bContext *C, wmEvent *event, uiPopupBlockHa
 
 /* *************** UI event handlers **************** */
 
-static int ui_handler_region(bContext *C, wmEvent *event, void *userdata)
+static int ui_handler_region(bContext *C, wmEvent *event, void *UNUSED(userdata))
 {
        ARegion *ar;
        uiBut *but;
@@ -5624,7 +5930,7 @@ static int ui_handler_region(bContext *C, wmEvent *event, void *userdata)
        return retval;
 }
 
-static void ui_handler_remove_region(bContext *C, void *userdata)
+static void ui_handler_remove_region(bContext *C, void *UNUSED(userdata))
 {
        bScreen *sc;
        ARegion *ar;
@@ -5644,7 +5950,7 @@ static void ui_handler_remove_region(bContext *C, void *userdata)
                ui_apply_but_funcs_after(C);
 }
 
-static int ui_handler_region_menu(bContext *C, wmEvent *event, void *userdata)
+static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(userdata))
 {
        ARegion *ar;
        uiBut *but;