WIP: Shift Extrude and Duplicate of meshes and objects #118968

Draft
Kyler Kelly-Tan wants to merge 20 commits from kylerk/blender:ShiftExtrude into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
4 changed files with 273 additions and 39 deletions

View File

@ -285,6 +285,33 @@ void ED_operatormacros_mesh()
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_extrude_context_rotate",
"Extrude Region and Rotate",
"Extrude region together along the average normal",
OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_rotate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_extrude_context_trackball",
"Extrude Region and Rotate (Trackball)",
"Extrude region together along the average normal",
OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_trackball");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_extrude_context_resize",
"Extrude Region and Resize",
"Extrude region together along the average normal",
OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_resize");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_extrude_region_shrink_fatten",
"Extrude Region and Shrink/Fatten",
"Extrude region together along local normals",
@ -357,6 +384,34 @@ void ED_operatormacros_mesh()
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_context_duplicate_rotate",
"Duplicate Region and Rotate",
nullptr,
OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_rotate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_context_duplicate_trackball",
"Duplicate Region and Rotate(Trackball)",
nullptr,
OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_trackball");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
ot = WM_operatortype_append_macro("MESH_OT_context_duplicate_scale",
"Duplicate Region and Scale",
nullptr,
OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_resize");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
}
void ED_keymap_mesh(wmKeyConfig *keyconf)

View File

@ -319,6 +319,36 @@ void ED_operatormacros_object()
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_rotate",
"Duplicate Objects and Rotate",
"Duplicate selected objects and rotate them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_rotate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_trackball",
"Duplicate Objects and Rotate (Trackball)",
"Duplicate selected objects and rotate them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_trackball");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_resize",
"Duplicate Objects and Scale",
"Duplicate selected objects and scale them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_resize");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro(
"OBJECT_OT_duplicate_move_linked",
"Duplicate Linked",
@ -330,6 +360,39 @@ void ED_operatormacros_object()
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_rotate_linked",
"Duplicate Linked and Rotate",
"Duplicate Linked selected objects and rotate them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
RNA_boolean_set(otmacro->ptr, "linked", true);
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_rotate");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_trackball_linked",
"Duplicate Linked and Rotate (Trackball)",
"Duplicate linked selected objects and rotate them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
otmacro =WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
RNA_boolean_set(otmacro->ptr, "linked", true);
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_trackball");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_resize_linked",
"Duplicate Linked and Scale",
"Duplicate linked selected objects and scale them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
otmacro =WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
RNA_boolean_set(otmacro->ptr, "linked", true);
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_resize");
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
}
static bool object_mode_poll(bContext *C)

View File

