Transform: support navigation while transforming in 3D view

Implements a new option in keymap settings:
- "Navigate during Transform"

Note that with the option enabled, the keymap changes as follows:

|Modal Map (Blender):| Conflict: | Current: | New:
|---|---|---|---
| Increase Proportional Influence | VIEW3D_OT_zoom | Wheel Down | Alt Wheel Down
| Decrease Proportional Influence | VIEW3D_OT_zoom | Wheel Up | Alt Wheel Up
| Adjust Proportional Influence | VIEW3D_OT_rotate | Mouse/Trackpad Pan | Alt Mouse/Trackpad Pan
| Increase Max AutoIK Chain Length | VIEW3D_OT_zoom | Wheel Down | Alt Wheel Down
| Decrease Max AutoIK Chain Length | VIEW3D_OT_zoom | Wheel Up | Alt Wheel Up
| Automatic Constraint | VIEW3D_OT_rotate | Middle Mouse | Alt Middle Mouse
| Automatic Constraint Plane | VIEW3D_OT_move | Shift Middle Mouse | Shift Alt Middle Mouse

Design Task: #106008
Pull Request: https://projects.blender.org/blender/blender/pulls/105764
This commit is contained in:
Germano Cavalcante
2023-05-19 23:45:27 +02:00
committed by Germano Cavalcante
parent 2ce365efc7
commit 33c13ae6e3
8 changed files with 114 additions and 33 deletions

View File

@@ -250,6 +250,15 @@ class Prefs(bpy.types.KeyConfigPreferences):
update=update_fn,
)
use_transform_navigation: BoolProperty(
name="Navigate during Transform",
description=(
"Enable view navigation while using transform operators. "
"Proportional Influence, Automatic Constraints and Auto IK Chain Length shortcuts will require holding Alt key"),
default=False,
update=update_fn,
)
def draw(self, layout):
from bpy import context
@@ -313,6 +322,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
sub.prop(self, "use_v3d_tab_menu")
sub.prop(self, "use_pie_click_drag")
sub.prop(self, "use_v3d_shade_ex_pie")
sub.prop(self, "use_transform_navigation")
# File Browser settings.
col = layout.column()
@@ -365,6 +375,7 @@ def load():
use_alt_click_leader=kc_prefs.use_alt_click_leader,
use_pie_click_drag=kc_prefs.use_pie_click_drag,
use_file_single_click=kc_prefs.use_file_single_click,
use_transform_navigation=kc_prefs.use_transform_navigation,
),
)

View File

