Reworked Edit Context Menu #113115

Open
Julien Kaspar wants to merge 5 commits from JulienKaspar/blender:context_menu into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
1 changed files with 172 additions and 244 deletions

View File

@ -4279,10 +4279,10 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.separator()
layout.menu("VIEW3D_MT_edit_mesh_attributes")
layout.menu("VIEW3D_MT_edit_mesh_normals")
layout.menu("VIEW3D_MT_edit_mesh_shading")
layout.menu("VIEW3D_MT_edit_mesh_weights")
layout.operator("mesh.attribute_set")
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
layout.separator()
@ -4298,7 +4298,7 @@ class VIEW3D_MT_edit_mesh(Menu):
class VIEW3D_MT_edit_mesh_context_menu(Menu):
bl_label = ""
bl_label = "Mesh"
def draw(self, context):
@ -4336,177 +4336,155 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu):
# Else something is selected
row = layout.row()
# The order mostly follows the this logic top to bottom:
# Selection contains = Singe Vert - Multiple Verts - Edges - Faces
# Exceptions for usability are similar operators that are grouped together and
# "Subdivision" at the top and "Delete and Split" at the bottom
if is_vert_mode:
col = row.column(align=True)
# Subdivision
if selected_edges_len > 0:
layout.operator("mesh.subdivide")
layout.operator("mesh.unsubdivide")
col.label(text="Vertex", icon='VERTEXSEL')
col.separator()
layout.separator()
# Additive Operators
col.operator("mesh.subdivide", text="Subdivide")
# Extrude & Bevel
layout.operator("view3d.edit_mesh_extrude_move_normal",
text="Extrude along Normals")
layout.menu("VIEW3D_MT_edit_mesh_extrude")
if selected_faces_len > 0:
layout.operator("mesh.inset")
layout.operator("mesh.bevel", text="Bevel Vertices").affect = 'VERTICES'
if selected_edges_len > 0:
layout.operator("mesh.bevel", text="Bevel Edges").affect = 'EDGES'
col.separator()
layout.separator()
col.operator("mesh.extrude_vertices_move", text="Extrude Vertices")
col.operator("mesh.bevel", text="Bevel Vertices").affect = 'VERTICES'
props = layout.operator("mesh.knife_tool")
props.use_occlude_geometry = props.use_occlude_geometry = True
props.only_selected = props.only_selected = False
if selected_edges_len > 0:
layout.operator("mesh.bisect")
if selected_verts_len > 1:
col.separator()
col.operator("mesh.edge_face_add", text="New Edge/Face from Vertices")
col.operator("mesh.vert_connect_path", text="Connect Vertex Path")
col.operator("mesh.vert_connect", text="Connect Vertex Pairs")
layout.separator()
col.separator()
# Deform Operators
layout.menu("VIEW3D_MT_transform")
layout.operator("transform.vert_slide")
if selected_edges_len > 0:
layout.operator("transform.edge_slide")
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("mesh.vertices_smooth").factor = 0.5
layout.operator("transform.vertex_random", text="Randomize Vertices").offset = 0.1
# WIP This could get a check for a skin modifier
layout.operator("transform.skin_resize")
# Deform Operators
col.operator("transform.push_pull", text="Push/Pull")
col.operator("transform.shrink_fatten", text="Shrink/Fatten")
col.operator("transform.shear", text="Shear")
col.operator("transform.vert_slide", text="Slide Vertices")
col.operator_context = 'EXEC_REGION_WIN'
col.operator("transform.vertex_random", text="Randomize Vertices").offset = 0.1
col.operator("mesh.vertices_smooth", text="Smooth Vertices").factor = 0.5
col.operator_context = 'INVOKE_REGION_WIN'
col.operator("mesh.vertices_smooth_laplacian", text="Smooth Laplacian")
layout.separator()
col.separator()
layout.operator("mesh.loopcut_slide")
if selected_edges_len >= 1:
layout.operator("mesh.offset_edge_loops_slide")
col.menu("VIEW3D_MT_mirror", text="Mirror Vertices")
col.menu("VIEW3D_MT_snap", text="Snap Vertices")
layout.separator()
col.separator()
layout.operator("transform.mirror")
layout.menu("VIEW3D_MT_snap")
col.operator("transform.vert_crease")
layout.separator()
col.separator()
# Attributes
layout.menu("VIEW3D_MT_edit_mesh_attributes", text="Write Attributes")
# Removal Operators
if selected_verts_len > 1:
col.menu("VIEW3D_MT_edit_mesh_merge", text="Merge Vertices")
col.operator("mesh.split")
col.operator_menu_enum("mesh.separate", "type")
col.operator("mesh.dissolve_verts")
col.operator("mesh.delete", text="Delete Vertices").type = 'VERT'
layout.separator()
if is_edge_mode:
col = row.column(align=True)
col.label(text="Edge", icon='EDGESEL')
col.separator()
# Fill & Connect
if selected_verts_len > 1:
layout.separator()
layout.operator("mesh.edge_face_add")
# WIP This is a placeholder menu.
layout.menu("VIEW3D_MT_edit_mesh_fill_connect")
# Additive Operators
col.operator("mesh.subdivide", text="Subdivide")
layout.separator()
col.separator()
# UV Mapping
if selected_verts_len > 1:
layout.menu("VIEW3D_MT_uv_map")
col.operator("mesh.extrude_edges_move", text="Extrude Edges")
col.operator("mesh.bevel", text="Bevel Edges").affect = 'EDGES'
if selected_edges_len >= 2:
col.operator("mesh.bridge_edge_loops")
if selected_edges_len >= 1:
col.operator("mesh.edge_face_add", text="New Face from Edges")
if selected_edges_len >= 2:
col.operator("mesh.fill")
layout.separator()
col.separator()
if selected_faces_len > 1:
layout.operator("mesh.faces_shade_smooth")
layout.operator("mesh.faces_shade_flat")
layout.operator("mesh.normals_make_consistent").inside = False
props = col.operator("mesh.loopcut_slide")
props.TRANSFORM_OT_edge_slide.release_confirm = False
col.operator("mesh.offset_edge_loops_slide")
layout.separator()
col.separator()
col.operator("mesh.knife_tool")
col.operator("mesh.bisect")
col.separator()
# Deform Operators
col.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
col.operator("transform.edge_slide")
col.operator("mesh.edge_split")
col.separator()
# Edge Flags
col.operator("transform.edge_crease")
col.operator("transform.edge_bevelweight")
col.separator()
col.operator("mesh.mark_seam").clear = False
col.operator("mesh.mark_seam", text="Clear Seam").clear = True
col.separator()
col.operator("mesh.mark_sharp")
col.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
if with_freestyle:
col.separator()
col.operator("mesh.mark_freestyle_edge").clear = False
col.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
col.separator()
# Removal Operators
col.operator("mesh.unsubdivide")
col.operator("mesh.split")
col.operator_menu_enum("mesh.separate", "type")
col.operator("mesh.dissolve_edges")
col.operator("mesh.delete", text="Delete Edges").type = 'EDGE'
if is_face_mode:
col = row.column(align=True)
col.label(text="Face", icon='FACESEL')
col.separator()
# Additive Operators
col.operator("mesh.subdivide", text="Subdivide")
col.separator()
col.operator("view3d.edit_mesh_extrude_move_normal",
text="Extrude Faces")
col.operator("view3d.edit_mesh_extrude_move_shrink_fatten",
text="Extrude Faces Along Normals")
col.operator("mesh.extrude_faces_move",
text="Extrude Individual Faces")
col.operator("mesh.inset")
col.operator("mesh.poke")
if selected_faces_len >= 2:
col.operator("mesh.bridge_edge_loops", text="Bridge Faces")
col.separator()
# Modify Operators
col.menu("VIEW3D_MT_uv_map", text="UV Unwrap Faces")
col.separator()
props = col.operator("mesh.quads_convert_to_tris")
# Tris & Quads
if selected_faces_len > 0:
props = layout.operator("mesh.quads_convert_to_tris")
props.quad_method = props.ngon_method = 'BEAUTY'
col.operator("mesh.tris_convert_to_quads")
layout.operator("mesh.tris_convert_to_quads")
col.separator()
layout.separator()
col.operator("mesh.faces_shade_smooth")
col.operator("mesh.faces_shade_flat")
# Delete and Split
if selected_verts_len > 1:
layout.menu("VIEW3D_MT_edit_mesh_merge")
layout.operator("mesh.split")
layout.operator_menu_enum("mesh.separate", "type")
if is_vert_mode:
layout.operator("mesh.delete", text="Delete Vertices").type = 'VERT'
if is_edge_mode:
layout.operator("mesh.delete", text="Delete Edges").type = 'EDGE'
if is_face_mode:
layout.operator("mesh.delete", text="Delete Faces").type = 'FACE'
layout.operator("mesh.dissolve_mode")
layout.menu("VIEW3D_MT_edit_mesh_delete")
col.separator()
# Removal Operators
col.operator("mesh.unsubdivide")
col.operator("mesh.split")
col.operator_menu_enum("mesh.separate", "type")
col.operator("mesh.dissolve_faces")
col.operator("mesh.delete", text="Delete Faces").type = 'FACE'
class VIEW3D_MT_edit_mesh_attributes(Menu):
bl_label = "Attributes"
def draw(self, _context):
layout = self.layout
with_freestyle = bpy.app.build_options.freestyle
layout.operator("mesh.attribute_set")
layout.separator()
layout.operator("transform.vert_crease")
layout.operator("transform.edge_crease")
layout.operator("transform.edge_bevelweight")
layout.separator()
layout.operator("mesh.mark_seam").clear = False
layout.operator("mesh.mark_seam", text="Clear Seam").clear = True
layout.separator()
layout.operator("mesh.mark_sharp")
layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
layout.operator("mesh.mark_sharp", text="Mark Sharp from Vertices").use_verts = True
props = layout.operator("mesh.mark_sharp", text="Clear Sharp from Vertices")
props.use_verts = True
props.clear = True
if with_freestyle:
layout.separator()
layout.operator("mesh.mark_freestyle_edge").clear = False
layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
class VIEW3D_MT_edit_mesh_fill_connect(Menu):
bl_label = "Fill/Connect"
def draw(self, _context):
layout = self.layout
class VIEW3D_MT_edit_mesh_select_mode(Menu):
bl_label = "Mesh Select Mode"
@ -4911,6 +4889,7 @@ class VIEW3D_MT_edit_mesh_delete(Menu):
layout.separator()
layout.operator("mesh.dissolve_mode")
layout.operator("mesh.dissolve_verts")
layout.operator("mesh.dissolve_edges")
layout.operator("mesh.dissolve_faces")
@ -7993,125 +7972,72 @@ class VIEW3D_PT_gpencil_curve_edit(Panel):
class VIEW3D_MT_gpencil_edit_context_menu(Menu):
bl_label = ""
bl_label = "Grease Pencil"
def draw(self, context):
layout = self.layout
tool_settings = context.tool_settings
is_point_mode = tool_settings.gpencil_selectmode_edit == 'POINT'
is_stroke_mode = tool_settings.gpencil_selectmode_edit == 'STROKE'
is_segment_mode = tool_settings.gpencil_selectmode_edit == 'SEGMENT'
layout.operator_context = 'INVOKE_REGION_WIN'
row = layout.row()
# Subdivision
layout.operator("gpencil.stroke_subdivide").only_selected = True
layout.menu("VIEW3D_MT_gpencil_simplify")
layout.operator("gpencil.stroke_trim")
if is_point_mode or is_segment_mode:
col = row.column(align=True)
layout.separator()
col.label(text="Point", icon='GP_SELECT_POINTS')
col.separator()
# Deform Operators
layout.operator("gpencil.stroke_smooth").only_selected = True
layout.operator("transform.bend")
layout.operator("transform.shear")
layout.operator("transform.tosphere")
layout.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
layout.operator("gpencil.stroke_start_set")
# Additive Operators
col.operator("gpencil.stroke_subdivide", text="Subdivide").only_selected = True
layout.separator()
col.separator()
# Extrude
layout.operator("gpencil.extrude_move")
col.operator("gpencil.extrude_move", text="Extrude")
layout.separator()
col.separator()
layout.menu("VIEW3D_MT_mirror")
layout.menu("GPENCIL_MT_snap")
# Deform Operators
col.operator("gpencil.stroke_smooth", text="Smooth").only_selected = True
col.operator("transform.bend", text="Bend")
col.operator("transform.shear", text="Shear")
col.operator("transform.tosphere", text="To Sphere")
col.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.operator("gpencil.stroke_start_set", text="Set Start Point")
layout.separator()
col.separator()
# Duplicate operators
layout.operator("gpencil.duplicate_move")
layout.operator("gpencil.copy", icon='COPYDOWN')
layout.operator("gpencil.paste", icon='PASTEDOWN').type = 'ACTIVE'
layout.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col.menu("VIEW3D_MT_mirror", text="Mirror")
col.menu("GPENCIL_MT_snap", text="Snap")
layout.separator()
col.separator()
# Layer and Materials operators
layout.menu("GPENCIL_MT_move_to_layer")
layout.menu("VIEW3D_MT_assign_material")
layout.operator("gpencil.set_active_material",)
layout.operator_menu_enum("gpencil.stroke_arrange", "direction",)
# Duplicate operators
col.operator("gpencil.duplicate_move", text="Duplicate")
col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
layout.separator()
col.separator()
# Removal Operators
col.operator("gpencil.stroke_merge", text="Merge")
col.operator("gpencil.stroke_merge_by_distance").use_unselected = False
col.operator("gpencil.stroke_split", text="Split")
col.operator("gpencil.stroke_separate", text="Separate").mode = 'POINT'
col.separator()
col.operator("gpencil.delete", text="Delete").type = 'POINTS'
col.operator("gpencil.dissolve", text="Dissolve").type = 'POINTS'
col.operator("gpencil.dissolve", text="Dissolve Between").type = 'BETWEEN'
col.operator("gpencil.dissolve", text="Dissolve Unselected").type = 'UNSELECT'
if is_stroke_mode:
col = row.column(align=True)
col.label(text="Stroke", icon='GP_SELECT_STROKES')
col.separator()
# Main Strokes Operators
col.operator("gpencil.stroke_subdivide", text="Subdivide").only_selected = False
col.menu("VIEW3D_MT_gpencil_simplify")
col.operator("gpencil.stroke_trim", text="Trim")
col.separator()
col.operator("gpencil.stroke_smooth", text="Smooth").only_selected = False
col.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN'
col.separator()
# Layer and Materials operators
col.menu("GPENCIL_MT_move_to_layer")
col.menu("VIEW3D_MT_assign_material")
col.operator("gpencil.set_active_material", text="Set as Active Material")
col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange")
col.separator()
col.menu("VIEW3D_MT_mirror", text="Mirror")
col.menu("VIEW3D_MT_snap", text="Snap")
col.separator()
# Duplicate operators
col.operator("gpencil.duplicate_move", text="Duplicate")
col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col.separator()
# Removal Operators
col.operator("gpencil.stroke_merge_by_distance").use_unselected = True
col.operator_menu_enum("gpencil.stroke_join", "type", text="Join",
# Delete and Split
layout.operator("gpencil.stroke_merge")
layout.operator("gpencil.stroke_merge_by_distance").use_unselected = False
layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join",
text_ctxt=i18n_contexts.id_gpencil)
layout.operator("gpencil.stroke_split", text="Split")
layout.operator("gpencil.stroke_separate", text="Separate").mode = 'POINT'
col.operator("gpencil.stroke_split", text="Split")
col.operator("gpencil.stroke_separate", text="Separate").mode = 'STROKE'
layout.separator()
col.separator()
col.operator("gpencil.delete", text="Delete").type = 'STROKES'
col.separator()
col.operator("gpencil.reproject", text="Reproject")
layout.operator("gpencil.delete", text="Delete Selection").type = 'POINTS'
layout.operator("gpencil.delete", text="Delete Frame").type = 'FRAME'
layout.operator("gpencil.dissolve", text="Dissolve").type = 'POINTS'
layout.operator("gpencil.dissolve", text="Dissolve Between").type = 'BETWEEN'
layout.operator("gpencil.dissolve", text="Dissolve Unselected").type = 'UNSELECT'
layout.operator("gpencil.reproject", text="Reproject")
class VIEW3D_MT_greasepencil_material_active(Menu):
@ -8886,6 +8812,8 @@ classes = (
VIEW3D_MT_bone_options_disable,
VIEW3D_MT_edit_mesh_context_menu,
VIEW3D_MT_edit_mesh_select_mode,
VIEW3D_MT_edit_mesh_attributes,
VIEW3D_MT_edit_mesh_fill_connect,
VIEW3D_MT_edit_mesh_select_linked,
VIEW3D_MT_edit_mesh_select_loops,
VIEW3D_MT_edit_mesh_extrude,