- fix numpad comma replacement which was broken since unicode input was added.
[blender.git] / source / blender / editors / interface / interface_handlers.c
index e4776cd..e49cb48 100644 (file)
@@ -107,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;
@@ -260,7 +266,7 @@ 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) {
                const int subtype= RNA_property_subtype(but->rnaprop);
@@ -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,10 @@ 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);
@@ -1252,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;
@@ -1294,29 +1383,37 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, sho
        
        /* 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;
        }
@@ -1340,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;
                }
        }
@@ -1368,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;
                        }
                } 
@@ -1642,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;
@@ -1679,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);
                        }
                }
                
@@ -1831,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:
@@ -1845,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:
@@ -1855,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:
@@ -1864,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;
                                
@@ -1892,16 +1942,33 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                break;
                }
 
-               if(event->ascii && (retval == WM_UI_HANDLER_CONTINUE)) {
+               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))
-                               if(event->type == PADPERIOD && ascii == ',')
+                       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);
+                       }
 
-                       changed= ui_textedit_type_ascii(but, data, ascii);
                        retval= WM_UI_HANDLER_BREAK;
                        
                }
@@ -1955,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;
        }
@@ -1966,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;
@@ -2152,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);
                        
@@ -2993,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;
@@ -3623,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;
@@ -3662,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;
@@ -4367,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);
@@ -4397,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;
@@ -4418,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)) {
@@ -4430,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
@@ -4441,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
@@ -4452,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
@@ -4681,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;
        }
@@ -4868,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;
 
@@ -4967,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;
@@ -5089,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) {
@@ -5112,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);
                }
        }
 }
@@ -5894,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) {
 
@@ -5914,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;