@@ -93,6 +93,8 @@ class Params:
# Since this means with RMB select enabled in edit-mode for e.g.
# `Ctrl-LMB` would be caught by box-select instead of add/extrude.
"tool_maybe_tweak_event",
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
"use_transform_navigation",
)
def __init__(
@@ -119,6 +121,7 @@ class Params:
use_file_single_click=False,
v3d_tilde_action='VIEW',
v3d_alt_mmb_drag_action='RELATIVE',
use_transform_navigation=False,
):
from sys import platform
self.apple = (platform == 'darwin')
@@ -209,6 +212,7 @@ class Params:
self.pie_value = 'CLICK_DRAG' if use_pie_click_drag else 'PRESS'
self.tool_tweak_event = {"type": self.tool_mouse, "value": 'CLICK_DRAG'}
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
self.use_transform_navigation = use_transform_navigation
# ------------------------------------------------------------------------------
@@ -1312,7 +1316,7 @@ def km_uv_editor(params):
{"properties": [("extend", True)]}),
])
# 3D cursor
# 2D cursor
if params.cursor_tweak_event:
items.extend([
("uv.cursor_set", params.cursor_set_event, None),
@@ -1581,13 +1585,16 @@ def km_view3d(params):
# Transform.
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
op_tool_optional(
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
("transform.translate", {"type": 'G', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
(op_tool_cycle, "builtin.move"), params),
op_tool_optional(
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
("transform.rotate", {"type": 'R', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
(op_tool_cycle, "builtin.rotate"), params),
op_tool_optional(
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
("transform.resize", {"type": 'S', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
(op_tool_cycle, "builtin.scale"), params),
op_tool_optional(
("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None),
@@ -4681,10 +4688,13 @@ def km_paint_curve(params):
("paintcurve.delete_point", {"type": 'DEL', "value": 'PRESS'}, None),
("paintcurve.draw", {"type": 'RET', "value": 'PRESS'}, None),
("paintcurve.draw", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None),
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
("transform.translate", {"type": 'G', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
("transform.translate", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
("transform.rotate", {"type": 'R', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
("transform.resize", {"type": 'S', "value": 'PRESS'},
{"properties": [("allow_navigation", params.use_transform_navigation)]}),
])
return keymap
@@ -5844,7 +5854,7 @@ def km_eyedropper_colorramp_pointsampling_map(_params):
return keymap
def km_transform_modal_map(_params):
def km_transform_modal_map(params):
items = []
keymap = (
"Transform Modal Map",
@@ -5884,24 +5894,24 @@ def km_transform_modal_map(_params):
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY', "alt": params.use_transform_navigation}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "repeat": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": params.use_transform_navigation}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
("INSERTOFS_TOGGLE_DIR", {"type": 'T', "value": 'PRESS'}, None),
("NODE_ATTACH_ON", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
("NODE_ATTACH_OFF", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY'}, None),
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True}, None),
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY', "alt": params.use_transform_navigation}, None),
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True, "alt": params.use_transform_navigation}, None),
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
("PRECISION", {"type": 'RIGHT_SHIFT', "value": 'ANY', "any": True}, None),
])

View File

@@ -1038,10 +1038,22 @@ class VIEW3D_MT_transform_base:
# TODO: get rid of the custom text strings?
def draw(self, context):
layout = self.layout
allow_navigation = getattr(
context.window_manager.keyconfigs.active.preferences,
"use_transform_navigation",
False)
layout.operator("transform.translate")
layout.operator("transform.rotate")
layout.operator("transform.resize", text="Scale")
props = layout.operator("transform.translate")
props.release_confirm = False
props.allow_navigation = allow_navigation
props = layout.operator("transform.rotate")
props.release_confirm = False
props.allow_navigation = allow_navigation
props = layout.operator("transform.resize", text="Scale")
props.release_confirm = False
props.allow_navigation = allow_navigation
layout.separator()

View File

@@ -125,8 +125,9 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_CURSOR_EDIT (1 << 16)
#define P_CLNOR_INVALIDATE (1 << 17)
#define P_VIEW2D_EDGE_PAN (1 << 18)
#define P_VIEW3D_NAVIGATION (1 << 19)
/* For properties performed when confirming the transformation. */
#define P_POST_TRANSFORM (1 << 19)
#define P_POST_TRANSFORM (1 << 20)
void Transform_Properties(struct wmOperatorType *ot, int flags);

View File

@@ -92,9 +92,6 @@ void setTransformViewMatrices(TransInfo *t)
unit_m4(t->persinv);
t->persp = RV3D_ORTHO;
}
calculateCenter2D(t);
calculateCenterLocal(t, t->center_global);
}
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
@@ -926,15 +923,16 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
int transformEvent(TransInfo *t, const wmEvent *event)
{
bool handled = false;
bool is_navigating = t->vod ? ((RegionView3D *)t->region->regiondata)->rflag & RV3D_NAVIGATING :
false;
/* Handle modal numinput events first, if already activated. */
if (((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) && hasNumInput(&t->num) &&
handleNumInput(t->context, &(t->num), event))
{
if (!is_navigating && ((event->val == KM_PRESS) || (event->type == EVT_MODAL_MAP)) &&
hasNumInput(&t->num) && handleNumInput(t->context, &(t->num), event)) {
t->redraw |= TREDRAW_HARD;
handled = true;
}
else if (event->type == MOUSEMOVE) {
else if (!is_navigating && event->type == MOUSEMOVE) {
copy_v2_v2_int(t->mval, event->mval);
/* Use this for soft redraw. Might cause flicker in object mode */

View File

@@ -41,6 +41,7 @@ struct TransDataContainer;
struct TransInfo;
struct TransSnap;
struct ViewLayer;
struct ViewOpsData;
struct bContext;
struct wmEvent;
struct wmKeyConfig;
@@ -673,6 +674,8 @@ typedef struct TransInfo {
/** Currently only used for random curve of proportional editing. */
struct RNG *rng;
struct ViewOpsData *vod;
/** Typically for mode settings. */
TransCustomDataContainer custom;

View File

@@ -660,7 +660,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag |= T_NO_CURSOR_WRAP;
}
if (op && (t->flag & T_MODAL) && !(t->flag & T_RELEASE_CONFIRM) &&
(prop = RNA_struct_find_property(op->ptr, "allow_navigation")) &&
RNA_property_boolean_get(op->ptr, prop)) {
t->vod = ED_view3d_navigation_init(C);
}
setTransformViewMatrices(t);
calculateCenter2D(t);
calculateCenterLocal(t, t->center_global);
initNumInput(&t->num);
transform_gizmo_3d_model_from_constraint_and_mode_init(t);
@@ -770,6 +778,10 @@ void postTrans(bContext *C, TransInfo *t)
}
freeSnapping(t);
if (t->vod) {
ED_view3d_navigation_free(C, t->vod);
}
}
void applyTransObjects(TransInfo *t)

View File

@@ -399,7 +399,7 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event)
static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
int exit_code;
int exit_code = OPERATOR_PASS_THROUGH;
TransInfo *t = op->customdata;
const eTfmMode mode_prev = t->mode;
@@ -419,6 +419,31 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
exit_code = transformEvent(t, event);
t->context = NULL;
/* Allow navigation while transforming. */
if (t->vod && (exit_code & OPERATOR_PASS_THROUGH) && ED_view3d_navigation_do(C, t->vod, event)) {
RegionView3D *rv3d = t->region->regiondata;
if (rv3d->rflag & RV3D_NAVIGATING) {
/* Do not update transform while navigating. This can be distracting. */
return OPERATOR_RUNNING_MODAL;
}
if (t->modifiers & MOD_PRECISION) {
/* Remove Precision modifier, it may have be unintentionally enabled. */
t->modifiers &= ~MOD_PRECISION;
t->mouse.precision = 0;
}
/* Make sure `t->mval` is up to date before calling #transformViewUpdate. */
copy_v2_v2_int(t->mval, event->mval);
/* Call before #applyMouseInput. */
tranformViewUpdate(t);
/* Mouse input is outdated. */
applyMouseInput(t, &t->mouse, t->mval, t->values);
t->redraw |= TREDRAW_HARD;
}
transformApply(C, t);
exit_code |= transformEnd(C, t);
@@ -752,6 +777,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
if (flags & P_VIEW3D_NAVIGATION) {
prop = RNA_def_boolean(ot->srna,
"allow_navigation",
0,
"Allow Navigation",
"Allow navigation while transforming");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
if (flags & P_POST_TRANSFORM) {
prop = RNA_def_boolean(ot->srna,
"use_automerge_and_split",
@@ -786,7 +820,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_VIEW2D_EDGE_PAN |
P_POST_TRANSFORM);
P_VIEW3D_NAVIGATION | P_POST_TRANSFORM);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@@ -825,7 +859,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP |
P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
P_OPTIONS | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
@@ -902,7 +936,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
@@ -1147,7 +1181,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
"When Even mode is active, flips between the two adjacent edge loops");
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV);
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
@@ -1182,7 +1216,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
"When Even mode is active, flips between the two adjacent edge loops");
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV);
Transform_Properties(ot, P_MIRROR | P_GEO_SNAP | P_CORRECT_UV | P_VIEW3D_NAVIGATION);
}
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
@@ -1330,7 +1364,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER | P_VIEW3D_NAVIGATION);
}
static int transform_from_gizmo_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)