- fix numpad comma replacement which was broken since unicode input was added.
[blender.git] / source / blender / editors / interface / interface_handlers.c
index 648eee0..e49cb48 100644 (file)
@@ -81,6 +81,7 @@ static void ui_add_link(bContext *C, uiBut *from, uiBut *to);
 
 #define BUTTON_TOOLTIP_DELAY           0.500
 #define BUTTON_FLASH_DELAY                     0.020
+#define MENU_SCROLL_INTERVAL           0.1
 #define BUTTON_AUTO_OPEN_THRESH                0.3
 #define BUTTON_MOUSE_TOWARDS_THRESH    1.0
 
@@ -106,6 +107,12 @@ typedef enum uiHandleButtonState {
        BUTTON_STATE_EXIT
 } uiHandleButtonState;
 
+typedef enum uiButtonJumpType {
+       BUTTON_EDIT_JUMP_NONE,
+       BUTTON_EDIT_JUMP_DELIM,
+       BUTTON_EDIT_JUMP_ALL
+} uiButtonJumpType;
+
 typedef struct uiHandleButtonData {
        wmWindowManager *wm;
        wmWindow *window;
@@ -259,17 +266,15 @@ static int ui_is_a_warp_but(uiBut *but)
 }
 
 /* file selectors are exempt from utf-8 checks */
-static int ui_is_utf8_but(uiBut *but)
+int ui_is_but_utf8(uiBut *but)
 {
        if (but->rnaprop) {
-               int subtype= RNA_property_subtype(but->rnaprop);
-               
-               if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
-                       return TRUE;
-               }
+               const int subtype= RNA_property_subtype(but->rnaprop);
+               return !(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME));
+       }
+       else {
+               return !(but->flag & UI_BUT_NO_UTF8);
        }
-
-       return !(but->flag & UI_BUT_NO_UTF8);
 }
 
 /* ********************** button apply/revert ************************/
@@ -300,7 +305,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
                after->func_arg3= but->func_arg3;
 
                after->funcN= but->funcN;
-               after->func_argN= but->func_argN;
+               after->func_argN= MEM_dupallocN(but->func_argN);
 
                after->rename_func= but->rename_func;
                after->rename_arg1= but->rename_arg1;
@@ -404,6 +409,8 @@ static void ui_apply_but_funcs_after(bContext *C)
                        after.func(C, after.func_arg1, after.func_arg2);
                if(after.funcN)
                        after.funcN(C, after.func_argN, after.func_arg2);
+               if(after.func_argN)
+                       MEM_freeN(after.func_argN);
                
                if(after.handle_func)
                        after.handle_func(C, after.handle_func_arg, after.retval);
@@ -630,7 +637,7 @@ static void ui_apply_but_IDPOIN(bContext *C, uiBut *but, uiHandleButtonData *dat
        data->applied= 1;
 }
 
-#ifdef INTERNATIONAL
+#ifdef WITH_INTERNATIONAL
 static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *data)
 {
        ui_apply_but_func(C, but);
@@ -799,8 +806,7 @@ static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to)
        if(!act_iter) return;
 
        /* (3) add a new controller */
-       if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, NULL) & OPERATOR_FINISHED)
-       {
+       if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, NULL) & OPERATOR_FINISHED) {
                cont = (bController *)ob->controllers.last;
 
                /* (4) link the sensor->controller->actuator */
@@ -1023,7 +1029,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
                case IDPOIN:
                        ui_apply_but_IDPOIN(C, but, data);
                        break;
-#ifdef INTERNATIONAL
+#ifdef WITH_INTERNATIONAL
                case CHARTAB:
                        ui_apply_but_CHARTAB(C, but, data);
                        break;
@@ -1113,9 +1119,9 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
                if(but->poin==NULL && but->rnapoin.data==NULL);
                else if(mode=='c') {
                        if(ui_is_but_float(but))
-                               sprintf(buf, "%f", ui_get_but_val(but));
+                               BLI_snprintf(buf, sizeof(buf), "%f", ui_get_but_val(but));
                        else
-                               sprintf(buf, "%d", (int)ui_get_but_val(but));
+                               BLI_snprintf(buf, sizeof(buf), "%d", (int)ui_get_but_val(but));
 
                        WM_clipboard_text_set(buf, 0);
                }
@@ -1136,7 +1142,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
                else if(mode=='c') {
 
                        ui_get_but_vectorf(but, rgb);
-                       sprintf(buf, "[%f, %f, %f]", rgb[0], rgb[1], rgb[2]);
+                       BLI_snprintf(buf, sizeof(buf), "[%f, %f, %f]", rgb[0], rgb[1], rgb[2]);
                        WM_clipboard_text_set(buf, 0);
                        
                }
@@ -1163,7 +1169,14 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
                }
                else {
                        button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
-                       BLI_strncpy(active_data->str, buf, active_data->maxlen);
+
+                       if(ui_is_but_utf8(but)) BLI_strncpy_utf8(active_data->str, buf, active_data->maxlen);
+                       else                    BLI_strncpy(active_data->str, buf, active_data->maxlen);
+
+                       if(but->type == SEARCH_MENU) {
+                               /* else uiSearchboxData.active member is not updated [#26856] */
+                               ui_searchbox_update(C, data->searchbox, but, 1);
+                       }
                        button_activate_state(C, but, BUTTON_STATE_EXIT);
                }
        }
@@ -1231,7 +1244,7 @@ static short test_special_char(char ch)
                case ':':
                case ';':
                case '\'':
-               case '\"':
+               case '\"': // " - an extra closing one for Aligorith's text editor
                case '<':
                case '>':
                case ',':
@@ -1248,6 +1261,86 @@ static short test_special_char(char ch)
        return 0;
 }
 
