diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/editors/armature/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/armature/pose_slide.c | 387 |
2 files changed, 357 insertions, 31 deletions
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 98c050950be..7266b1b88d7 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -19,6 +19,7 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenfont ../../blentranslation ../../depsgraph ../../gpu diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 93d36abe792..9b285f06d14 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -33,6 +33,7 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_vec_types.h" #include "BKE_fcurve.h" #include "BKE_nla.h" @@ -50,15 +51,27 @@ #include "WM_types.h" #include "UI_interface.h" +#include "UI_resources.h" #include "ED_armature.h" #include "ED_keyframes_draw.h" #include "ED_markers.h" #include "ED_numinput.h" #include "ED_screen.h" +#include "ED_space_api.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" #include "armature_intern.h" +#include "BLF_api.h" + +/* Pixel distance from 0% to 100%. */ +#define SLIDE_PIXEL_DISTANCE (300 * U.dpi_fac) + /* **************************************************** */ /* == POSE 'SLIDING' TOOLS == * @@ -110,15 +123,43 @@ typedef struct tPoseSlideOp { /** unused for now, but can later get used for storing runtime settings.... */ short flag; + /* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */ + int overlay_flag; + /** which transforms/channels are affected (ePoseSlide_Channels) */ short channels; /** axis-limits for transforms (ePoseSlide_AxisLock) */ short axislock; - /** 0-1 value for determining the influence of whatever is relevant */ + /* Allow overshoot or clamp between 0% and 100%. */ + bool overshoot; + + /* Reduces percentage delta from mouse movement. */ + bool precision; + + /* Move percentage in 10% steps. */ + bool increments; + + /* Pixel value in area space where the slider starts. */ + int slider_start[2]; + + /* Draw callback handler. */ + void *draw_handle; + + /* Accumulative, unclamped and unrounded percentage. */ + float raw_percentage; + + /* 0-1 value for determining the influence of whatever is relevant. */ float percentage; - /** numeric input */ + /* Cursor position in region space. */ + int cursor_region_x; + int cursor_region_y; + + /* Last cursor position in screen space used for mouse movement delta calculation. */ + int last_cursor_x; + + /* Numeric input. */ NumInput num; struct tPoseSlideObject *ob_data_array; @@ -187,6 +228,135 @@ static const EnumPropertyItem prop_axis_lock_types[] = { /* ------------------------------------ */ +/* Draw a given string centered at the given coordinates. */ +static void draw_centered_string_with_background( + const char *string, const float x, const float y, const uchar color_bg[4], const int fontid) +{ + const int bg_margin = 5 * U.dpi_fac; + float string_pixel_size[2]; + /* Get width and height of printed string to center above ticks. */ + BLF_width_and_height( + fontid, string, sizeof(string), &string_pixel_size[0], &string_pixel_size[1]); + const unsigned char col[3] = {color_bg[0], color_bg[1], color_bg[2]}; + const rctf background_rect = {.xmin = x - string_pixel_size[0] / 2 - bg_margin, + .xmax = x + string_pixel_size[0] / 2 + bg_margin, + .ymin = y - string_pixel_size[1] / 2 - bg_margin, + .ymax = y + string_pixel_size[1] / 2 + bg_margin}; + UI_draw_roundbox_3ub_alpha(&background_rect, true, 4.0f, col, color_bg[3]); + BLF_position(fontid, x - string_pixel_size[0] / 2, y - string_pixel_size[1] / 2, 0.0f); + BLF_draw(fontid, string, sizeof(string)); +} + +/* Draw an on screen Slider for a Pose Slide Operator. */ +static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg) +{ + tPoseSlideOp *pso = arg; + + /* Only draw in region from which the Operator was started. */ + if (region != pso->region) { + return; + } + + uchar color_text[4]; + uchar color_line[4]; + uchar color_handle[4]; + uchar color_bg[4]; + + char percentage_string[256]; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* Get theme colors. Text gets a different color when the value is clamped.*/ + UI_GetThemeColor4ubv(TH_TEXT, color_text); + UI_GetThemeColor4ubv(TH_TEXT, color_line); + UI_GetThemeColor4ubv(TH_ACTIVE, color_handle); + UI_GetThemeColor4ubv(TH_HEADER, color_bg); + color_bg[3] = 160; + + /* Get the default font. */ + const uiStyle *style = UI_style_get(); + const uiFontStyle *fstyle = &style->widget; + const int fontid = fstyle->uifont_id; + BLF_color3ubv(fontid, color_text); + BLF_rotation(fontid, 0.0f); + + const float line_width = 4 * U.dpi_fac; + const float base_tick_height = 16.0 * U.dpi_fac; + const float text_offset = 24.0 * U.dpi_fac; + const float overshoot_range_delta = 0.2; + int initial_tick_percentage; + int handle_pos_x; + float overshoot_length_delta; + + if (pso->overshoot) { + initial_tick_percentage = (int)((pso->percentage - 0.5f - overshoot_range_delta) * 100); + handle_pos_x = pso->slider_start[0] + (SLIDE_PIXEL_DISTANCE / 2); + overshoot_length_delta = SLIDE_PIXEL_DISTANCE * overshoot_range_delta; + } + else { + initial_tick_percentage = 0; + handle_pos_x = pso->slider_start[0] + SLIDE_PIXEL_DISTANCE * pso->percentage; + overshoot_length_delta = 0; + } + + /* Draw main line. */ + const struct rctf main_line_rect = {.xmin = pso->slider_start[0] - overshoot_length_delta, + .xmax = pso->slider_start[0] + SLIDE_PIXEL_DISTANCE + + overshoot_length_delta, + .ymin = pso->slider_start[1] - line_width / 2, + .ymax = pso->slider_start[1] + line_width / 2}; + UI_draw_roundbox_3ub_alpha(&main_line_rect, true, 0, color_line, 255); + UI_draw_roundbox_3ub_alpha(&main_line_rect, false, 0, color_bg, 255); + + /* Draw percentage ticks. */ + const int tick_increment = 10; + const int percentage_range = pso->overshoot ? 100 + 100 * overshoot_range_delta * 2 : 100; + + /* Round initial_tick_percentage up to the next tick_increment. */ + int tick_percentage = ceil((float)initial_tick_percentage / tick_increment) * tick_increment; + + for (; tick_percentage <= initial_tick_percentage + percentage_range; + tick_percentage += tick_increment) { + const float x = handle_pos_x + + SLIDE_PIXEL_DISTANCE * (((float)tick_percentage / 100) - pso->percentage); + /* 0.5 steps are considered main ticks and are drawn thicker with + * percentage indicator string below. */ + const bool is_main_tick = tick_percentage % 50 == 0; + const float tick_height = is_main_tick ? base_tick_height : base_tick_height / 2; + + const struct rctf tick_rect = {.xmin = x - (line_width / 2), + .xmax = x + (line_width / 2), + .ymin = pso->slider_start[1] - (tick_height / 2), + .ymax = pso->slider_start[1] + (tick_height / 2)}; + + UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255); + UI_draw_roundbox_3ub_alpha(&tick_rect, false, 1, color_bg, 255); + + /* Draw percentage on main ticks. */ + if (is_main_tick) { + BLI_snprintf(percentage_string, sizeof(percentage_string), "%d%%", tick_percentage); + draw_centered_string_with_background( + percentage_string, x, pso->slider_start[1] - text_offset, color_bg, fontid); + } + } + + /* Draw handle indicating current percentage. */ + const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width), + .xmax = handle_pos_x + (line_width), + .ymin = pso->slider_start[1] - (base_tick_height / 2), + .ymax = pso->slider_start[1] + (base_tick_height / 2)}; + + UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255); + UI_draw_roundbox_3ub_alpha(&handle_rect, false, 1, color_bg, 255); + + BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100); + draw_centered_string_with_background( + percentage_string, handle_pos_x, pso->slider_start[1] + text_offset, color_bg, fontid); + + GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); +} + /* operator init */ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) { @@ -205,6 +375,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) /* set range info from property values - these may get overridden for the invoke() */ pso->percentage = RNA_float_get(op->ptr, "percentage"); + pso->raw_percentage = pso->percentage; pso->prevFrame = RNA_int_get(op->ptr, "prev_frame"); pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); @@ -257,6 +428,10 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) pso->num.val_flag[0] |= NUM_NO_NEGATIVE; pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */ + /* Register UI drawing callback. */ + pso->draw_handle = ED_region_draw_cb_activate( + pso->region->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL); + /* return status is whether we've got all the data we were requested to get */ return 1; } @@ -266,6 +441,13 @@ static void pose_slide_exit(wmOperator *op) { tPoseSlideOp *pso = op->customdata; + /* Hide Bone Overlay. */ + View3D *v3d = pso->area->spacedata.first; + v3d->overlay.flag = pso->overlay_flag; + + /* Remove UI drawing callback. */ + ED_region_draw_cb_exit(pso->region->type, pso->draw_handle); + /* if data exists, clear its data and exit */ if (pso) { /* free the temp pchan links and their data */ @@ -602,7 +784,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value) { - /* We only slide to the rest pose. So only use the default rest pose value */ + /* We only slide to the rest pose. So only use the default rest pose value. */ const int lock = pso->axislock; for (int idx = 0; idx < 3; idx++) { if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) || @@ -621,7 +803,7 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat) { - /* We only slide to the rest pose. So only use the default rest pose value */ + /* We only slide to the rest pose. So only use the default rest pose value. */ float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f}; if (!quat) { /* Axis Angle */ @@ -789,14 +971,18 @@ static void pose_slide_reset(tPoseSlideOp *pso) /* ------------------------------------ */ -/* draw percentage indicator in header */ +/* Draw percentage indicator in workspace footer. */ /* TODO: Include hints about locks here... */ -static void pose_slide_draw_status(tPoseSlideOp *pso) +static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso) { char status_str[UI_MAX_DRAW_STR]; char limits_str[UI_MAX_DRAW_STR]; char axis_str[50]; char mode_str[32]; + char overshoot_str[50]; + char precision_str[50]; + char increments_str[50]; + char bone_vis_str[50]; switch (pso->mode) { case POSESLIDE_PUSH: @@ -871,25 +1057,51 @@ static void pose_slide_draw_status(tPoseSlideOp *pso) break; } + if (pso->overshoot) { + BLI_strncpy(overshoot_str, TIP_("[E] - Disable overshoot"), sizeof(overshoot_str)); + } + else { + BLI_strncpy(overshoot_str, TIP_("E - Enable overshoot"), sizeof(overshoot_str)); + } + + if (pso->precision) { + BLI_strncpy(precision_str, TIP_("[Shift] - Precision active"), sizeof(precision_str)); + } + else { + BLI_strncpy(precision_str, TIP_("Shift - Hold for precision"), sizeof(precision_str)); + } + + if (pso->increments) { + BLI_strncpy(increments_str, TIP_("[Ctrl] - Increments active"), sizeof(increments_str)); + } + else { + BLI_strncpy(increments_str, TIP_("Ctrl - Hold for 10% increments"), sizeof(increments_str)); + } + + BLI_strncpy(bone_vis_str, TIP_("[H] - Toggle bone visibility"), sizeof(increments_str)); + if (hasNumInput(&pso->num)) { Scene *scene = pso->scene; - char str_ofs[NUM_STR_REP_LEN]; + char str_offs[NUM_STR_REP_LEN]; - outputNumInput(&pso->num, str_ofs, &scene->unit); + outputNumInput(&pso->num, str_offs, &scene->unit); - BLI_snprintf( - status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str); } else { BLI_snprintf(status_str, - sizeof(status_str), - "%s: %d %% | %s", - mode_str, - (int)(pso->percentage * 100.0f), - limits_str); + sizeof(status_str), + "%s: %d %% | %s | %s | %s | %s | %s", + mode_str, + (int)(pso->percentage * 100.0f), + limits_str, + overshoot_str, + precision_str, + increments_str, + bone_vis_str); } - ED_area_status_text(pso->area, status_str); + ED_workspace_status_text(C, status_str); } /* common code for invoke() methods */ @@ -975,24 +1187,74 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL); /* header print */ - pose_slide_draw_status(pso); + pose_slide_draw_status(C, pso); /* add a modal handler for this operator */ WM_event_add_modal_handler(C, op); + + /* Hide Bone Overlay. */ + View3D *v3d = pso->area->spacedata.first; + pso->overlay_flag = v3d->overlay.flag; + v3d->overlay.flag |= V3D_OVERLAY_HIDE_BONES; + return OPERATOR_RUNNING_MODAL; } -/* calculate percentage based on position of mouse (we only use x-axis for now. - * since this is more convenient for users to do), and store new percentage value +/* Calculate percentage based on mouse movement, clamp or round to increments if + * enabled by the user. Store the new percentage value. */ static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event) { - pso->percentage = (event->x - pso->region->winrct.xmin) / ((float)pso->region->winx); + const float percentage_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE)); + /* Reduced percentage delta in precision mode (shift held). */ + pso->raw_percentage += pso->precision ? (percentage_delta / 8) : percentage_delta; + pso->percentage = pso->raw_percentage; + pso->last_cursor_x = event->x; + /* Modulo mval so the value wraps properly in area space with the cursor. */ + if (event->mval[0] > 0) { + pso->cursor_region_x = event->mval[0] % pso->region->winx; + } + else { + pso->cursor_region_x = (event->mval[0] % pso->region->winx) + pso->region->winx; + } + pso->cursor_region_y = event->mval[1]; + + if (!pso->overshoot) { + pso->percentage = clamp_f(pso->percentage, 0, 1); + } + + if (pso->increments) { + pso->percentage = round(pso->percentage * 10) / 10; + } + RNA_float_set(op->ptr, "percentage", pso->percentage); } +/* Calculate the starting percentage so that 0% or 100% will always be in the area. */ +static void pose_slide_calculate_start_percentage(tPoseSlideOp *pso, const wmEvent *event) +{ + pso->last_cursor_x = event->x; + /* A bit of padding to both sides so the text stays on screen. */ + const int padding = 16 * U.dpi_fac; + + /* Clamp it so 0% or 100% is always on screen. */ + /* Catching edge case where slider doesn't fit in window. */ + if (padding < pso->region->winx - SLIDE_PIXEL_DISTANCE - padding) { + pso->last_cursor_x = clamp_i(pso->last_cursor_x, + pso->region->winrct.xmin + padding + SLIDE_PIXEL_DISTANCE / 2, + pso->region->winrct.xmax - padding - SLIDE_PIXEL_DISTANCE / 2); + } + else { + pso->last_cursor_x = clamp_i(pso->last_cursor_x, + pso->region->winrct.xmin + padding + SLIDE_PIXEL_DISTANCE / 2, + INT_MAX); + } + pso->slider_start[0] = (pso->region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2); + pso->slider_start[1] = 64 * U.dpi_fac; +} + /* handle an event to toggle channels mode */ static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, @@ -1056,9 +1318,12 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) case EVT_PADENTER: { if (event->val == KM_PRESS) { /* return to normal cursor and header status */ - ED_area_status_text(pso->area, NULL); + ED_workspace_status_text(C, NULL); WM_cursor_modal_restore(win); + /* Depsgraph updates + redraws. Redraw needed to remove UI. */ + pose_slide_refresh(C, pso); + /* insert keyframes as required... */ pose_slide_autoKeyframe(C, pso); pose_slide_exit(op); @@ -1073,13 +1338,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) case RIGHTMOUSE: { if (event->val == KM_PRESS) { /* return to normal cursor and header status */ - ED_area_status_text(pso->area, NULL); + ED_workspace_status_text(C, NULL); WM_cursor_modal_restore(win); /* reset transforms back to original state */ pose_slide_reset(pso); - /* depsgraph updates + redraws */ + /* Depsgraph updates + redraws.*/ pose_slide_refresh(C, pso); /* clean up temp data */ @@ -1178,10 +1443,58 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } + /* Overshoot. */ + case EVT_EKEY: { + pso->overshoot = !pso->overshoot; + do_pose_update = true; + break; + } + + /* Precision mode. */ + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: { + pso->precision = true; + do_pose_update = true; + break; + } + + /* Increments mode. */ + case EVT_LEFTCTRLKEY: + case EVT_RIGHTCTRLKEY: { + pso->increments = true; + do_pose_update = true; + break; + } + + /* Toggle Bone visibility. */ + case EVT_HKEY: { + View3D *v3d = pso->area->spacedata.first; + v3d->overlay.flag ^= V3D_OVERLAY_HIDE_BONES; + } + default: /* Some other unhandled key... */ break; } } + /* Precision and stepping only active while button is held. */ + else if (event->val == KM_RELEASE) { + switch (event->type) { + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: { + pso->precision = false; + do_pose_update = true; + break; + } + case EVT_LEFTCTRLKEY: + case EVT_RIGHTCTRLKEY: { + pso->increments = false; + do_pose_update = true; + break; + } + default: + break; + } + } else { /* unhandled event - maybe it was some view manipulation? */ /* allow to pass through */ @@ -1193,8 +1506,10 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Perform pose updates - in response to some user action * (e.g. pressing a key or moving the mouse). */ if (do_pose_update) { + pose_slide_mouse_update_percentage(pso, op, event); + /* update percentage indicator in header */ - pose_slide_draw_status(pso); + pose_slide_draw_status(C, pso); /* reset transforms (to avoid accumulation errors) */ pose_slide_reset(pso); @@ -1247,11 +1562,11 @@ static void pose_slide_opdef_properties(wmOperatorType *ot) PropertyRNA *prop; prop = RNA_def_float_factor(ot->srna, - "factor", + "percentage", 0.5f, 0.0f, 1.0f, - "Factor", + "Percentage", "Weighting factor for which keyframe is favored more", 0.0, 1.0); @@ -1310,6 +1625,8 @@ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *ev pso = op->customdata; + pose_slide_calculate_start_percentage(pso, event); + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1349,7 +1666,7 @@ void POSE_OT_push(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1370,6 +1687,8 @@ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *e pso = op->customdata; + pose_slide_calculate_start_percentage(pso, event); + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1409,7 +1728,7 @@ void POSE_OT_relax(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1429,6 +1748,8 @@ static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEven pso = op->customdata; + pso->last_cursor_x = event->x; + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1468,7 +1789,7 @@ void POSE_OT_push_rest(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1489,6 +1810,8 @@ static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEve pso = op->customdata; + pose_slide_calculate_start_percentage(pso, event); + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1528,7 +1851,7 @@ void POSE_OT_relax_rest(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1549,6 +1872,8 @@ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEven pso = op->customdata; + pose_slide_calculate_start_percentage(pso, event); + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1588,7 +1913,7 @@ void POSE_OT_breakdown(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); |