diff options
Diffstat (limited to 'source/blender/editors/interface/interface_handlers.c')
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 876 |
1 files changed, 528 insertions, 348 deletions
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index fe5a5031725..6c961179c6f 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -119,6 +119,7 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to); static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to); static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event); static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b); +static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str); #ifdef USE_KEYNAV_LIMIT static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event); @@ -138,6 +139,8 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve #define MENU_TOWARDS_MARGIN 20 /* margin in pixels */ #define MENU_TOWARDS_WIGGLE_ROOM 64 /* tolerance in pixels */ +/* drag-lock distance threshold in pixels */ +#define BUTTON_DRAGLOCK_THRESH 3 typedef enum uiButtonActivateType { BUTTON_ACTIVATE_OVER, @@ -280,7 +283,9 @@ typedef struct uiHandleButtonData { wmTimer *flashtimer; /* edited value */ - char *str, *origstr; + /* use 'ui_textedit_string_set' to assign new strings */ + char *str; + char *origstr; double value, origvalue, startvalue; float vec[3], origvec[3]; #if 0 /* UNUSED */ @@ -291,14 +296,25 @@ typedef struct uiHandleButtonData { /* tooltip */ ARegion *tooltip; wmTimer *tooltiptimer; + unsigned int tooltip_force : 1; /* auto open */ bool used_mouse; wmTimer *autoopentimer; /* text selection/editing */ - int maxlen, selextend; + /* size of 'str' (including terminator) */ + int maxlen; + /* Button text selection: + * extension direction, selextend, inside ui_do_but_TEX */ + enum { + EXTEND_NONE = 0, + EXTEND_LEFT = 1, + EXTEND_RIGHT = 2, + } selextend; float selstartx; + /* allow to realloc str/editstr and use 'maxlen' to track alloc size (maxlen + 1) */ + bool is_str_dynamic; /* number editing / dragging */ /* coords are Window/uiBlock relative (depends on the button) */ @@ -381,7 +397,6 @@ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit); static bool ui_but_contains_pt(uiBut *but, float mx, float my); static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y); static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit); -static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event); static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type); static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state); static void button_activate_exit( @@ -529,6 +544,30 @@ static bool ui_but_is_cursor_warp(uiBut *but) return false; } +/** + * Ignore mouse movements within some horizontal pixel threshold before starting to drag + */ +static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx) +{ + if (mx == data->draglastx) + return false; + + if (data->draglock) { + if (ABS(mx - data->dragstartx) <= BUTTON_DRAGLOCK_THRESH) { + return false; + } +#ifdef USE_DRAG_MULTINUM + if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) { + return false; + } +#endif + data->draglock = false; + data->dragstartx = mx; /* ignore mouse movement within drag-lock */ + } + + return true; +} + static float ui_mouse_scale_warp_factor(const bool shift) { return shift ? 0.05f : 1.0f; @@ -721,7 +760,7 @@ static void ui_apply_but_funcs_after(bContext *C) if (after.opptr) { /* free in advance to avoid leak on exit */ - opptr = *after.opptr, + opptr = *after.opptr; MEM_freeN(after.opptr); } @@ -783,7 +822,7 @@ static void ui_apply_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data if (but->type == UI_BTYPE_MENU) ui_but_value_set(but, data->value); - ui_but_update(but); + ui_but_update_edited(but); ui_apply_but_func(C, but); data->retval = but->retval; data->applied = true; @@ -803,7 +842,9 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data) else lvalue = UI_BITBUT_SET(lvalue, but->bitnr); ui_but_value_set(but, (double)lvalue); - if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) ui_but_update(but); + if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) { + ui_but_update_edited(but); + } } else { @@ -812,7 +853,9 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data) if (ELEM(but->type, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE_N, UI_BTYPE_CHECKBOX_N)) push = !push; ui_but_value_set(but, (double)push); - if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) ui_but_update(but); + if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) { + ui_but_update_edited(but); + } } ui_apply_but_func(C, but); @@ -830,9 +873,11 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu ui_apply_but_func(C, but); /* states of other row buttons */ - for (bt = block->buttons.first; bt; bt = bt->next) - if (bt != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) - ui_but_update(bt); + for (bt = block->buttons.first; bt; bt = bt->next) { + if (bt != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { + ui_but_update_edited(bt); + } + } data->retval = but->retval; data->applied = true; @@ -844,7 +889,7 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data) return; ui_but_string_set(C, but, data->str); - ui_but_update(but); + ui_but_update_edited(but); /* give butfunc a copy of the original text too. * feature used for bone renaming, channels, etc. @@ -875,10 +920,11 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data) return; } } - else + else { ui_but_value_set(but, data->value); + } - ui_but_update(but); + ui_but_update_edited(but); ui_apply_but_func(C, but); data->retval = but->retval; @@ -888,7 +934,7 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data) static void ui_apply_but_VEC(bContext *C, uiBut *but, uiHandleButtonData *data) { ui_but_v3_set(but, data->vec); - ui_but_update(but); + ui_but_update_edited(but); ui_apply_but_func(C, but); data->retval = but->retval; @@ -1199,7 +1245,7 @@ static bool ui_drag_toggle_set_xy_xy( if (is_set_but != is_set) { UI_but_execute(C, but); if (do_check) { - ui_but_update(but); + ui_but_update_edited(but); } changed = true; } @@ -2130,7 +2176,8 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB ID *id = (ID *)wmd->poin; button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); - BLI_strncpy(data->str, id->name + 2, data->maxlen); + + ui_textedit_string_set(but, data, id->name + 2); if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) { but->changed = true; @@ -2146,12 +2193,39 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB /* ******************* copy and paste ******************** */ +static void ui_but_copy_data_path(uiBut *but, const bool full_path) +{ + char *id_path; + + if (but->rnapoin.id.data == NULL) { + return; + } + + if (full_path) { + if (but->rnaprop) { + id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true); + } + else { + id_path = RNA_path_full_struct_py(&but->rnapoin); + } + } + else { + id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); + } + + if (id_path) { + WM_clipboard_text_set(id_path, false); + MEM_freeN(id_path); + } +} + /* c = copy, v = paste */ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode) { int buf_paste_len = 0; const char *buf_paste = ""; bool buf_paste_alloc = false; + bool show_report = false; /* use to display errors parsing paste input */ if (mode == 'v' && but->lock == true) { return; @@ -2186,9 +2260,9 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, } else if (mode == 'c') { /* Get many decimal places, then strip trailing zeros. - * note: too high values start to give strange results (6 or so is ok) */ + * note: too high values start to give strange results */ char buf_copy[UI_MAX_DRAW_STR]; - ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), 6); + ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX); BLI_str_rstrip_float_zero(buf_copy, '\0'); WM_clipboard_text_set(buf_copy, 0); @@ -2202,6 +2276,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, ui_but_string_set(C, but, buf_paste); button_activate_state(C, but, BUTTON_STATE_EXIT); } + else { + /* evaluating will report errors */ + show_report = true; + } } } @@ -2228,6 +2306,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, ui_but_v3_set(but, xyz); button_activate_state(C, but, BUTTON_STATE_EXIT); } + else { + WM_report(RPT_ERROR, "Paste expected 3 numbers, formatted: '[n, n, n]'"); + show_report = true; + } } } @@ -2269,6 +2351,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, button_activate_state(C, but, BUTTON_STATE_EXIT); } + else { + WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'"); + show_report = true; + } } } @@ -2288,10 +2374,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, else { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); - if (ui_but_is_utf8(but)) - BLI_strncpy_utf8(active_data->str, buf_paste, active_data->maxlen); - else - BLI_strncpy(active_data->str, buf_paste, active_data->maxlen); + ui_textedit_string_set(but, active_data, buf_paste); if (but->type == UI_BTYPE_SEARCH_MENU) { /* else uiSearchboxData.active member is not updated [#26856] */ @@ -2366,6 +2449,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, if (buf_paste_alloc) { MEM_freeN((void *)buf_paste); } + + if (show_report) { + WM_report_banner_show(); + } } /** @@ -2442,6 +2529,31 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu /* ************* in-button text selection/editing ************* */ +static void ui_textedit_string_ensure_max_length(uiBut *but, uiHandleButtonData *data, int maxlen) +{ + BLI_assert(data->is_str_dynamic); + BLI_assert(data->str == but->editstr); + + if (maxlen > data->maxlen) { + data->str = but->editstr = MEM_reallocN(data->str, sizeof(char) * maxlen); + data->maxlen = maxlen; + } +} + +static void ui_textedit_string_set(uiBut *but, uiHandleButtonData *data, const char *str) +{ + if (data->is_str_dynamic) { + ui_textedit_string_ensure_max_length(but, data, strlen(str) + 1); + } + + if (ui_but_is_utf8(but)) { + BLI_strncpy_utf8(data->str, str, data->maxlen); + } + else { + BLI_strncpy(data->str, str, data->maxlen); + } +} + static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data) { @@ -2471,7 +2583,9 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con float startx = but->rect.xmin; float starty_dummy = 0.0f; - char *origstr, password_str[UI_MAX_PASSWORD_STR]; + char password_str[UI_MAX_PASSWORD_STR]; + /* treat 'str_last' as null terminator for str, no need to modify in-place */ + const char *str = but->editstr, *str_last; ui_block_to_window_fl(data->region, but->block, &startx, &starty_dummy); @@ -2484,10 +2598,6 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con ui_but_text_password_hide(password_str, but, false); - origstr = MEM_mallocN(sizeof(char) * data->maxlen, "ui_textedit origstr"); - - BLI_strncpy(origstr, but->editstr, data->maxlen); - if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { if (but->flag & UI_HAS_ICON) { startx += UI_DPI_ICON_SIZE / aspect; @@ -2500,12 +2610,12 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con if (x < startx) { int i = but->ofs; - origstr[but->ofs] = '\0'; + str_last = &str[but->ofs]; while (i > 0) { - if (BLI_str_cursor_step_prev_utf8(origstr, but->ofs, &i)) { + if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &i)) { /* 0.25 == scale factor for less sensitivity */ - if (BLF_width(fstyle->uifont_id, origstr + i, BLF_DRAW_STR_DUMMY_MAX) > (startx - x) * 0.25f) { + if (BLF_width(fstyle->uifont_id, str + i, (str_last - str) - i) > (startx - x) * 0.25f) { break; } } @@ -2524,10 +2634,12 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con float cdist, cdist_prev = 0.0f; short pos_prev; - but->pos = pos_prev = strlen(origstr) - but->ofs; + str_last = &str[strlen(str)]; + + but->pos = pos_prev = ((str_last - str) - but->ofs); while (true) { - cdist = startx + BLF_width(fstyle->uifont_id, origstr + but->ofs, BLF_DRAW_STR_DUMMY_MAX); + cdist = startx + BLF_width(fstyle->uifont_id, str + but->ofs, (str_last - str) - but->ofs); /* check if position is found */ if (cdist < x) { @@ -2543,9 +2655,9 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con pos_i = but->pos; if (but->pos <= 0) break; - if (BLI_str_cursor_step_prev_utf8(origstr, but->ofs, &pos_i)) { + if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &pos_i)) { but->pos = pos_i; - origstr[but->pos + but->ofs] = 0; + str_last = &str[but->pos + but->ofs]; } else { break; /* unlikely but possible */ @@ -2560,8 +2672,6 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con ui_but_text_password_hide(password_str, but, true); - MEM_freeN(origstr); - fstyle->points = fstyle_points_prev; } @@ -2579,22 +2689,25 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, } /** - * This is used for both utf8 and ascii, its meant to be used for single keys, - * notice the buffer is either copied or not, so its not suitable for pasting in - * - campbell */ -static bool ui_textedit_type_buf( + * This is used for both utf8 and ascii + * + * For unicode buttons, \a buf is treated as unicode. + */ +static bool ui_textedit_insert_buf( uiBut *but, uiHandleButtonData *data, - const char *utf8_buf, int utf8_buf_len) + const char *buf, int buf_len) { - char *str; - int len; + int len = strlen(data->str); + int len_new = len - (but->selend - but->selsta) + 1; bool changed = false; - str = data->str; - len = strlen(str); + if (data->is_str_dynamic) { + ui_textedit_string_ensure_max_length(but, data, len_new + buf_len); + } - if (len - (but->selend - but->selsta) + 1 <= data->maxlen) { - int step = utf8_buf_len; + if (len_new <= data->maxlen) { + char *str = data->str; + size_t step = buf_len; /* type over the current selection */ if ((but->selend - but->selsta) > 0) { @@ -2602,9 +2715,19 @@ static bool ui_textedit_type_buf( len = strlen(str); } - if (len + step < data->maxlen) { + if ((len + step >= data->maxlen) && (data->maxlen - (len + 1) > 0)) { + if (ui_but_is_utf8(but)) { + /* shorten 'step' to a utf8 algined size that fits */ + BLI_strnlen_utf8_ex(buf, data->maxlen - (len + 1), &step); + } + else { + step = data->maxlen - (len + 1); + } + } + + if (step && (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)); + memcpy(&str[but->pos], buf, step * sizeof(char)); but->pos += step; changed = true; } @@ -2613,7 +2736,7 @@ static bool ui_textedit_type_buf( return changed; } -static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char ascii) +static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, char ascii) { char buf[2] = {ascii, '\0'}; @@ -2625,7 +2748,7 @@ static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char as } /* in some cases we want to allow invalid utf8 chars */ - return ui_textedit_type_buf(but, data, buf, 1); + return ui_textedit_insert_buf(but, data, buf, 1); } static void ui_textedit_move( @@ -2652,7 +2775,7 @@ static void ui_textedit_move( but->pos = but->selend = but->selsta; } } - data->selextend = 0; + data->selextend = EXTEND_NONE; } else { int pos_i = but->pos; @@ -2663,7 +2786,7 @@ static void ui_textedit_move( /* existing selection */ if (has_sel) { - if (data->selextend == 0) { + if (data->selextend == EXTEND_NONE) { data->selextend = EXTEND_RIGHT; } @@ -2779,48 +2902,24 @@ enum { static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const int mode) { - char *str, *pbuf; - int x; + char *pbuf; bool changed = false; - int str_len, buf_len; - - str = data->str; - str_len = strlen(str); + int buf_len; /* paste */ if (mode == UI_TEXTEDIT_PASTE) { - /* TODO, ensure UTF8 ui_but_is_utf8() - campbell */ /* extract the first line from the clipboard */ pbuf = WM_clipboard_text_get_firstline(false, &buf_len); if (pbuf) { - char buf[UI_MAX_DRAW_STR] = {0}; - unsigned int y; - - buf_len = BLI_strncpy_rlen(buf, pbuf, sizeof(buf)); - - /* paste over the current selection */ - if ((but->selend - but->selsta) > 0) { - ui_textedit_delete_selection(but, data); - str_len = strlen(str); - } - - for (y = 0; y < buf_len; y++) { - /* add contents of buffer */ - if (str_len + 1 < data->maxlen) { - for (x = data->maxlen; x > but->pos; x--) - str[x] = str[x - 1]; - str[but->pos] = buf[y]; - but->pos++; - str_len++; - str[str_len] = '\0'; - } + if (ui_but_is_utf8(but)) { + buf_len -= BLI_utf8_invalid_strip(pbuf, buf_len); } + ui_textedit_insert_buf(but, data, pbuf, buf_len); + changed = true; - } - if (pbuf) { MEM_freeN(pbuf); } } @@ -2830,7 +2929,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in int sellen = but->selend - but->selsta; char *buf = MEM_mallocN(sizeof(char) * (sellen + 1), "ui_textedit_copypaste"); - BLI_strncpy(buf, str + but->selsta, sellen + 1); + BLI_strncpy(buf, data->str + but->selsta, sellen + 1); WM_clipboard_text_set(buf, 0); MEM_freeN(buf); @@ -2934,14 +3033,21 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) /* retrieve string */ data->maxlen = ui_but_string_get_max_length(but); - data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str"); - ui_but_string_get(but, data->str, data->maxlen); + if (data->maxlen != 0) { + data->str = MEM_callocN(sizeof(char) * data->maxlen, "textedit str"); + ui_but_string_get(but, data->str, data->maxlen); + } + else { + data->is_str_dynamic = true; + data->str = ui_but_string_get_dynamic(but, &data->maxlen); + } if (ui_but_is_float(but) && !ui_but_is_unit(but)) { BLI_str_rstrip_float_zero(data->str, '\0'); } if (is_num_but) { + BLI_assert(data->is_str_dynamic == false); ui_but_convert_to_unit_alt_name(but, data->str, data->maxlen); } @@ -2949,7 +3055,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) len = strlen(data->str); data->origstr = BLI_strdupn(data->str, len); - data->selextend = 0; + data->selextend = EXTEND_NONE; data->selstartx = 0.0f; /* set cursor pos to the end of the text */ @@ -2960,7 +3066,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) /* optional searchbox */ if (but->type == UI_BTYPE_SEARCH_MENU) { - data->searchbox = ui_searchbox_create(C, data->region, but); + data->searchbox = but->search_create_func(C, data->region, but); ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */ } @@ -3323,10 +3429,10 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle } // strcpy(utf8_buf, "12345"); - changed = ui_textedit_type_buf(but, data, event->utf8_buf, utf8_buf_len); + changed = ui_textedit_insert_buf(but, data, event->utf8_buf, utf8_buf_len); } else { - changed = ui_textedit_type_ascii(but, data, ascii); + changed = ui_textedit_insert_ascii(but, data, ascii); } retval = WM_UI_HANDLER_BREAK; @@ -3346,7 +3452,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle ui_textedit_delete_selection(but, data); } if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) { - ui_textedit_type_buf( + ui_textedit_insert_buf( but, data, ime_data->str_result, ime_data->result_len); @@ -3363,7 +3469,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle ui_apply_but(C, block, but, data, true); } else { - ui_but_update(but); + ui_but_update_edited(but); } but->changed = true; @@ -3936,8 +4042,12 @@ static float ui_numedit_apply_snapf( /* snapping by 10's for float buttons is quite annoying (location, scale...), * but allow for rotations */ if (softrange >= 21.0f) { + UnitSettings *unit = but->block->unit; int unit_type = UI_but_unit_type_get(but); - if (!ELEM(unit_type, PROP_UNIT_ROTATION)) { + if ((unit_type == PROP_UNIT_ROTATION) && (unit->system_rotation != USER_UNIT_ROT_RADIANS)) { + /* pass (degrees)*/ + } + else { softrange = 20.0f; } } @@ -3993,23 +4103,10 @@ static bool ui_numedit_but_NUM( int lvalue, temp; bool changed = false; const bool is_float = ui_but_is_float(but); - - if (mx == data->draglastx) - return changed; - - /* drag-lock - prevent unwanted scroll adjustments */ - /* change value (now 3) to adjust threshold in pixels */ - if (data->draglock) { - if (abs(mx - data->dragstartx) <= 3) - return changed; -#ifdef USE_DRAG_MULTINUM - if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) { - return changed; - } -#endif - data->draglock = false; - data->dragstartx = mx; /* ignore mouse movement within drag-lock */ + /* prevent unwanted drag adjustments */ + if (ui_but_dragedit_update_mval(data, mx) == false) { + return changed; } softmin = but->softmin; @@ -4074,9 +4171,23 @@ static bool ui_numedit_but_NUM( data->draglastx = mx; } else { + float non_linear_range_limit; + float non_linear_pixel_map; + float non_linear_scale; + /* Use a non-linear mapping of the mouse drag especially for large floats (normal behavior) */ deler = 500; - if (!is_float) { + if (is_float) { + /* not needed for smaller float buttons */ + non_linear_range_limit = 11.0f; + non_linear_pixel_map = 500.0f; + } + else { + /* only scale large int buttons */ + non_linear_range_limit = 129.0f; + /* larger for ints, we dont need to fine tune them */ + non_linear_pixel_map = 250.0f; + /* prevent large ranges from getting too out of control */ if (softrange > 600) deler = powf(softrange, 0.75f); else if (softrange < 25) deler = 50.0; @@ -4084,18 +4195,19 @@ static bool ui_numedit_but_NUM( } deler /= fac; - if ((is_float == true) && (softrange > 11)) { - /* non linear change in mouse input- good for high precicsion */ - data->dragf += (((float)(mx - data->draglastx)) / deler) * ((float)abs(mx - data->dragstartx) / 500.0f); - } - else if ((is_float == false) && (softrange > 129)) { /* only scale large int buttons */ - /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */ - data->dragf += (((float)(mx - data->draglastx)) / deler) * ((float)abs(mx - data->dragstartx) / 250.0f); + if (softrange > non_linear_range_limit) { + non_linear_scale = (float)abs(mx - data->dragstartx) / non_linear_pixel_map; } else { - /*no scaling */ - data->dragf += ((float)(mx - data->draglastx)) / deler; + non_linear_scale = 1.0f; } + + if (is_float == false) { + /* at minimum, moving cursor 2 pixels should change an int button. */ + CLAMP_MIN(non_linear_scale, 0.5f * U.pixelsize); + } + + data->dragf += (((float)(mx - data->draglastx)) / deler) * non_linear_scale; CLAMP(data->dragf, 0.0f, 1.0f); data->draglastx = mx; @@ -4332,6 +4444,13 @@ static bool ui_numedit_but_SLI( /* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */ float offs; + /* prevent unwanted drag adjustments */ + if ((but->type != UI_BTYPE_SCROLL) && + (ui_but_dragedit_update_mval(data, mx) == false)) + { + return changed; + } + softmin = but->softmin; softmax = but->softmax; softrange = softmax - softmin; @@ -4511,6 +4630,10 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else { +#ifdef USE_CONT_MOUSE_CORRECT + /* reset! */ + copy_v2_fl(data->ungrab_mval, FLT_MAX); +#endif click = 1; } } @@ -6317,10 +6440,10 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) uiLayout *layout; uiStyle *style = UI_style_get_dpi(); IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); - kmi = WM_keymap_item_find_id(km, kmi_id); - + kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, true, &km); + BLI_assert(kmi != NULL); + RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); @@ -6414,7 +6537,6 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) { uiBut *but = (uiBut *)arg1; - UI_but_tooltip_timer_remove(C, but); UI_popup_block_invoke(C, menu_change_shortcut, but); } @@ -6424,9 +6546,10 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) wmKeyMap *km; wmKeyMapItem *kmi; IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); - - kmi = WM_keymap_item_find_id(km, kmi_id); + + kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, true, &km); + BLI_assert(kmi != NULL); + WM_keymap_remove_item(km, kmi); but_shortcut_name_func(C, but, 0); @@ -6435,7 +6558,6 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) { uiBut *but = (uiBut *)arg1; - UI_but_tooltip_timer_remove(C, but); UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but); } @@ -6484,8 +6606,6 @@ static bool ui_but_menu(bContext *C, uiBut *but) return false; } - UI_but_tooltip_timer_remove(C, but); - /* highly unlikely getting the label ever fails */ UI_but_string_info_get(C, but, &label, NULL); @@ -6517,7 +6637,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) /* replace/delete keyfraemes */ if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"), - ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); + ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Single Keyframe"), ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframes"), @@ -6527,7 +6647,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) } else { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframe"), - ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); + ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframe"), ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 1); } @@ -6543,26 +6663,26 @@ static bool ui_but_menu(bContext *C, uiBut *but) else if (is_anim) { if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframes"), - ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); + ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Single Keyframe"), ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); } else { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframe"), - ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); + ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1); } } if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) { if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"), - ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1); + ICON_KEY_DEHLT, "ANIM_OT_keyframe_clear_button", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"), ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 0); } else { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"), - ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1); + ICON_KEY_DEHLT, "ANIM_OT_keyframe_clear_button", "all", 1); } } @@ -6572,13 +6692,13 @@ static bool ui_but_menu(bContext *C, uiBut *but) if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Drivers"), - ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1); + ICON_X, "ANIM_OT_driver_button_remove", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Driver"), ICON_NONE, "ANIM_OT_driver_button_remove", "all", 0); } else { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Driver"), - ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1); + ICON_X, "ANIM_OT_driver_button_remove", "all", 1); } uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver"), @@ -6595,14 +6715,14 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemS(layout); if (is_array_component) { - uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"), - ICON_NONE, "ANIM_OT_driver_button_add", "all", 1); - uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single Driver"), - ICON_NONE, "ANIM_OT_driver_button_add", "all", 0); + uiItemMenuEnumO(layout, C, "ANIM_OT_driver_button_add", "mapping_type", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"), + ICON_DRIVER); } else { - uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"), - ICON_NONE, "ANIM_OT_driver_button_add", "all", 1); + uiItemMenuEnumO(layout, C, "ANIM_OT_driver_button_add", "mapping_type", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"), + ICON_DRIVER); } if (ANIM_driver_can_paste()) { @@ -6618,7 +6738,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"), - ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1); + ICON_KEYINGSET, "ANIM_OT_keyingset_button_add", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single to Keying Set"), ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 0); uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"), @@ -6626,7 +6746,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) } else { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Keying Set"), - ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1); + ICON_KEYINGSET, "ANIM_OT_keyingset_button_add", "all", 1); uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"), ICON_NONE, "ANIM_OT_keyingset_button_remove"); } @@ -6641,23 +6761,32 @@ static bool ui_but_menu(bContext *C, uiBut *but) if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"), - ICON_NONE, "UI_OT_reset_default_button", "all", 1); + ICON_LOOP_BACK, "UI_OT_reset_default_button", "all", 1); uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Single to Default Value"), ICON_NONE, "UI_OT_reset_default_button", "all", 0); } else { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"), - ICON_NONE, "UI_OT_reset_default_button", "all", 1); + ICON_LOOP_BACK, "UI_OT_reset_default_button", "all", 1); } if (is_editable /*&& is_idprop*/ && is_set) { uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"), ICON_NONE, "UI_OT_unset_property_button"); } + if (is_array_component) { + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"), + ICON_NONE, "UI_OT_copy_to_selected_button", "all", true); + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"), + ICON_NONE, "UI_OT_copy_to_selected_button", "all", false); + } + else { + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"), + ICON_NONE, "UI_OT_copy_to_selected_button", "all", true); + } + uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"), ICON_NONE, "UI_OT_copy_data_path_button"); - uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"), - ICON_NONE, "UI_OT_copy_to_selected_button"); uiItemS(layout); } @@ -6669,29 +6798,39 @@ static bool ui_but_menu(bContext *C, uiBut *but) IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; int w = uiLayoutGetWidth(layout); wmKeyMap *km; - wmKeyMapItem *kmi = NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); - - if (kmi_id) - kmi = WM_keymap_item_find_id(km, kmi_id); - - /* keyboard shortcuts */ - if ((kmi) && ISKEYBOARD(kmi->type)) { + /* We want to know if this op has a shortcut, be it hotkey or not. */ + wmKeyMapItem *kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, false, &km); + + /* We do have a shortcut, but only keyboard ones are editbale that way... */ + if (kmi) { + if (ISKEYBOARD(kmi->type)) { +#if 0 /* would rather use a block but, but gets weirdly positioned... */ + uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", + 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, ""); +#endif - /* would rather use a block but, but gets weirdly positioned... */ - //uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, ""); - - but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), - 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); - UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_HAND, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), + 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); + UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); - but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), - 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); - UI_but_func_set(but2, remove_shortcut_func, but, NULL); + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_NONE, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), + 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); + UI_but_func_set(but2, remove_shortcut_func, but, NULL); + } + else { + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_HAND, IFACE_("Non-Keyboard Shortcut"), + 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, + TIP_("Only keyboard shortcuts can be edited that way, " + "please use User Preferences otherwise")); + UI_but_flag_enable(but2, UI_BUT_DISABLED); + } } /* only show 'add' if there's a suitable key map for it to go in */ else if (WM_keymap_guess_opname(C, but->optype->idname)) { - but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"), + but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_HAND, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); UI_but_func_set(but2, popup_add_shortcut_func, but, NULL); } @@ -6714,7 +6853,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) if (UI_but_online_manual_id(but, buf, sizeof(buf))) { uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"), - ICON_NONE, "WM_OT_doc_view_manual_ui_context"); + ICON_URL, "WM_OT_doc_view_manual_ui_context"); WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); RNA_string_set(&ptr_props, "doc_id", buf); @@ -6732,6 +6871,11 @@ static bool ui_but_menu(bContext *C, uiBut *but) } } + if (but->optype) { + uiItemO(layout, NULL, + ICON_NONE, "UI_OT_copy_python_command_button"); + } + /* perhaps we should move this into (G.debug & G_DEBUG) - campbell */ if (ui_block_is_menu(but->block) == false) { uiItemFullO(layout, "UI_OT_editsource", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0); @@ -6768,6 +6912,12 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } } + /* special case, copy-data-path */ + if ((event->type == CKEY) && event->shift) { + ui_but_copy_data_path(but, event->alt != 0); + return WM_UI_HANDLER_BREAK; + } + ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v'); return WM_UI_HANDLER_BREAK; } @@ -6832,12 +6982,12 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle drivers */ else if ((event->type == DKEY) && - !IS_EVENT_MOD(event, shift, ctrl, oskey) && + !IS_EVENT_MOD(event, shift, oskey) && (event->val == KM_PRESS)) { if (event->alt) ui_but_anim_remove_driver(C); - else + else if (event->ctrl) ui_but_anim_add_driver(C); ED_region_tag_redraw(data->region); @@ -6875,7 +7025,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * /* this should become disabled button .. */ if (but->lock == true) { if (but->lockstr) { - WM_report(C, RPT_INFO, but->lockstr); + WM_report(RPT_INFO, but->lockstr); button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; } @@ -7360,7 +7510,7 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c return butover; } -static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event) +uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event) { return ui_but_find_mouse_over_ex(ar, event->x, event->y, event->ctrl != 0); } @@ -7408,6 +7558,20 @@ static bool button_modal_state(uiHandleButtonState state) BUTTON_STATE_MENU_OPEN); } +/** + * Recreate tooltip (use to update dynamic tips) + */ +void UI_but_tooltip_refresh(bContext *C, uiBut *but) +{ + uiHandleButtonData *data; + + data = but->active; + if (data && data->tooltip) { + ui_tooltip_free(C, data->tooltip); + data->tooltip = ui_tooltip_create(C, data->region, but); + } +} + /* removes tooltip timer from active but (meaning tooltip is disabled until it's reenabled again) */ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) { @@ -7444,7 +7608,7 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but) data->tooltiptimer = NULL; } - if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_BUT_TIP_FORCE)) { + if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); @@ -7513,8 +7677,14 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s else if (data->state == BUTTON_STATE_NUM_EDITING) { ui_numedit_end(but, data); - if (but->flag & UI_BUT_DRIVEN) - WM_report(C, RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup."); + if (but->flag & UI_BUT_DRIVEN) { + /* Only warn when editing stepping/dragging the value. + * No warnings should show for editing driver expressions though! + */ + if (state != BUTTON_STATE_TEXT_EDITING) { + WM_report(RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup."); + } + } if (ui_but_is_cursor_warp(but)) { @@ -7604,7 +7774,9 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA /* XXX curve is temp */ } else { - data->interactive = true; + if ((but->flag & UI_BUT_UPDATE_DELAY) == 0) { + data->interactive = true; + } } data->state = BUTTON_STATE_INIT; @@ -7964,14 +8136,12 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar) if (event->type == MOUSEMOVE) { but = ui_but_find_mouse_over(ar, event); if (but) { - if (event->alt) { + button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); + + if (event->alt && but->active) { /* display tooltips if holding alt on mouseover when tooltips are off in prefs */ - but->flag |= UI_BUT_TIP_FORCE; + but->active->tooltip_force = true; } - else { - but->flag &= ~UI_BUT_TIP_FORCE; - } - button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); } } else if (event->type == EVT_BUT_OPEN) { @@ -8145,7 +8315,6 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) case MOUSEMOVE: if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) { - ARegion *ar = data->region; but->flag |= UI_SELECT; ui_do_button(C, block, but, event); ED_region_tag_redraw(ar); @@ -9318,6 +9487,9 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle is_click_style = (block->pie_data.flags & UI_PIE_CLICK_STYLE); + /* if there's an active modal button, don't check events or outside, except for search menu */ + but = ui_but_find_active_in_region(ar); + if (menu->scrolltimer == NULL) { menu->scrolltimer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL); @@ -9333,210 +9505,214 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle dist = ui_block_calc_pie_segment(block, event_xy); - if (event->type == TIMER) { - if (event->customdata == menu->scrolltimer) { - /* deactivate initial direction after a while */ - if (duration > 0.01 * U.pie_initial_timeout) { - block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION; - } + if (but && button_modal_state(but->active->state)) { + retval = ui_handle_menu_button(C, event, menu); + } + else { + if (event->type == TIMER) { + if (event->customdata == menu->scrolltimer) { + /* deactivate initial direction after a while */ + if (duration > 0.01 * U.pie_initial_timeout) { + block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION; + } - /* handle animation */ - if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) { - uiBut *but; - double final_time = 0.01 * U.pie_animation_timeout; - float fac = duration / final_time; - float pie_radius = U.pie_menu_radius * UI_DPI_FAC; + /* handle animation */ + if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) { + double final_time = 0.01 * U.pie_animation_timeout; + float fac = duration / final_time; + float pie_radius = U.pie_menu_radius * UI_DPI_FAC; - if (fac > 1.0f) { - fac = 1.0f; - block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED; - } + if (fac > 1.0f) { + fac = 1.0f; + block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED; + } - for (but = block->buttons.first; but; but = but->next) { - if (but->pie_dir != UI_RADIAL_NONE) { - float vec[2]; - float center[2]; - - ui_but_pie_dir(but->pie_dir, vec); + for (but = block->buttons.first; but; but = but->next) { + if (but->pie_dir != UI_RADIAL_NONE) { + float vec[2]; + float center[2]; - center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f); - center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f); + ui_but_pie_dir(but->pie_dir, vec); - center[0] *= BLI_rctf_size_x(&but->rect); - center[1] *= BLI_rctf_size_y(&but->rect); - - mul_v2_fl(vec, pie_radius); - add_v2_v2(vec, center); - mul_v2_fl(vec, fac); - add_v2_v2(vec, block->pie_data.pie_center_spawned); - - BLI_rctf_recenter(&but->rect, vec[0], vec[1]); + center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f); + center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f); + + center[0] *= BLI_rctf_size_x(&but->rect); + center[1] *= BLI_rctf_size_y(&but->rect); + + mul_v2_fl(vec, pie_radius); + add_v2_v2(vec, center); + mul_v2_fl(vec, fac); + add_v2_v2(vec, block->pie_data.pie_center_spawned); + + BLI_rctf_recenter(&but->rect, vec[0], vec[1]); + } } - } - block->pie_data.alphafac = fac; + block->pie_data.alphafac = fac; - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); + } } - } - /* check pie velociy here if gesture has ended */ - if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) { - float len_sq = 10; + /* check pie velociy here if gesture has ended */ + if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) { + float len_sq = 10; - /* use a time threshold to ensure we leave time to the mouse to move */ - if (duration - block->pie_data.duration_gesture > 0.02) { - len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos); - copy_v2_v2(block->pie_data.last_pos, event_xy); - block->pie_data.duration_gesture = duration; - } + /* use a time threshold to ensure we leave time to the mouse to move */ + if (duration - block->pie_data.duration_gesture > 0.02) { + len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos); + copy_v2_v2(block->pie_data.last_pos, event_xy); + block->pie_data.duration_gesture = duration; + } - if (len_sq < 1.0f) { - uiBut *but = ui_but_find_active_in_region(menu->region); + if (len_sq < 1.0f) { + but = ui_but_find_active_in_region(menu->region); - if (but) { - return ui_but_pie_menu_apply(C, menu, but, true); + if (but) { + return ui_but_pie_menu_apply(C, menu, but, true); + } } } } - } - if (event->type == block->pie_data.event && !is_click_style) { - if (event->val != KM_RELEASE) { - ui_handle_menu_button(C, event, menu); + if (event->type == block->pie_data.event && !is_click_style) { + if (event->val != KM_RELEASE) { + ui_handle_menu_button(C, event, menu); - if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) { - block->pie_data.flags |= UI_PIE_DRAG_STYLE; - } - /* why redraw here? It's simple, we are getting many double click events here. - * Those operate like mouse move events almost */ - ED_region_tag_redraw(ar); - } - else { - /* distance from initial point */ - if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) { - block->pie_data.flags |= UI_PIE_CLICK_STYLE; + if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) { + block->pie_data.flags |= UI_PIE_DRAG_STYLE; + } + /* why redraw here? It's simple, we are getting many double click events here. + * Those operate like mouse move events almost */ + ED_region_tag_redraw(ar); } else { - uiBut *but = ui_but_find_active_in_region(menu->region); - - if (but && (U.pie_menu_confirm > 0) && - (dist >= U.pie_menu_threshold + U.pie_menu_confirm)) - { - if (but) - return ui_but_pie_menu_apply(C, menu, but, true); + /* distance from initial point */ + if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) { + block->pie_data.flags |= UI_PIE_CLICK_STYLE; } + else { + but = ui_but_find_active_in_region(menu->region); - retval = ui_but_pie_menu_apply(C, menu, but, true); + if (but && (U.pie_menu_confirm > 0) && + (dist >= U.pie_menu_threshold + U.pie_menu_confirm)) + { + if (but) + return ui_but_pie_menu_apply(C, menu, but, true); + } + + retval = ui_but_pie_menu_apply(C, menu, but, true); + } } } - } - else { - /* direction from numpad */ - RadialDirection num_dir = UI_RADIAL_NONE; + else { + /* direction from numpad */ + RadialDirection num_dir = UI_RADIAL_NONE; - switch (event->type) { - case MOUSEMOVE: - if (!is_click_style) { - float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init); + switch (event->type) { + case MOUSEMOVE: + if (!is_click_style) { + float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init); - /* here we use the initial position explicitly */ - if (len_sq > PIE_CLICK_THRESHOLD_SQ) { - block->pie_data.flags |= UI_PIE_DRAG_STYLE; - } + /* here we use the initial position explicitly */ + if (len_sq > PIE_CLICK_THRESHOLD_SQ) { + block->pie_data.flags |= UI_PIE_DRAG_STYLE; + } - /* here instead, we use the offset location to account for the initial direction timeout */ - if ((U.pie_menu_confirm > 0) && - (dist >= U.pie_menu_threshold + U.pie_menu_confirm)) - { - block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT; - copy_v2_v2(block->pie_data.last_pos, event_xy); - block->pie_data.duration_gesture = duration; + /* here instead, we use the offset location to account for the initial direction timeout */ + if ((U.pie_menu_confirm > 0) && + (dist >= U.pie_menu_threshold + U.pie_menu_confirm)) + { + block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT; + copy_v2_v2(block->pie_data.last_pos, event_xy); + block->pie_data.duration_gesture = duration; + } } - } - ui_handle_menu_button(C, event, menu); - - /* mouse move should always refresh the area for pie menus */ - ED_region_tag_redraw(ar); - break; + ui_handle_menu_button(C, event, menu); - case LEFTMOUSE: - if (is_click_style) { - if (block->pie_data.flags & UI_PIE_INVALID_DIR) { - menu->menuretval = UI_RETURN_CANCEL; - } - else { - retval = ui_handle_menu_button(C, event, menu); + /* mouse move should always refresh the area for pie menus */ + ED_region_tag_redraw(ar); + break; + + case LEFTMOUSE: + if (is_click_style) { + if (block->pie_data.flags & UI_PIE_INVALID_DIR) { + menu->menuretval = UI_RETURN_CANCEL; + } + else { + retval = ui_handle_menu_button(C, event, menu); + } } - } - break; + break; - case ESCKEY: - case RIGHTMOUSE: - menu->menuretval = UI_RETURN_CANCEL; - break; + case ESCKEY: + case RIGHTMOUSE: + menu->menuretval = UI_RETURN_CANCEL; + break; - case AKEY: - case BKEY: - case CKEY: - case DKEY: - case EKEY: - case FKEY: - case GKEY: - case HKEY: - case IKEY: - case JKEY: - case KKEY: - case LKEY: - case MKEY: - case NKEY: - case OKEY: - case PKEY: - case QKEY: - case RKEY: - case SKEY: - case TKEY: - case UKEY: - case VKEY: - case WKEY: - case XKEY: - case YKEY: - case ZKEY: - { - if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) && - !IS_EVENT_MOD(event, shift, ctrl, oskey)) + case AKEY: + case BKEY: + case CKEY: + case DKEY: + case EKEY: + case FKEY: + case GKEY: + case HKEY: + case IKEY: + case JKEY: + case KKEY: + case LKEY: + case MKEY: + case NKEY: + case OKEY: + case PKEY: + case QKEY: + case RKEY: + case SKEY: + case TKEY: + case UKEY: + case VKEY: + case WKEY: + case XKEY: + case YKEY: + case ZKEY: { - for (but = block->buttons.first; but; but = but->next) { - if (but->menu_key == event->type) { - ui_but_pie_button_activate(C, but, menu); + if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) && + !IS_EVENT_MOD(event, shift, ctrl, oskey)) + { + for (but = block->buttons.first; but; but = but->next) { + if (but->menu_key == event->type) { + ui_but_pie_button_activate(C, but, menu); + } } } + break; } - break; - } #define CASE_NUM_TO_DIR(n, d) \ case (ZEROKEY + n): case (PAD0 + n): \ { if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0 - CASE_NUM_TO_DIR(1, UI_RADIAL_SW); - CASE_NUM_TO_DIR(2, UI_RADIAL_S); - CASE_NUM_TO_DIR(3, UI_RADIAL_SE); - CASE_NUM_TO_DIR(4, UI_RADIAL_W); - CASE_NUM_TO_DIR(6, UI_RADIAL_E); - CASE_NUM_TO_DIR(7, UI_RADIAL_NW); - CASE_NUM_TO_DIR(8, UI_RADIAL_N); - CASE_NUM_TO_DIR(9, UI_RADIAL_NE); - { - but = ui_block_pie_dir_activate(block, event, num_dir); - retval = ui_but_pie_button_activate(C, but, menu); - break; - } + CASE_NUM_TO_DIR(1, UI_RADIAL_SW); + CASE_NUM_TO_DIR(2, UI_RADIAL_S); + CASE_NUM_TO_DIR(3, UI_RADIAL_SE); + CASE_NUM_TO_DIR(4, UI_RADIAL_W); + CASE_NUM_TO_DIR(6, UI_RADIAL_E); + CASE_NUM_TO_DIR(7, UI_RADIAL_NW); + CASE_NUM_TO_DIR(8, UI_RADIAL_N); + CASE_NUM_TO_DIR(9, UI_RADIAL_NE); + { + but = ui_block_pie_dir_activate(block, event, num_dir); + retval = ui_but_pie_button_activate(C, but, menu); + break; + } #undef CASE_NUM_TO_DIR - default: - retval = ui_handle_menu_button(C, event, menu); - break; + default: + retval = ui_handle_menu_button(C, event, menu); + break; + } } } @@ -9783,10 +9959,14 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata) menu_region = CTX_wm_menu(C); CTX_wm_menu_set(C, menu->region); - if (event->type == EVT_DROP) { - /* if we're handling drop event we'll want it to be handled by popup callee as well, - * so it'll be possible to perform such operations as opening .blend files by dropping - * them into blender even if there's opened popup like splash screen (sergey) + if (event->type == EVT_DROP || event->val == KM_DBL_CLICK) { + /* EVT_DROP: + * If we're handling drop event we'll want it to be handled by popup callee as well, + * so it'll be possible to perform such operations as opening .blend files by dropping + * them into blender, even if there's opened popup like splash screen (sergey). + * KM_DBL_CLICK: + * Continue in case of double click so wm_handlers_do calls handler again with KM_PRESS + * event. This is needed to ensure correct button handling for fast clicking (T47532). */ retval = WM_UI_HANDLER_CONTINUE; |