+static int ui_textedit_step_next_utf8(const char *str, size_t maxlen, short *pos)
+{
+       const char *str_end= str + (maxlen + 1);
+       const char *str_pos= str + (*pos);
+       const char *str_next= BLI_str_find_next_char_utf8(str_pos, str_end);
+       if (str_next) {
+               (*pos) += (str_next - str_pos);
+               if((*pos) > maxlen) (*pos)= maxlen;
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static int ui_textedit_step_prev_utf8(const char *str, size_t UNUSED(maxlen), short *pos)
+{
+       if((*pos) > 0) {
+               const char *str_pos= str + (*pos);
+               const char *str_prev= BLI_str_find_prev_char_utf8(str, str_pos);
+               if (str_prev) {
+                       (*pos) -= (str_pos - str_prev);
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static void ui_textedit_step_utf8(const char *str, size_t maxlen,
+                                  short *pos, const char direction,
+                                  uiButtonJumpType jump)
+{
+       const short pos_prev= *pos;
+
+       if(direction) { /* right*/
+               if(jump != BUTTON_EDIT_JUMP_NONE) {
+                       /* jump between special characters (/,\,_,-, etc.),
+                        * look at function test_special_char() for complete
+                        * list of special character, ctr -> */
+                       while((*pos) < maxlen) {
+                               if (ui_textedit_step_next_utf8(str, maxlen, pos)) {
+                                       if((jump != BUTTON_EDIT_JUMP_ALL) && test_special_char(str[(*pos)])) break;
+                               }
+                               else {
+                                       break; /* unlikely but just incase */
+                               }
+                       }
+               }
+               else {
+                       ui_textedit_step_next_utf8(str, maxlen, pos);
+               }
+       }
+       else { /* left */
+               if(jump != BUTTON_EDIT_JUMP_NONE) {
+                       /* left only: compensate for index/change in direction */
+                       ui_textedit_step_prev_utf8(str, maxlen, pos);
+
+                       /* jump between special characters (/,\,_,-, etc.),
+                        * look at function test_special_char() for complete
+                        * list of special character, ctr -> */
+                       while ((*pos) > 0) {
+                               if (ui_textedit_step_prev_utf8(str, maxlen, pos)) {
+                                       if((jump != BUTTON_EDIT_JUMP_ALL) && test_special_char(str[(*pos)])) break;
+                               }
+                               else {
+                                       break;
+                               }
+                       }
+
+                       /* left only: compensate for index/change in direction */
+                       if(((*pos) != 0) && ABS(pos_prev - (*pos)) > 1) {
+                               ui_textedit_step_next_utf8(str, maxlen, pos);
+                       }
+               }
+               else {
+                       ui_textedit_step_prev_utf8(str, maxlen, pos);
+               }
+       }
+}
+
 static int ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
 {
        char *str= data->str;
@@ -1265,7 +1358,7 @@ static int ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
 /* note, but->block->aspect is used here, when drawing button style is getting scaled too */
 static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, short x)
 {
-       uiStyle *style= U.uistyles.first;       // XXX pass on as arg
+       uiStyle *style= UI_GetStyle();  // XXX pass on as arg
        uiFontStyle *fstyle = &style->widget;
        int startx= but->x1;
        char *origstr;
@@ -1285,34 +1378,42 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, sho
        else if(ELEM(but->type, TEX, SEARCH_MENU)) {
                startx += 5;
                if (but->flag & UI_HAS_ICON)
-                       startx += 16;
+                       startx += UI_DPI_ICON_SIZE;
        }
        
        /* mouse dragged outside the widget to the left */
        if (x < startx && but->ofs > 0) {       
-               int i= but->ofs;
+               short i= but->ofs;
 
                origstr[but->ofs] = 0;
                
                while (i > 0) {
-                       i--;
-                       if (BLF_width(fstyle->uifont_id, origstr+i) > (startx - x)*0.25f) break;        // 0.25 == scale factor for less sensitivity
+                       if (ui_textedit_step_prev_utf8(origstr, but->ofs, &i)) {
+                               if (BLF_width(fstyle->uifont_id, origstr+i) > (startx - x)*0.25f) break;        // 0.25 == scale factor for less sensitivity
+                       }
+                       else {
+                               break; /* unlikely but possible */
+                       }
                }
                but->ofs = i;
                but->pos = but->ofs;
        }
        /* mouse inside the widget */
        else if (x >= startx) {
-               float aspect= (but->block->aspect);
+               const float aspect_sqrt= sqrtf(but->block->aspect);
                
                but->pos= strlen(origstr)-but->ofs;
                
                /* XXX does not take zoom level into account */
-               while (startx + aspect*BLF_width(fstyle->uifont_id, origstr+but->ofs) > x) {
+               while (startx + aspect_sqrt * BLF_width(fstyle->uifont_id, origstr+but->ofs) > x) {
                        if (but->pos <= 0) break;
-                       but->pos--;
-                       origstr[but->pos+but->ofs] = 0;
-               }               
+                       if (ui_textedit_step_prev_utf8(origstr, but->ofs, &but->pos)) {
+                               origstr[but->pos+but->ofs] = 0;
+                       }
+                       else {
+                               break; /* unlikely but possible */
+                       }
+               }
                but->pos += but->ofs;
                if(but->pos<0) but->pos= 0;
        }
@@ -1336,27 +1437,31 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data,
        ui_check_but(but);
 }
 
-static int ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
+/* this is used for both utf8 and ascii, its meant to be used for single keys,
+ * notie the buffer is either copied or not, so its not suitable for pasting in
+ * - campbell */
+static int ui_textedit_type_buf(uiBut *but, uiHandleButtonData *data,
+                                const char *utf8_buf, int utf8_buf_len)
 {
        char *str;
-       int len, x, changed= 0;
+       int len, changed= 0;
 
        str= data->str;
        len= strlen(str);
 
        if(len-(but->selend - but->selsta)+1 <= data->maxlen) {
+               int step= utf8_buf_len;
+
                /* type over the current selection */
-               if ((but->selend - but->selsta) > 0)
+               if ((but->selend - but->selsta) > 0) {
                        changed= ui_textedit_delete_selection(but, data);
+                       len= strlen(str);
+               }
 
-               len= strlen(str);
-               if(len+1 < data->maxlen) {
-                       for(x= data->maxlen; x>but->pos; x--)
-                               str[x]= str[x-1];
-                       str[but->pos]= ascii;
-                       str[len+1]= '\0';
-
-                       but->pos++; 
+               if(len + step < data->maxlen) {
+                       memmove(&str[but->pos + step], &str[but->pos], (len + 1) - but->pos);
+                       memcpy(&str[but->pos], utf8_buf, step * sizeof(char));
+                       but->pos += step;
                        changed= 1;
                }
        }
@@ -1364,172 +1469,131 @@ static int ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char asc
        return changed;
 }
 
-static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int select, int jump)
+static int ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
 {
-       char *str;
-       int len;
+       char buf[2]= {ascii, '\0'};
 
-       str= data->str;
-       len= strlen(str);
+       if (ui_is_but_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
+               printf("%s: entering invalid ascii char into an ascii key (%d)\n",
+                      __func__, (int)(unsigned char)ascii);
 
-       if(direction) { /* right*/
-               /* if there's a selection */
-               if ((but->selend - but->selsta) > 0) {
-                       /* extend the selection based on the first direction taken */
-                       if(select) {
-                               if (!data->selextend) {
-                                       data->selextend = EXTEND_RIGHT;
-                               }
-                               if (data->selextend == EXTEND_RIGHT) {
-                                       but->selend++;
-                                       if (but->selend > len) but->selend = len;
-                               } else if (data->selextend == EXTEND_LEFT) {
-                                       but->selsta++;
-                                       /* if the selection start has gone past the end,
-                                       * flip them so they're in sync again */
-                                       if (but->selsta == but->selend) {
-                                               but->pos = but->selsta;
-                                               data->selextend = EXTEND_RIGHT;
-                                       }
-                               }
-                       } else {
+               return 0;
+       }
+
+       /* in some cases we want to allow invalid utf8 chars */
+       return ui_textedit_type_buf(but, data, buf, 1);
+}
+
+static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int select, uiButtonJumpType jump)
+{
+       const char *str= data->str;
+       const int len= strlen(str);
+       const int pos_prev= but->pos;
+       const int has_sel= (but->selend - but->selsta) > 0;
+
+       /* special case, quit selection and set cursor */
+       if (has_sel && !select) {
+               if (jump == BUTTON_EDIT_JUMP_ALL) {
+                       but->selsta = but->selend= but->pos = direction ? len : 0;
+               }
+               else {
+                       if (direction) {
                                but->selsta = but->pos = but->selend;
-                               data->selextend = 0;
                        }
-               } else {
-                       if(select) {
-                               /* make a selection, starting from the cursor position */
-                               int tlen;
-                               but->selsta = but->pos;
-                               
-                               but->pos++;
-                               if(but->pos > (tlen= strlen(str))) but->pos= tlen;
-                               
-                               but->selend = but->pos;
-                       } else if(jump) {
-                               /* jump betweenn special characters (/,\,_,-, etc.),
-                                * look at function test_special_char() for complete
-                                * list of special character, ctr -> */
-                               while(but->pos < len) {
-                                       but->pos++;
-                                       if(test_special_char(str[but->pos])) break;
-                               }
-                       } else {
-                               int tlen;
-                               but->pos++;
-                               if(but->pos > (tlen= strlen(str))) but->pos= tlen;
+                       else {
+                               but->pos = but->selend = but->selsta;
                        }
                }
+               data->selextend = 0;
        }
-       else { /* left */
-               /* if there's a selection */
-               if ((but->selend - but->selsta) > 0) {
-                       /* extend the selection based on the first direction taken */
-                       if(select) {
-                               if (!data->selextend) {
-                                       data->selextend = EXTEND_LEFT;
+       else {
+               ui_textedit_step_utf8(str, len, &but->pos, direction, jump);
+
+               if(select) {
+                       /* existing selection */
+                       if (has_sel) {
+
+                               if(data->selextend == 0) {
+                                       data->selextend= EXTEND_RIGHT;
                                }
-                               if (data->selextend == EXTEND_LEFT) {
-                                       but->selsta--;
-                                       if (but->selsta < 0) but->selsta = 0;
-                               } else if (data->selextend == EXTEND_RIGHT) {
-                                       but->selend--;
-                                       /* if the selection start has gone past the end,
-                                       * flip them so they're in sync again */
-                                       if (but->selsta == but->selend) {
-                                               but->pos = but->selsta;
-                                               data->selextend = EXTEND_LEFT;
+
+                               if (direction) {
+                                       if (data->selextend == EXTEND_RIGHT) {
+                                               but->selend= but->pos;
+                                       }
+                                       else {
+                                               but->selsta= but->pos;
                                        }
                                }
-                       } else {
-                               but->pos = but->selend = but->selsta;
-                               data->selextend = 0;
-                       }
-               } else {
-                       if(select) {
-                               /* make a selection, starting from the cursor position */
-                               but->selend = but->pos;
-                               
-                               but->pos--;
-                               if(but->pos<0) but->pos= 0;
-                               
-                               but->selsta = but->pos;
-                       } else if(jump) {
-                               /* jump betweenn special characters (/,\,_,-, etc.),
-                                * look at function test_special_char() for complete
-                                * list of special character, ctr -> */
-                               while(but->pos > 0){
-                                       but->pos--;
-                                       if(test_special_char(str[but->pos])) break;
+                               else {
+                                       if (data->selextend == EXTEND_LEFT) {
+                                               but->selsta= but->pos;
+                                       }
+                                       else {
+                                               but->selend= but->pos;
+                                       }
                                }
-                       } else {
-                               if(but->pos>0) but->pos--;
-                       }
-               }
-       }
-}
-
-static void ui_textedit_move_end(uiBut *but, uiHandleButtonData *data, int direction, int select)
-{
-       char *str;
 
-       str= data->str;
+                               if (but->selend < but->selsta) {
+                                       SWAP(short, but->selsta, but->selend);
+                                       data->selextend= (data->selextend == EXTEND_RIGHT) ? EXTEND_LEFT : EXTEND_RIGHT;
+                               }
 
-       if(direction) { /* right */
-               if(select) {
-                       but->selsta = but->pos;
-                       but->selend = strlen(str);
-                       data->selextend = EXTEND_RIGHT;
-               } else {
-                       but->selsta = but->selend = but->pos= strlen(str);
-               }
-       }
-       else { /* left */
-               if(select) {
-                       but->selend = but->pos;
-                       but->selsta = 0;
-                       data->selextend = EXTEND_LEFT;
-               } else {
-                       but->selsta = but->selend = but->pos= 0;
+                       } /* new selection */
+                       else {
+                               if (direction) {
+                                       data->selextend= EXTEND_RIGHT;
+                                       but->selend= but->pos;
+                                       but->selsta= pos_prev;
+                               }
+                               else {
+                                       data->selextend= EXTEND_LEFT;
+                                       but->selend= pos_prev;
+                                       but->selsta= but->pos;
+                               }
+                       }
                }
        }
 }
 
-static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int direction, int all)
+static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int direction, uiButtonJumpType jump)
 {
-       char *str;
-       int len, x, changed= 0;
+       char *str= data->str;
+       const int len= strlen(str);
 
-       str= data->str;
-       len= strlen(str);
+       int changed= 0;
 
-       if(all) {
+       if(jump == BUTTON_EDIT_JUMP_ALL) {
                if(len) changed=1;
-               str[0]= 0;
+               str[0]= '\0';
                but->pos= 0;
        }
        else if(direction) { /* delete */
                if ((but->selend - but->selsta) > 0) {
                        changed= ui_textedit_delete_selection(but, data);
                }
-               else if(but->pos>=0 && but->pos<len) {
-                       for(x=but->pos; x<len; x++)
-                               str[x]= str[x+1];
-                       str[len-1]='\0';
+               else if (but->pos>=0 && but->pos<len) {
+                       short pos= but->pos;
+                       int step;
+                       ui_textedit_step_utf8(str, len, &pos, direction, jump);
+                       step= pos - but->pos;
+                       memmove(&str[but->pos], &str[but->pos + step], (len + 1) - but->pos);
                        changed= 1;
                }
        }
        else { /* backspace */
-               if(len!=0) {
+               if (len != 0) {
                        if ((but->selend - but->selsta) > 0) {
                                changed= ui_textedit_delete_selection(but, data);
                        }
                        else if(but->pos>0) {
-                               for(x=but->pos; x<len; x++)
-                                       str[x-1]= str[x];
-                               str[len-1]='\0';
+                               short pos= but->pos;
+                               int step;
 
-                               but->pos--;
+                               ui_textedit_step_utf8(str, len, &pos, direction, jump);
+                               step= but->pos - pos;
+                               memmove(&str[but->pos - step], &str[but->pos], (len + 1) - but->pos);
+                               but->pos -= step;
                                changed= 1;
                        }
                } 
@@ -1638,19 +1702,9 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
        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;
-                       }
-               }
+               ui_convert_to_unit_alt_name(but, data->str, data->maxlen);
        }
-       
-       
+
        data->origstr= BLI_strdup(data->str);
        data->selextend= 0;
        data->selstartx= 0;
@@ -1675,12 +1729,12 @@ 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)) {
+               if(ui_is_but_utf8(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);
+                               printf("%s: invalid utf8 - stripped chars %d\n", __func__, strip);
                        }
                }
                
@@ -1827,11 +1881,11 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                }
                                break;
                        case RIGHTARROWKEY:
-                               ui_textedit_move(but, data, 1, event->shift, event->ctrl);
+                               ui_textedit_move(but, data, 1, event->shift, event->ctrl ? BUTTON_EDIT_JUMP_DELIM : BUTTON_EDIT_JUMP_NONE);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                        case LEFTARROWKEY:
-                               ui_textedit_move(but, data, 0, event->shift, event->ctrl);
+                               ui_textedit_move(but, data, 0, event->shift, event->ctrl ? BUTTON_EDIT_JUMP_DELIM : BUTTON_EDIT_JUMP_NONE);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                        case DOWNARROWKEY:
@@ -1841,7 +1895,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                }
                                /* pass on purposedly */
                        case ENDKEY:
-                               ui_textedit_move_end(but, data, 1, event->shift);
+                               ui_textedit_move(but, data, 1, event->shift, BUTTON_EDIT_JUMP_ALL);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                        case UPARROWKEY:
@@ -1851,7 +1905,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                }
                                /* pass on purposedly */
                        case HOMEKEY:
-                               ui_textedit_move_end(but, data, 0, event->shift);
+                               ui_textedit_move(but, data, 0, event->shift, BUTTON_EDIT_JUMP_ALL);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                        case PADENTER:
@@ -1860,12 +1914,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                        case DELKEY:
-                               changed= ui_textedit_delete(but, data, 1, 0);
+                               changed= ui_textedit_delete(but, data, 1, event->ctrl ? BUTTON_EDIT_JUMP_DELIM : BUTTON_EDIT_JUMP_NONE);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
 
                        case BACKSPACEKEY:
-                               changed= ui_textedit_delete(but, data, 0, event->shift);
+                               changed= ui_textedit_delete(but, data, 0, event->shift ? BUTTON_EDIT_JUMP_ALL :  (event->ctrl ? BUTTON_EDIT_JUMP_DELIM : BUTTON_EDIT_JUMP_NONE));
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                                
@@ -1874,7 +1928,6 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                if(but->autocomplete_func || data->searchbox) {
                                        changed= ui_textedit_autocomplete(C, but, data);
                                        update= 1; /* do live update for tab key */
-                                       retval= WM_UI_HANDLER_BREAK;
                                }
                                /* the hotkey here is not well defined, was G.qual so we check all */
                                else if(event->shift || event->ctrl || event->alt || event->oskey) {
@@ -1889,8 +1942,33 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                break;
                }
 
-               if(event->ascii && (retval == WM_UI_HANDLER_CONTINUE)) {
-                       changed= ui_textedit_type_ascii(but, data, event->ascii);
+               if((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)) {
+                       char ascii = event->ascii;
+                       const char *utf8_buf= event->utf8_buf;
+
+                       /* exception that's useful for number buttons, some keyboard
+                          numpads have a comma instead of a period */
+                       if(ELEM3(but->type, NUM, NUMABS, NUMSLI)) { /* could use data->min*/
+                               if(event->type == PADPERIOD && ascii == ',') {
+                                       ascii = '.';
+                                       utf8_buf= NULL; /* force ascii fallback */
+                               }
+                       }
+
+                       if(utf8_buf && utf8_buf[0]) {
+                               int utf8_buf_len= BLI_str_utf8_size(utf8_buf);
+                               /* keep this printf until utf8 is well tested */
+                               if (utf8_buf_len != 1) {
+                                       printf("%s: utf8 char '%.*s'\n", __func__, utf8_buf_len, utf8_buf);
+                               }
+
+                               // strcpy(utf8_buf, "12345");
+                               changed= ui_textedit_type_buf(but, data, event->utf8_buf, utf8_buf_len);
+                       }
+                       else {
+                               changed= ui_textedit_type_ascii(but, data, ascii);
+                       }
+
                        retval= WM_UI_HANDLER_BREAK;
                        
                }
@@ -1944,8 +2022,6 @@ static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, u
 
 static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
 {
-       float softrange, softmin, softmax;
-
        if(but->type == BUT_CURVE) {
                but->editcumap= (CurveMapping*)but->poin;
        }
@@ -1955,10 +2031,12 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
        }
        else if(ELEM3(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE)) {
                ui_get_but_vectorf(but, data->origvec);
-               VECCOPY(data->vec, data->origvec);
+               copy_v3_v3(data->vec, data->origvec);
                but->editvec= data->vec;
        }
        else {
+               float softrange, softmin, softmax;
+
                data->startvalue= ui_get_but_val(but);
                data->origvalue= data->startvalue;
                data->value= data->origvalue;
@@ -2141,15 +2219,11 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
                
                /* always set */
                but->modifier_key = 0;
-               if(event->shift)
-                       but->modifier_key |= KM_SHIFT;
-               if(event->alt)
-                       but->modifier_key |= KM_ALT;
-               if(event->ctrl)
-                       but->modifier_key |= KM_CTRL;
-               if(event->oskey)
-                       but->modifier_key |= KM_OSKEY;
-               
+               if(event->shift) but->modifier_key |= KM_SHIFT;
+               if(event->alt)   but->modifier_key |= KM_ALT;
+               if(event->ctrl)  but->modifier_key |= KM_CTRL;
+               if(event->oskey) but->modifier_key |= KM_OSKEY;
+
                ui_check_but(but);
                ED_region_tag_redraw(data->region);
                        
@@ -2298,13 +2372,13 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
                float fac= 1.0f;
                
                if(ui_is_but_unit(but)) {
-                       Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
+                       UnitSettings *unit= but->block->unit;
                        int unit_type= uiButGetUnitType(but)>>16;
 
-                       if(bUnit_IsValid(scene->unit.system, unit_type)) {
-                               fac= (float)bUnit_BaseScalar(scene->unit.system, unit_type);
+                       if(bUnit_IsValid(unit->system, unit_type)) {
+                               fac= (float)bUnit_BaseScalar(unit->system, unit_type);
                                if(ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
-                                       fac /= scene->unit.scale_length;
+                                       fac /= unit->scale_length;
                                }
                        }
                }
@@ -2312,8 +2386,8 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
                if(fac != 1.0f) {
                        /* snap in unit-space */
                        tempf /= fac;
-                       softmin /= fac;
-                       softmax /= fac;
+                       /* softmin /= fac; */ /* UNUSED */
+                       /* softmax /= fac; */ /* UNUSED */
                        softrange /= fac;
                }
 
@@ -2797,10 +2871,16 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
                        
                        tempf= data->value;
                        temp= (int)data->value;
-                       
-                       /* XXX useles "if", same result for f, uh??? */
-                       if(but->type==SLI) f= (float)(mx-but->x1)/(but->x2-but->x1);
-                       else f= (float)(mx- but->x1)/(but->x2-but->x1);
+
+#if 0
+                       if(but->type==SLI) {
+                               f= (float)(mx-but->x1)/(but->x2-but->x1); /* same as below */
+                       }
+                       else
+#endif
+                       {
+                               f= (float)(mx- but->x1)/(but->x2-but->x1);
+                       }
                        
                        f= softmin + f*softrange;
                        
@@ -2838,7 +2918,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
 
 static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
 {
-       int mx, my, click= 0;
+       int mx, my /*, click= 0 */;
        int retval= WM_UI_HANDLER_CONTINUE;
        int horizontal= (but->x2 - but->x1 > but->y2 - but->y1);
        
@@ -2860,8 +2940,10 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
                                button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
                                retval= WM_UI_HANDLER_BREAK;
                        }
-                       else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS)
+                       /* UNUSED - otherwise code is ok, add back if needed */
+                       /* else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS)
                                click= 1;
+                       */
                }
        }
        else if(data->state == BUTTON_STATE_NUM_EDITING) {
@@ -2974,6 +3056,9 @@ static int ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data, int mx, i
        /* button is presumed square */
        /* if mouse moves outside of sphere, it does negative normal */
 
+       /* note that both data->vec and data->origvec should be normalized
+        * else we'll get a hamrless but annoying jump when first clicking */
+
        fp= data->origvec;
        rad= (but->x2 - but->x1);
        radsq= rad*rad;
@@ -3450,13 +3535,13 @@ static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap,
        CurveMapping *cumap= (CurveMapping*)but->poin;
        CurveMap *cuma= cumap->cm+cumap->cur;
        CurveMapPoint *cmp= cuma->curve;
-       float fx, fy, zoomx, zoomy, offsx, offsy;
+       float fx, fy, zoomx, zoomy /*, offsx, offsy */ /* UNUSED */;
        int a, changed= 0;
 
        zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin);
        zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin);
-       offsx= cumap->curr.xmin;
-       offsy= cumap->curr.ymin;
+       /* offsx= cumap->curr.xmin; */
+       /* offsy= cumap->curr.ymin; */
 
        if(snap) {
                float d[2];
@@ -3604,7 +3689,7 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
                        if(sel!= -1) {
                                /* ok, we move a point */
                                /* deselect all if this one is deselect. except if we hold shift */
-                               if(event->shift==0) {
+                               if(event->shift == FALSE) {
                                        for(a=0; a<cuma->totpoint; a++)
                                                cmp[a].flag &= ~SELECT;
                                        cmp[sel].flag |= SELECT;
@@ -3643,7 +3728,7 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
 
                                if(!data->dragchange) {
                                        /* deselect all, select one */
-                                       if(event->shift==0) {
+                                       if(event->shift == FALSE) {
                                                for(a=0; a<cuma->totpoint; a++)
                                                        cmp[a].flag &= ~SELECT;
                                                cmp[data->dragsel].flag |= SELECT;
@@ -3659,6 +3744,9 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
                return WM_UI_HANDLER_BREAK;
        }
 
+       /* UNUSED but keep for now */
+       (void)changed;
+
        return WM_UI_HANDLER_CONTINUE;
 }
 
@@ -3671,14 +3759,14 @@ static int in_scope_resize_zone(uiBut *but, int UNUSED(x), int y)
 static int ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx, int my)
 {
        Histogram *hist = (Histogram *)but->poin;
-       rcti rect;
+       /* rcti rect; */
        int changed= 1;
-       float dx, dy, yfac=1.f;
+       float /* dx, */ dy, yfac=1.f; /* UNUSED */
        
-       rect.xmin= but->x1; rect.xmax= but->x2;
-       rect.ymin= but->y1; rect.ymax= but->y2;
+       /* rect.xmin= but->x1; rect.xmax= but->x2; */
+       /* rect.ymin= but->y1; rect.ymax= but->y2; */
        
-       dx = mx - data->draglastx;
+       /* dx = mx - data->draglastx; */ /* UNUSED */
        dy = my - data->draglasty;
        
        
@@ -3754,14 +3842,14 @@ static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandle
 static int ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx, int my)
 {
        Scopes *scopes = (Scopes *)but->poin;
-       rcti rect;
+       /* rcti rect; */
        int changed= 1;
-       float dx, dy, yfac=1.f;
+       float /* dx, */ dy /* , yfac=1.f */; /* UNUSED */
 
-       rect.xmin= but->x1; rect.xmax= but->x2;
-       rect.ymin= but->y1; rect.ymax= but->y2;
+       /* rect.xmin= but->x1; rect.xmax= but->x2; */
+       /* rect.ymin= but->y1; rect.ymax= but->y2; */
 
-       dx = mx - data->draglastx;
+       /* dx = mx - data->draglastx; */ /* UNUSED */
        dy = my - data->draglasty;
 
 
@@ -3770,7 +3858,7 @@ static int ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx,
                scopes->wavefrm_height = (but->y2 - but->y1) + (data->dragstarty - my);
        } else {
                /* scale waveform values */
-               yfac = scopes->wavefrm_yfac;
+               /* yfac = scopes->wavefrm_yfac; */ /* UNUSED */
                scopes->wavefrm_yfac += dy/200.0f;
 
                CLAMP(scopes->wavefrm_yfac, 0.5f, 2.f);
@@ -3837,12 +3925,12 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB
 static int ui_numedit_but_VECTORSCOPE(uiBut *but, uiHandleButtonData *data, int mx, int my)
 {
        Scopes *scopes = (Scopes *)but->poin;
-       rcti rect;
+       /* rcti rect; */
        int changed= 1;
        /* float dx, dy; */
 
-       rect.xmin= but->x1; rect.xmax= but->x2;
-       rect.ymin= but->y1; rect.ymax= but->y2;
+       /* rect.xmin= but->x1; rect.xmax= but->x2; */
+       /* rect.ymin= but->y1; rect.ymax= but->y2; */
 
        /* dx = mx - data->draglastx; */
        /* dy = my - data->draglasty; */
@@ -3902,7 +3990,7 @@ static int ui_do_but_VECTORSCOPE(bContext *C, uiBlock *block, uiBut *but, uiHand
        return WM_UI_HANDLER_CONTINUE;
 }
 
-#ifdef INTERNATIONAL
+#ifdef WITH_INTERNATIONAL
 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 */
@@ -4012,12 +4100,9 @@ static int ui_do_but_CHARTAB(bContext *UNUSED(C), uiBlock *UNUSED(block), uiBut
 
 
 static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
-{
-       ARegion *ar= CTX_wm_region(C);
-       
-       but->linkto[0]= event->x-ar->winrct.xmin;
-       but->linkto[1]= event->y-ar->winrct.ymin;
-       
+{      
+       VECCOPY2D(but->linkto, event->mval);
+
        if(data->state == BUTTON_STATE_HIGHLIGHT) {
                if(event->type == LEFTMOUSE && event->val==KM_PRESS) {
                        button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE);
@@ -4052,7 +4137,6 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
                
                /* complex code to change name of button */
                if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
-                       wmKeyMap *km= NULL;
                        char *butstr_orig;
 
                        // XXX but->str changed... should not, remove the hotkey from it
@@ -4065,10 +4149,6 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
                        but->str= but->strdata;
 
                        ui_check_but(but);
-
-                       /* 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 */
@@ -4080,19 +4160,20 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
 
 static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        uiBlock *block;
        uiBut *but = (uiBut *)arg;
        wmKeyMap *km;
        wmKeyMapItem *kmi;
        PointerRNA ptr;
        uiLayout *layout;
-       uiStyle *style= U.uistyles.first;
+       uiStyle *style= UI_GetStyle();
        IDProperty *prop= (but->opptr)? but->opptr->data: NULL;
        int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, 1, &km);
 
        kmi = WM_keymap_item_find_id(km, kmi_id);
        
-       RNA_pointer_create(NULL, &RNA_KeyMapItem, kmi, &ptr);
+       RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
        
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
@@ -4111,27 +4192,34 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
 
 static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        uiBlock *block;
        uiBut *but = (uiBut *)arg;
        wmKeyMap *km;
        wmKeyMapItem *kmi;
        PointerRNA ptr;
        uiLayout *layout;
-       uiStyle *style= U.uistyles.first;
+       uiStyle *style= UI_GetStyle();
        IDProperty *prop= (but->opptr)? but->opptr->data: NULL;
+       int kmi_id;
        
        /* XXX this guess_opname can potentially return a different keymap than being found on adding later... */
        km = WM_keymap_guess_opname(C, but->optype->idname);            
        kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0);
+       kmi_id = kmi->id;
 
-       if (prop) {
+       /* copy properties, prop can be NULL for reset */       
+       if(prop)
                prop= IDP_CopyProperty(prop);
-       }
-
-       /* prop can be NULL */  
        WM_keymap_properties_reset(kmi, prop);
 
-       RNA_pointer_create(NULL, &RNA_KeyMapItem, kmi, &ptr);
+       /* update and get pointers again */
+       WM_keyconfig_update(wm);
+
+       km = WM_keymap_guess_opname(C, but->optype->idname);            
+       kmi = WM_keymap_item_find_id(km, kmi_id);
+
+       RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
 
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
@@ -4212,6 +4300,7 @@ static int ui_but_menu(bContext *C, uiBut *but)
                
                /* Keyframes */
                if(but->flag & UI_BUT_ANIMATED_KEY) {
+                       /* replace/delete keyfraemes */
                        if(length) {
                                uiItemBooleanO(layout, "Replace Keyframes", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
                                uiItemBooleanO(layout, "Replace Single Keyframe", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0);
@@ -4222,6 +4311,11 @@ static int ui_but_menu(bContext *C, uiBut *but)
                                uiItemBooleanO(layout, "Replace Keyframe", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0);
                                uiItemBooleanO(layout, "Delete Keyframe", ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 0);
                        }
+                       
+                       /* keyframe settings */
+                       uiItemS(layout);
+                       
+                       
                }
                else if(but->flag & UI_BUT_DRIVEN);
                else if(is_anim) {
@@ -4264,6 +4358,7 @@ static int ui_but_menu(bContext *C, uiBut *but)
                }
                
                /* Keying Sets */
+               // TODO: check on modifyability of Keying Set when doing this
                if(is_anim) {
                        uiItemS(layout);
 
@@ -4338,7 +4433,7 @@ static int ui_but_menu(bContext *C, uiBut *but)
                PointerRNA ptr_props;
 
                if(but->rnapoin.data && but->rnaprop) {
-                       sprintf(buf, "%s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
+                       BLI_snprintf(buf, sizeof(buf), "%s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
 
                        WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
                        RNA_string_set(&ptr_props, "doc_id", buf);
@@ -4368,6 +4463,9 @@ static int ui_but_menu(bContext *C, uiBut *but)
                }
        }
 
+       /* perhaps we should move this into (G.f & G_DEBUG) - campbell */
+       uiItemFullO(layout, "UI_OT_editsource", "Edit Source", ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0);
+
        uiPupMenuEnd(C, pup);
 
        return 1;
@@ -4389,7 +4487,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                /* 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))
+               ((event->prevval != KM_PRESS) || (ISKEYMODIFIER(event->prevtype)) || (event->type == EVT_DROP))
        ) {
                /* handle copy-paste */
                if(ELEM(event->type, CKEY, VKEY) && event->val==KM_PRESS && (event->ctrl || event->oskey)) {
@@ -4401,7 +4499,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                        ui_but_drop     (C, event, but, data);
                }
                /* handle keyframing */
-               else if(event->type == IKEY && !ELEM3(1, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) {
+               else if(event->type == IKEY && !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) {
                        if(event->alt)
                                ui_but_anim_delete_keyframe(C);
                        else
@@ -4412,7 +4510,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                        return WM_UI_HANDLER_BREAK;
                }
                /* handle drivers */
-               else if(event->type == DKEY && !ELEM3(1, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) {
+               else if(event->type == DKEY && !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) {
                        if(event->alt)
                                ui_but_anim_remove_driver(C);
                        else
@@ -4423,7 +4521,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                        return WM_UI_HANDLER_BREAK;
                }
                /* handle keyingsets */
-               else if(event->type == KKEY && !ELEM3(1, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) {
+               else if(event->type == KKEY && !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) {
                        if(event->alt)
                                ui_but_anim_remove_keyingset(C);
                        else
@@ -4435,10 +4533,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                }
                /* reset to default */
                /* 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) */
+               else if(ELEM(event->type, DELKEY, PADPERIOD) && event->val == KM_PRESS) {
+                       /* ctrl+del - reset active button; del - reset a whole array*/
                        if (!(ELEM3(but->type, HSVCIRCLE, HSVCUBE, HISTOGRAM)))
-                               ui_set_but_default(C, but, !event->ctrl);
+                               ui_set_but_default(C, !event->ctrl);
                }
                /* handle menu */
                else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) {
@@ -4555,7 +4653,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
        case HSVCIRCLE:
                retval= ui_do_but_HSVCIRCLE(C, block, but, data, event);
                break;
-#ifdef INTERNATIONAL
+#ifdef WITH_INTERNATIONAL
        case CHARTAB:
                retval= ui_do_but_CHARTAB(C, block, but, data, event);
                break;
@@ -4652,7 +4750,7 @@ static int ui_mouse_inside_region(ARegion *ar, int x, int y)
        /* check if the mouse is in the region */
        if(!BLI_in_rcti(&ar->winrct, x, y)) {
                for(block=ar->uiblocks.first; block; block=block->next)
-                       block->auto_open= 0;
+                       block->auto_open= FALSE;
                
                return 0;
        }
@@ -4736,6 +4834,8 @@ static uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
                                continue;
                        if(but->flag & UI_HIDDEN)
                                continue;
+                       if(but->flag & UI_SCROLLED)
+                               continue;
                        if(ui_but_contains_pt(but, mx, my))
                                butover= but;
                }
@@ -4837,8 +4937,8 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
                        if(data->used_mouse && !data->autoopentimer) {
                                int time;
 
-                               if(but->block->auto_open==2) time= 1;    // test for toolbox
-                               else if((but->block->flag & UI_BLOCK_LOOP && but->type != BLOCK) || but->block->auto_open) time= 5*U.menuthreshold2;
+                               if(but->block->auto_open==TRUE) time= 1;    // test for toolbox
+                               else if((but->block->flag & UI_BLOCK_LOOP && but->type != BLOCK) || but->block->auto_open==TRUE) time= 5*U.menuthreshold2;
                                else if(U.uiflag & USER_MENUOPENAUTO) time= 5*U.menuthreshold1;
                                else time= -1;
 
@@ -4894,7 +4994,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
                }
                else {
                        if(button_modal_state(data->state))
-                               WM_event_remove_ui_handler(&data->window->modalhandlers, ui_handler_region_menu, NULL, data);
+                               WM_event_remove_ui_handler(&data->window->modalhandlers, ui_handler_region_menu, NULL, data, 1); /* 1 = postpone free */
                }
        }
        
@@ -4936,9 +5036,9 @@ 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
         * in between going over to the other button, but only for a short while */
-       if(type == BUTTON_ACTIVATE_OVER && but->block->auto_open)
+       if(type == BUTTON_ACTIVATE_OVER && but->block->auto_open==TRUE)
                if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer())
-                       but->block->auto_open= 0;
+                       but->block->auto_open= FALSE;
 
        if(type == BUTTON_ACTIVATE_OVER) {
                data->used_mouse= 1;
@@ -5058,19 +5158,17 @@ void ui_button_active_free(const bContext *C, uiBut *but)
        }
 }
 
-/* helper function for insert keyframe, reset to default, etc operators */
-void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+/* returns the active button with an optional checking function */
+static uiBut *ui_context_button_active(const bContext *C, int (*but_check_cb)(uiBut *))
 {
-       ARegion *ar= CTX_wm_region(C);
+       uiBut *but_found= NULL;
 
-       memset(ptr, 0, sizeof(*ptr));
-       *prop= NULL;
-       *index= 0;
+       ARegion *ar= CTX_wm_region(C);
 
        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) {
@@ -5081,25 +5179,70 @@ void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct P
                        }
                }
 
-               if(activebut && activebut->rnapoin.data) {
+               if(activebut && (but_check_cb == NULL || but_check_cb(activebut))) {
                        uiHandleButtonData *data= activebut->active;
 
-                       /* found RNA button */
-                       *ptr= activebut->rnapoin;
-                       *prop= activebut->rnaprop;
-                       *index= activebut->rnaindex;
+                       but_found= activebut;
 
                        /* recurse into opened menu, like colorpicker case */
                        if(data && data->menu && (ar != data->menu->region)) {
                                ar = data->menu->region;
                        }
                        else {
-                               return;
+                               return but_found;
                        }
                }
                else {
                        /* no active button */
-                       return;
+                       return but_found;
+               }
+       }
+
+       return but_found;
+}
+
+static int ui_context_rna_button_active_test(uiBut *but)
+{
+       return (but->rnapoin.data != NULL);
+}
+static uiBut *ui_context_rna_button_active(const bContext *C)
+{
+       return ui_context_button_active(C, ui_context_rna_button_active_test);
+}
+
+uiBut *uiContextActiveButton(const struct bContext *C)
+{
+       return ui_context_button_active(C, NULL);
+}
+
+/* helper function for insert keyframe, reset to default, etc operators */
+void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
+{
+       uiBut *activebut= ui_context_rna_button_active(C);
+
+       memset(ptr, 0, sizeof(*ptr));
+
+       if(activebut && activebut->rnapoin.data) {
+               *ptr= activebut->rnapoin;
+               *prop= activebut->rnaprop;
+               *index= activebut->rnaindex;
+       }
+       else {
+               *prop= NULL;
+               *index= 0;
+       }
+}
+
+void uiContextActivePropertyHandle(bContext *C)
+{
+       uiBut *activebut= ui_context_rna_button_active(C);
+       if(activebut) {
+               /* TODO, look into a better way to handle the button change
+                * currently this is mainly so reset defaults works for the
+                * operator redo panel - campbell */
+               uiBlock *block= activebut->block;
+               if (block->handle_func) {
+                       block->handle_func(C, block->handle_func_arg, 0);
                }
        }
 }
@@ -5524,10 +5667,6 @@ static int ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *men
        int closer;
 
        if(!menu->dotowards) return 0;
-       if((block->direction & UI_TOP) || (block->direction & UI_DOWN)) {
-               menu->dotowards= 0;
-               return menu->dotowards;
-       }
 
        /* verify that we are moving towards one of the edges of the
         * menu block, in other words, in the triangle formed by the
@@ -5569,6 +5708,76 @@ static int ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *men
        return menu->dotowards;
 }
 
+static char ui_menu_scroll_test(uiBlock *block, int my)
+{
+       if(block->flag & (UI_BLOCK_CLIPTOP|UI_BLOCK_CLIPBOTTOM)) {
+               if(block->flag & UI_BLOCK_CLIPTOP) 
+                       if(my > block->maxy-14)
+                               return 't';
+               if(block->flag & UI_BLOCK_CLIPBOTTOM)
+                       if(my < block->miny+14)
+                               return 'b';
+       }
+       return 0;
+}
+
+static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my)
+{
+       char test= ui_menu_scroll_test(block, my);
+       
+       if(test) {
+               uiBut *b1= block->buttons.first;
+               uiBut *b2= block->buttons.last;
+               uiBut *bnext;
+               uiBut *bprev;
+               int dy= 0;
+               
+               /* get first and last visible buttons */
+               while(b1 && ui_but_next(b1) && (b1->flag & UI_SCROLLED))
+                       b1= ui_but_next(b1);
+               while(b2 && ui_but_prev(b2) && (b2->flag & UI_SCROLLED))
+                       b2= ui_but_prev(b2);
+               /* skips separators */
+               bnext= ui_but_next(b1);
+               bprev= ui_but_prev(b2);
+               
+               if(bnext==NULL || bprev==NULL)
+                       return 0;
+               
+               if(test=='t') {
+                       /* bottom button is first button */
+                       if(b1->y1 < b2->y1)
+                               dy= bnext->y1 - b1->y1;
+                       /* bottom button is last button */
+                       else 
+                               dy= bprev->y1 - b2->y1;
+               }
+               else if(test=='b') {
+                       /* bottom button is first button */
+                       if(b1->y1 < b2->y1)
+                               dy= b1->y1 - bnext->y1;
+                       /* bottom button is last button */
+                       else 
+                               dy= b2->y1 - bprev->y1;
+               }
+               if(dy) {
+                       
+                       for(b1= block->buttons.first; b1; b1= b1->next) {
+                               b1->y1 -= dy;
+                               b1->y2 -= dy;
+                       }
+                       /* set flags again */
+                       ui_popup_block_scrolltest(block);
+                       
+                       ED_region_tag_redraw(ar);
+                       
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
+
 static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int UNUSED(topmenu))
 {
        ARegion *ar;
@@ -5600,11 +5809,22 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                 * and don't handle events */
                ui_mouse_motion_towards_init(menu, mx, my, 1);
        }
-       else if(event->type != TIMER) {
+       else if(event->type == TIMER) {
+               if(event->customdata == menu->scrolltimer)
+                       ui_menu_scroll(ar, block, my);
+       }
+       else {
                /* for ui_mouse_motion_towards_block */
-               if(event->type == MOUSEMOVE)
+               if(event->type == MOUSEMOVE) {
                        ui_mouse_motion_towards_init(menu, mx, my, 0);
-
+                       
+                       /* add menu scroll timer, if needed */
+                       if(ui_menu_scroll_test(block, my))
+                               if(menu->scrolltimer==NULL)
+                                       menu->scrolltimer= 
+                                       WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, MENU_SCROLL_INTERVAL);
+               }
+               
                /* first block own event func */
                if(block->block_event_func && block->block_event_func(C, block, event));
                /* events not for active search menu button */
@@ -5786,9 +6006,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                case ZKEY:
                                {
                                        if(     (event->val == KM_PRESS) &&
-                                               (event->shift == FALSE) &&
-                                               (event->ctrl == FALSE) &&
-                                               (event->oskey == FALSE)
+                                           (event->shift == FALSE) &&
+                                           (event->ctrl ==  FALSE) &&
+                                           (event->oskey == FALSE)
                                        ) {
                                                for(but= block->buttons.first; but; but= but->next) {
 
@@ -5806,7 +6026,7 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                                                        ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
                                                                }
                                                                else {
-                                                                       printf("Error, but->menu_key type: %d\n", but->type);
+                                                                       printf("%s: error, but->menu_key type: %d\n", __func__, but->type);
                                                                }
 
                                                                break;
@@ -6150,7 +6370,7 @@ static void ui_handler_remove_popup(bContext *C, void *userdata)
 
 void UI_add_region_handlers(ListBase *handlers)
 {
-       WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL);
+       WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, 0);
        WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL);
 }
 
@@ -6161,7 +6381,7 @@ void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *
 
 void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup)
 {
-       WM_event_remove_ui_handler(handlers, ui_handler_popup, ui_handler_remove_popup, popup);
+       WM_event_remove_ui_handler(handlers, ui_handler_popup, ui_handler_remove_popup, popup, 0);
 }