@ -1767,17 +1767,23 @@ static int gizmo_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
static void gizmogroup_init_properties_from_twtype(const bContext *C, wmGizmoGroup *gzgroup)
{
struct {
wmOperatorType *translate, *rotate, *trackball, *resize;
wmOperatorType *extra_translate, *extra_rotate, *extra_trackball, *extra_resize;
wmOperatorType *extra_translate2, *extra_rotate2, *extra_trackball2, *extra_resize2;
} ot_store = {nullptr};
GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
const eContextObjectMode mode = CTX_data_mode_enum(C);
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
bool constraint_axis[3] = {true, false, false};
PointerRNA *ptr = nullptr;
PointerRNA *ptr_extra = nullptr;
PointerRNA *ptr_extra2 = nullptr;
gizmo_get_axis_constraint(axis_idx, constraint_axis);
@ -1791,21 +1797,92 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
if (ot_store.translate == nullptr) {
ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
}
if (ot_store.extra_translate == NULL) {
switch (mode) {
default:
break;
case CTX_MODE_OBJECT:
ot_store.extra_translate = WM_operatortype_find("OBJECT_OT_duplicate_move", true);
ot_store.extra_translate2 = WM_operatortype_find("OBJECT_OT_duplicate_move_linked", true);
break;
case CTX_MODE_EDIT_MESH:
ot_store.extra_translate = WM_operatortype_find("MESH_OT_extrude_context_move",
true);
ot_store.extra_translate2 = WM_operatortype_find("MESH_OT_duplicate_move",
true);
break;
}
}
if (ot_store.extra_translate) {
ptr_extra = WM_gizmo_operator_set(axis, 16, ot_store.extra_translate, NULL);
}
if (ot_store.extra_translate2) {
ptr_extra2 = WM_gizmo_operator_set(axis, 15, ot_store.extra_translate2, NULL);
}
ptr = WM_gizmo_operator_set(axis, 0, ot_store.translate, nullptr);
break;
case MAN_AXES_ROTATE: {
wmOperatorType *ot_rotate;
wmOperatorType *ot_rotate_extra;
wmOperatorType *ot_rotate_extra2;
if (axis_idx == MAN_AXIS_ROT_T) {
if (ot_store.trackball == nullptr) {
ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true);
}
if (ot_store.extra_trackball == NULL) {
switch (mode) {
default:
break;
case CTX_MODE_OBJECT:
ot_store.extra_trackball = WM_operatortype_find("OBJECT_OT_duplicate_trackball",
true);
ot_store.extra_trackball2 = WM_operatortype_find("OBJECT_OT_duplicate_trackball_linked",
true);
break;
case CTX_MODE_EDIT_MESH:
ot_store.extra_trackball = WM_operatortype_find(
"MESH_OT_extrude_context_trackball", true);
ot_store.extra_trackball2 = WM_operatortype_find(
"MESH_OT_context_duplicate_trackball", true);
break;
}
}
ot_rotate = ot_store.trackball;
ot_rotate_extra = ot_store.extra_trackball;
ot_rotate_extra2 = ot_store.extra_trackball2;
}
else {
if (ot_store.rotate == nullptr) {
ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
}
if (ot_store.extra_rotate == NULL) {
switch (mode) {
default:
break;
case CTX_MODE_OBJECT:
ot_store.extra_rotate = WM_operatortype_find("OBJECT_OT_duplicate_rotate", true);
ot_store.extra_rotate2 = WM_operatortype_find("OBJECT_OT_duplicate_rotate_linked", true);
break;
case CTX_MODE_EDIT_MESH:
ot_store.extra_rotate = WM_operatortype_find("MESH_OT_extrude_context_rotate",
true);
ot_store.extra_rotate2 = WM_operatortype_find("MESH_OT_context_duplicate_rotate",
true);
break;
}
}
ot_rotate = ot_store.rotate;
ot_rotate_extra = ot_store.extra_rotate;
ot_rotate_extra2 = ot_store.extra_rotate2;
}
if (ot_rotate_extra) {
ptr_extra = WM_gizmo_operator_set(axis, 16, ot_rotate_extra, NULL);
}
if (ot_rotate_extra2) {
ptr_extra2 = WM_gizmo_operator_set(axis, 15, ot_rotate_extra2, NULL);
}
ptr = WM_gizmo_operator_set(axis, 0, ot_rotate, nullptr);
break;
@ -1814,11 +1891,68 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
if (ot_store.resize == nullptr) {
ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
}
if (ot_store.extra_resize == NULL) {
switch (mode) {
default:
break;
case CTX_MODE_OBJECT:
ot_store.extra_resize = WM_operatortype_find("OBJECT_OT_duplicate_resize", true);
ot_store.extra_resize2 = WM_operatortype_find("OBJECT_OT_duplicate_resize_linked", true);
break;
case CTX_MODE_EDIT_MESH:
ot_store.extra_resize = WM_operatortype_find("MESH_OT_extrude_context_resize", true);
ot_store.extra_resize2 = WM_operatortype_find("MESH_OT_context_duplicate_scale", true);
break;
}
}
if (ot_store.extra_resize) {
ptr_extra = WM_gizmo_operator_set(axis, 16, ot_store.extra_resize, NULL);
}
if (ot_store.extra_resize2) {
ptr_extra2 = WM_gizmo_operator_set(axis, 15, ot_store.extra_resize2, NULL);
}
ptr = WM_gizmo_operator_set(axis, 0, ot_store.resize, nullptr);
break;
}
}
if (ptr_extra) {
RNA_STRUCT_BEGIN (ptr_extra, prop) {
if (RNA_property_type(prop) != PROP_POINTER)
continue;
PointerRNA propptr = RNA_property_pointer_get(ptr_extra, prop);
if (!propptr.data || !RNA_struct_is_a(propptr.type, &RNA_OperatorProperties))
continue;
PropertyRNA *constr = NULL;
if (ELEM(true, UNPACK3(constraint_axis))) {
if ((constr = RNA_struct_find_property(&propptr, "constraint_axis"))) {
RNA_property_boolean_set_array(&propptr, constr, constraint_axis);
}
}
if (constr)
RNA_boolean_set(&propptr, "release_confirm", 1);
}
RNA_STRUCT_END;
}
if (ptr_extra2) {
RNA_STRUCT_BEGIN (ptr_extra2, prop) {
if (RNA_property_type(prop) != PROP_POINTER)
continue;
PointerRNA propptr2 = RNA_property_pointer_get(ptr_extra2, prop);
if (!propptr2.data || !RNA_struct_is_a(propptr2.type, &RNA_OperatorProperties))
continue;
PropertyRNA *constr = NULL;
if (ELEM(true, UNPACK3(constraint_axis))) {
if ((constr = RNA_struct_find_property(&propptr2, "constraint_axis"))) {
RNA_property_boolean_set_array(&propptr2, constr, constraint_axis);
}
}
if (constr)
RNA_boolean_set(&propptr2, "release_confirm", 1);
}
RNA_STRUCT_END;
}
if (ptr) {
PropertyRNA *prop;
if (ELEM(true, UNPACK3(constraint_axis))) {
@ -1869,7 +2003,7 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
}
/* *** set properties for axes *** */
gizmogroup_init_properties_from_twtype(gzgroup);
gizmogroup_init_properties_from_twtype(C, gzgroup);
}
/**
@ -1975,7 +2109,7 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
if (ggd->twtype != ggd->twtype_prev) {
ggd->twtype_prev = ggd->twtype;
gizmogroup_init_properties_from_twtype(gzgroup);
gizmogroup_init_properties_from_twtype(C, gzgroup);
}
}
@ -2181,42 +2315,7 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
}
}
/* Support shift click to constrain axis. */
int axis = -1;
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
case MAN_AXIS_TRANS_Z:
axis = axis_idx - MAN_AXIS_TRANS_X;
break;
case MAN_AXIS_SCALE_X:
case MAN_AXIS_SCALE_Y:
case MAN_AXIS_SCALE_Z:
axis = axis_idx - MAN_AXIS_SCALE_X;
break;
}
if (axis != -1) {
/* Swap single axis for two-axis constraint. */
const bool flip = (event->modifier & KM_SHIFT) != 0;
BLI_assert(axis_idx != -1);
const short axis_type = gizmo_get_axis_type(axis_idx);
if (axis_type != MAN_AXES_ROTATE) {
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
PointerRNA *ptr = &gzop->ptr;
PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
if (prop_constraint_axis) {
bool constraint[3] = {false};
constraint[axis] = true;
if (flip) {
for (int i = 0; i < ARRAY_SIZE(constraint); i++) {
constraint[i] = !constraint[i];
}
}
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
}
}
}
}
static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)

View File

@ -1081,7 +1081,24 @@ void wm_gizmomap_modal_set(
gzmap->gzmap_context.event_xy[0] = INT_MAX;
}
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, gz->highlight_part);
struct wmGizmoOpElem *gzop = NULL;
if (event->modifier & KM_SHIFT) {
if (event->modifier & KM_ALT) {
gzop = WM_gizmo_operator_get(gz, 15);
}
else {
gzop = WM_gizmo_operator_get(gz, 16);
}
}
if ((event->modifier & KM_ALT )& (event->modifier & KM_SHIFT)) {
gzop = WM_gizmo_operator_get(gz, 15);
}
if (!gzop) {
gzop = WM_gizmo_operator_get(gz, gz->highlight_part);
}
if (gzop && gzop->type) {
const int retval = WM_gizmo_operator_invoke(C, gz, gzop, event);
if ((retval & OPERATOR_RUNNING_MODAL) == 0) {