demohero
(demohero)
August 8, 2011, 4:36pm
1
I would like to create a Mesh Specials context menu. For example, in edit mode, select a face then press w key for face specials menu, or select an edge press w to open edge specials and so on. I don’t like using Ctrl E/F/V for edge, face and vertex menus every time. I think only one dynamic menu can do the same thing. How can I do that? (An example script would be awesome.)
Thanks
demohero
(demohero)
August 9, 2011, 2:45pm
2
Maybe the right question is “Is this possible with python or not?” :eyebrowlift2:
Abidos
(Abidos)
August 10, 2011, 12:25am
3
My principal answer is “YES”, meaning “it should be possible”… But what if a vertex and an edge are selected in the same time? The script is to respond by a “CANCEL”-message???
batFINGER
(batFINGER)
August 10, 2011, 4:38am
4
Something like the dynamic space bar menu? You can test for specific conditions in the draw method of the menu class and output the menu accordingly.
demohero
(demohero)
August 10, 2011, 8:32am
5
This time another sub-menu can be created like in Dynamic Spacebar Menu. Or menu appears only for the last selected component. Maya is capable of doing this, why not Blender?
(was a Maya user before. Sorry. :))
zeffii
(zeffii)
August 10, 2011, 10:42am
6
In scripts/startup/bl_ui/space_view3d.py it’s these babies
layout.separator()
layout.menu("VIEW3D_MT_edit_mesh_vertices")
layout.menu("VIEW3D_MT_edit_mesh_edges")
layout.menu("VIEW3D_MT_edit_mesh_faces")
layout.menu("VIEW3D_MT_edit_mesh_normals")
easy enough to check the current selection mode too, this sets them. checking is similar
# vertex
bpy.ops.wm.context_set_value(data_path="tool_settings.mesh_select_mode", value="(True, False, False)")
# edge
bpy.ops.wm.context_set_value(data_path="tool_settings.mesh_select_mode", value="(False, True, False)")
# face
bpy.ops.wm.context_set_value(data_path="tool_settings.mesh_select_mode", value="(False, False, True)")
this would check the current state, while in context
# if is face select mode
bpy.context.tool_settings.mesh_select_mode[:] == (False, False, True)
>> true
i’ll give it a swing lateron demohero, unless someone beats me to it.
demohero
(demohero)
August 10, 2011, 12:13pm
7
Thank you zeffii.
I wish I had enough python knowledge. Using this in scripts/startup/bl_ui/space_view3d.py file would be great.
Btw, Blender already has context sensitive menus in Object mode. Select a camera and press w for example. When you select a lamp object, w specials menu changes for lamp properties. I think dynamic menus are very important for reducing keyboard shortcuts. Much more practical.
Abidos
(Abidos)
August 11, 2011, 12:37pm
8
@ yeah, the principle of providing a context sensitive menu for the last selected item sounds fair… although it may not be exactly what the user thinks in the moment… but partially, it is a problem of the user(s)
Heres an example, youll need to assign to a key to execute in different contexts.
import bpy
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
if context.space_data.type == 'VIEW_3D':
if context.mode == 'EDIT_MESH':
layout.operator("wm.open_mainfile")
layout.operator("wm.save_as_mainfile")
elif context.mode == 'OBJECT':
layout.operator("object.shade_smooth")
elif context.space_data.type == 'IMAGE_EDITOR':
layout.operator("image.new")
else:
layout.label("No Context!")
def register():
bpy.utils.register_class(SimpleCustomMenu)
def unregister():
bpy.utils.unregister_class(SimpleCustomMenu)
if __name__ == "__main__":
register()
# The menu can also be called from scripts
bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)
demohero
(demohero)
August 12, 2011, 8:55am
10
Thank you very much for this example Campbell.
But I don’t know how to assign a hotkey. How can I do that? Using keymap editor? Couldn’t find the operator named Simple Custom Menu?!
batFINGER
(batFINGER)
August 12, 2011, 9:36am
11
The following keymaps the menu to the “SPACE” bar
import bpy
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
if context.space_data.type == 'VIEW_3D':
if context.mode == 'EDIT':
layout.operator("wm.open_mainfile")
layout.operator("wm.save_as_mainfile")
elif context.mode == 'OBJECT':
layout.operator("object.shade_smooth")
elif context.space_data.type == 'IMAGE_EDITOR':
layout.operator("image.new")
else:
layout.label("No Context!")
def register():
bpy.utils.register_class(SimpleCustomMenu)
km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View']
kmi = km.keymap_items.new('wm.call_menu', 'SPACE', 'PRESS')
kmi.properties.name = "OBJECT_MT_simple_custom_menu"
def unregister():
bpy.utils.unregister_class(SimpleCustomMenu)
if __name__ == "__main__":
register()
# The menu can also be called from scripts
bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)
To map it to j for instance change to
kmi = km.keymap_items.new('wm.call_menu', 'J', 'PRESS')
demohero
(demohero)
August 12, 2011, 11:00am
12
Thanks for your help @batFINGER and Meta-Androcto. This is awesome. :yes:
ideasman42
(ideasman42)
August 13, 2011, 9:31pm
13
Updated the previous script.
uses spacebar
has vert/edge/face modes.
import bpy
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
if context.space_data.type == 'VIEW_3D':
if context.mode == 'EDIT_MESH':
layout.operator("wm.open_mainfile")
layout.operator("wm.save_as_mainfile")
layout.separator()
props = layout.operator("wm.context_set_value", text="Vertex Mode")
props.data_path = "tool_settings.mesh_select_mode"
props.value="(True, False, False)"
props = layout.operator("wm.context_set_value", text="Edge Mode")
props.data_path = "tool_settings.mesh_select_mode"
props.value="(False, True, False)"
props = layout.operator("wm.context_set_value", text="Face Mode")
props.data_path = "tool_settings.mesh_select_mode"
props.value="(False, False, True)"
elif context.mode == 'OBJECT':
layout.operator("object.shade_smooth")
elif context.space_data.type == 'IMAGE_EDITOR':
layout.operator("image.new")
else:
layout.label("No Context!")
def register():
bpy.utils.register_class(SimpleCustomMenu)
km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View']
kmi = km.keymap_items.new('wm.call_menu', 'SPACE', 'PRESS')
kmi.properties.name = "OBJECT_MT_simple_custom_menu"
def unregister():
bpy.utils.unregister_class(SimpleCustomMenu)
if __name__ == "__main__":
register()
# The menu can also be called from scripts
bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)
zeffii
(zeffii)
August 13, 2011, 10:52pm
14
a remix ( Using J key) :
import bpy
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
if context.space_data.type == 'VIEW_3D':
if context.mode == 'EDIT_MESH':
layout.separator()
# if vertex mode
if bpy.context.tool_settings.mesh_select_mode[:] == (True, False, False):
layout.menu("VIEW3D_MT_edit_mesh_vertices")
# if edge mode
if bpy.context.tool_settings.mesh_select_mode[:] == (False, True, False):
layout.menu("VIEW3D_MT_edit_mesh_edges")
# if face mode
if bpy.context.tool_settings.mesh_select_mode[:] == (False, False, True):
layout.menu("VIEW3D_MT_edit_mesh_faces")
elif context.mode == 'OBJECT':
layout.label("object mode")
elif context.space_data.type == 'IMAGE_EDITOR':
layout.label("No Context! image editor")
else:
layout.label("No Context!")
def register():
bpy.utils.register_class(SimpleCustomMenu)
km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View']
kmi = km.keymap_items.new('wm.call_menu', 'J', 'PRESS')
kmi.properties.name = "OBJECT_MT_simple_custom_menu"
def unregister():
bpy.utils.unregister_class(SimpleCustomMenu)
if __name__ == "__main__":
register()
or, if you use a variety of modes, sometimes combined like ‘faces+edges’ then consider
import bpy
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
if context.space_data.type == 'VIEW_3D':
if context.mode == 'EDIT_MESH':
layout.separator()
current_mesh_mode = context.tool_settings.mesh_select_mode[:]
# allows multiple, simultaneous modes, f.ex edges+faces
# if vertex mode on
if current_mesh_mode[0]:
layout.menu("VIEW3D_MT_edit_mesh_vertices")
# if vertex mode on
if current_mesh_mode[1]:
layout.menu("VIEW3D_MT_edit_mesh_edges")
# if vertex mode on
if current_mesh_mode[2]:
layout.menu("VIEW3D_MT_edit_mesh_faces")
elif context.mode == 'OBJECT':
layout.label("object mode")
elif context.space_data.type == 'IMAGE_EDITOR':
layout.label("No Context! image editor")
else:
layout.label("No Context!")
def register():
bpy.utils.register_class(SimpleCustomMenu)
km = bpy.context.window_manager.keyconfigs.active.keymaps['3D View']
kmi = km.keymap_items.new('wm.call_menu', 'J', 'PRESS')
kmi.properties.name = "OBJECT_MT_simple_custom_menu"
def unregister():
bpy.utils.unregister_class(SimpleCustomMenu)
if __name__ == "__main__":
register()
demohero
(demohero)
August 14, 2011, 1:46am
15
This must be a dream. Thank you soooo much for all your help. :yes: