From 49b574aa82e914b7c1a97bfa49991f72754ee30d Mon Sep 17 00:00:00 2001 From: Ryan Inch Date: Fri, 11 May 2018 19:15:48 -0400 Subject: [PATCH 1/2] Update branch to 1.5b --- .gitignore | 3 +- .kdev4/Advanced_UI_Menus.kdev4 | 5 - Advanced_UI_Menus.kdev4 | 4 - README.md | 71 +++++-- Utils/CustomMenu.xml | 332 +++++--------------------------- Utils/CustomMenu.xml.bkup | 183 ------------------ __init__.py | 6 +- brush_menu.py | 336 ++++++++++++++++++++++++--------- custom_menu.py | 11 +- dyntopo_menu.py | 10 +- manipulator_menu.py | 7 +- mode_menu.py | 4 +- proportional_menu.py | 31 +-- shade_menu.py | 2 +- snap_menu.py | 29 +-- stroke_menu.py | 88 ++++----- texture_menu.py | 42 ++--- 17 files changed, 437 insertions(+), 727 deletions(-) delete mode 100644 .kdev4/Advanced_UI_Menus.kdev4 delete mode 100644 Advanced_UI_Menus.kdev4 delete mode 100644 Utils/CustomMenu.xml.bkup diff --git a/.gitignore b/.gitignore index b566fe6..b6c2325 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -__pycache__/ +__pycache__ +nbproject diff --git a/.kdev4/Advanced_UI_Menus.kdev4 b/.kdev4/Advanced_UI_Menus.kdev4 deleted file mode 100644 index d7b8fb8..0000000 --- a/.kdev4/Advanced_UI_Menus.kdev4 +++ /dev/null @@ -1,5 +0,0 @@ -[Buildset] -BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00"\x00A\x00d\x00v\x00a\x00n\x00c\x00e\x00d\x00_\x00U\x00I\x00_\x00M\x00e\x00n\x00u\x00s) - -[Project] -VersionControlSupport=kdevgit diff --git a/Advanced_UI_Menus.kdev4 b/Advanced_UI_Menus.kdev4 deleted file mode 100644 index 65c2ae4..0000000 --- a/Advanced_UI_Menus.kdev4 +++ /dev/null @@ -1,4 +0,0 @@ -[Project] -CreatedFrom=Advanced_UI_Menus -Manager=KDevCustomBuildSystem -Name=Advanced_UI_Menus diff --git a/README.md b/README.md index 80aa018..14fb19c 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Description: Installation Instructions: - Download the script then unpack and copy the folder advanced_ui_menus into your addons folder. - Open Blender and go to the addons tab in User Preferences. - Enable the script. + • Download the script then unpack and copy the folder advanced_ui_menus into your addons folder. + • Open Blender and go to the addons tab in User Preferences. + • Enable the script. Shortcuts: @@ -14,8 +14,8 @@ Shortcuts: Curve menu = W (works in: Sculpt mode, Vertex Paint mode, Weight Paint mode, Texture Paint Mode) Custom menu = Alt-MiddleMouse Delete menu = X - Dyntopo menu = Ctrl-D Tap for toggle(on/off), hold for menu - Layers window = M - Tap for set visible layers, hold for move objects to layers + Dyntopo menu = Ctrl-D - Tap for toggle(on/off), hold for menu + Layers window = M Manipulator = Ctrl-Space - Tap for toggle(on/off), hold for menu Mesh Selection menu = Ctrl-Tab Mesh Extrude = E - Tap for extrude, hold for menu @@ -32,18 +32,49 @@ Shortcuts: Custom Menu Tutorial: - The Custom Menu is a menu that you can customize with Operators, Separators, Labels, and other - menus as you see fit. This is a alpha release and as such is not the easiest to use or the most - feature complete, but should still be useful to people. Also if it is to reach it's true potential - I will probably need to work closely with the blender UI team. Now onto the tutorial. - To add an Operator open the menu and go down to Add Custom Item, select Operator. A window will - come up, type the path to the operator(you can find it by turning on python tooltips and then - hovering your mouse over a button or menu entry in the ui) in the Path field, - e.g. bpy.ops.mesh.vertices_smooth(). Type something into the Name field if you want the item to - have a custom name. If you want the item to have an Icon simply select it from the Icon list. The - last field on the window controls where the item is placed in the menu; the item will be placed - directly under the item you specify from the list. Finally press the OK button to add the item. - The rest of the items are added in a similar fashion, however as far as I know there is no easy - way to find the path for menus if you want to add them(tooltips only show up for them in some cases). - If you want to remove an item simply go to Add Custom Item, select Remove Item, and then select - the item you wish removed and press OK. + The Custom Menu is a menu that you can customize with Operators, Separators, Labels, Properties, and other Menus as you see fit. Custom Menus can be created for any mode in the 3D View as well as for other editors like the node editor, dopesheet, console, etc.. + + To Add An Item: + + • open the menu (Alt-MiddleMouse), and click Edit Custom Menu. + + • (Required) + Select what type of item you would like to add from the drop down list at the top of the window. + + • (Required for Operators, Menus, Properties) + Click on the button to the right of the path field, this will bring up a searchable menu with a list of all paths, click on a path and the path field will be filled in. + + • (Optional, Operators Only) + The Args field will autofill with all possible arguments with their default values. Warning - If you want to modify them make sure to leave a space between the comma and the next argument. + + • (Optional) + Fill in the Name field if you want a custom name, otherwise the default name (for the operator/menu/property) will be used. + + • (Optional) + Select an icon from the list. + + • (Optional, Properties Only) + There are a number of checkboxes that control how the property is displayed in the menu, e.g. if you check the slider checkbox the item in the menu will appear (and work) as a slider and allow you to click and drag to change the value or if you just click on it you can type in a value. + + • (Required) + The last field on the window controls where the item is placed in the menu; the item will be placed directly under the item you specify from the list. + + • (Required) + Click the Add Item button to add the item. + + *Note - clicking the OK button does nothing and just closes the window + + + If you make a mistake the item will still show up in the menu, but it will be greyed out and have a warning icon. To fix this remove the item and re-add it. + + If you make a mistake with Operator arguments a submenu will appear at the bottom of the menu with a list of the items that have invalid arguments. + + To Remove An Item: + + • open the menu and click Edit Custom Menu. + + • Select Remove An Item from the drop down list at the top of the window. + + • Select which item to remove from the list. + + • Click the Remove Item button to remove the item. diff --git a/Utils/CustomMenu.xml b/Utils/CustomMenu.xml index c3e1c3b..f972be8 100644 --- a/Utils/CustomMenu.xml +++ b/Utils/CustomMenu.xml @@ -1,157 +1,5 @@ - - asdffdsafasdfasdfprop - none - NONE - False - False - False - False - False - False - False - True - - - asdffdsa - none - NONE - - - object.duplicate_moves - none - NONE - False - none - none - - - object.duplicate_move - none - NONE - False - OBJECT_OT_duplicate;TRANSFORM_OT_translate - {"linked":False, "mode":'TRANSLATION'};{"value":(0, 0, 0), "constraint_axis":(False, False, False), "constraint_orientation":'GLOBAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "texture_space":False, "remove_on_cancel":False,"release_confirm":False} - - - object.duplicate - none - NONE - False - linked;mode - False;'TRANSLATION' - - - object.duplicate - none - NONE - True - linked;mode - False;'TRANSLATION' - - - object.bake - none - NONE - True - type;pass_filter;filepath;width;height;margin;use_selected_to_active;cage_extrusion;cage_object;normal_space;normal_r;normal_g;normal_b;save_mode;use_clear;use_cage;use_split_materials;use_automatic_name;uv_layer - 'COMBINED';set();"";512;512;16;False;0;"";'TANGENT';'POS_X';'POS_Y';'POS_Z';'INTERNAL';False;False;False;False;"" - - - object.metaball_add - none - NONE - False - type;radius;view_align;enter_editmode;location;rotation;layers - 'BALL';1;False;False;(0, 0, 0);(0, 0, 0);(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,False) - - - object.metaball_add - none - NONE - True - type;radius;view_align;enter_editmode;location;rotation;layers - 'BALL';1;False;False;(0, 0, 0);(0, 0, 0);(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,False) - - - object.origin_set - none - NONE - True - type;center - 'GEOMETRY_ORIGIN';'MEDIAN' - - - object.origin_set - none - NONE - False - type;center - 'GEOMETRY_ORIGIN';'MEDIAN' - - - VIEW3D_MT_view - View - NONE - - - INFO_MT_file - none - NONE - - - klasjdflk;;; - none - NONE - False - False - False - False - False - False - False - True - - - context.scene.render.resolution_percentage - none - NONE - False - False - False - False - False - False - False - True - - - context.tool_settings.sculpt.constant_detail - Macguilicuty - PREVIEW_RANGE - False - False - False - False - False - False - False - True - - - context.tool_settings.sculpt.detail_size - none - NONE - False - False - True - False - False - False - False - True - General NONE @@ -165,19 +13,6 @@ none none - - ui79507jlfj))( - none - NONE - False - False - False - False - False - False - False - True - transform.tosphere none @@ -186,27 +21,6 @@ none none - - transform.shear - none - NONE - False - none - none - - - menulol - none - NONE - - - transform.bend - none - NONE - False - none - none - transform.push_pull none @@ -216,19 +30,6 @@ none - - context.tool_settings.sculpt.detail_size - none - NONE - False - False - False - False - False - False - False - True - Animation NONE @@ -236,7 +37,7 @@ anim.keyframe_insert_menu - none + Insert Keyframe NONE False none @@ -251,19 +52,13 @@ none - fsdfsdfdsfsdf + action.clean none NONE False none none - - action.clean - none - NONE - False - anim.keying_set_active_set none @@ -272,27 +67,8 @@ none none - - - INFO_MT_add - none - OBJECT_DATAMODE - - - VIEW3D_MT_select_object - none - RESTRICT_SELECT_OFF - - - view3d.edit_mesh_extrude_move_normal - Extrude - NONE - False - none - none - mesh.subdivide none @@ -302,24 +78,8 @@ none - mesh.loopcut_slide - none - NONE - False - none - none - - - mesh.spin - none - NONE - False - none - none - - - mesh.bisect - none + mesh.vertices_smooth + Smooth NONE False none @@ -333,55 +93,22 @@ none none - - - mesh.vertices_smooth - none - NONE - False - none - none - - object.vertex_random + mesh.edge_rotate none NONE False - none - none + use_ccw + False - transform.edge_slide + mesh.bridge_edge_loops none NONE False none none - - mesh.edge_rotate - none - NONE - False - use_ccw - False - - - - VIEW3D_MT_edit_mesh_vertices - none - NONE - - - VIEW3D_MT_edit_mesh_edges - none - NONE - - - VIEW3D_MT_edit_mesh_faces - none - NONE - @@ -437,6 +164,22 @@ True + + action.clickselect + none + NONE + False + none + none + + + action.clean + none + NONE + False + none + none + context.space_data.camera.field.strength none @@ -485,7 +228,32 @@ - + + + console.clear + none + MATERIAL + False + none + none + + + console.delete + none + NONE + False + none + none + + + console.clear_line + none + NONE + False + none + none + + text.find diff --git a/Utils/CustomMenu.xml.bkup b/Utils/CustomMenu.xml.bkup deleted file mode 100644 index 04cfba2..0000000 --- a/Utils/CustomMenu.xml.bkup +++ /dev/null @@ -1,183 +0,0 @@ - - - - General - NONE - - - - object.join - none - NONE - none - none - - - transform.tosphere - none - NONE - none - none - - - transform.shear - none - NONE - none - none - - - transform.bend - none - NONE - none - none - - - transform.push_pull - none - NONE - none - none - - - - Animation - NONE - - - - anim.keyframe_insert_menu - none - NONE - none - none - - - anim.keyframe_delete_v3d - none - NONE - none - none - - - anim.keying_set_active_set - none - NONE - none - none - - - - INFO_MT_add - none - OBJECT_DATAMODE - - - VIEW3D_MT_select_object - none - RESTRICT_SELECT_OFF - - - - - view3d.edit_mesh_extrude_move_normal - Extrude - NONE - none - none - - - mesh.subdivide - none - NONE - none - none - - - mesh.loopcut_slide - none - NONE - none - none - - - mesh.spin - none - NONE - none - none - - - mesh.bisect - none - NONE - none - none - - - mesh.vert_connect - none - NONE - none - none - - - - mesh.vertices_smooth - none - NONE - none - none - - - object.vertex_random - none - NONE - none - none - - - transform.edge_slide - none - NONE - none - none - - - mesh.edge_rotate - none - NONE - use_ccw - False - - - - VIEW3D_MT_edit_mesh_vertices - none - NONE - - - VIEW3D_MT_edit_mesh_edges - none - NONE - - - VIEW3D_MT_edit_mesh_faces - none - NONE - - - - - view3d.brushes_menu - none - BRUSH_DATA - - - view3d.dyn_detail - none - NONE - - - diff --git a/__init__.py b/__init__.py index 7c8550d..2a75a54 100644 --- a/__init__.py +++ b/__init__.py @@ -23,11 +23,11 @@ "name": "Advanced UI Menus Stable Version", "description": "Menus for advanced interaction with blender's UI", "author": "Ryan Inch", - "version": (1, 5), - "blender": (2, 77), + "version": (1, "5b"), + "blender": (2, 79), "location": "View3D - Multiple menus in multiple modes.", "warning": '', # used for warning icon and text in addons panel - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Advanced_UI_Menus", + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Advanced_UI_Menus_Full", "category": "User Interface"} import sys, os diff --git a/brush_menu.py b/brush_menu.py index 524eef9..5111bc2 100644 --- a/brush_menu.py +++ b/brush_menu.py @@ -1,6 +1,58 @@ from bpy.props import * from .Utils.core import * +def get_current_brush_icon(tool): + if get_mode() == sculpt: + icons = {"BLOB":'BRUSH_BLOB', + "CLAY":'BRUSH_CLAY', + "CLAY_STRIPS":'BRUSH_CLAY_STRIPS', + "CREASE":'BRUSH_CREASE', + "DRAW":'BRUSH_SCULPT_DRAW', + "FILL":'BRUSH_FILL', + "FLATTEN":'BRUSH_FLATTEN', + "GRAB":'BRUSH_GRAB', + "INFLATE":'BRUSH_INFLATE', + "LAYER":'BRUSH_LAYER', + "MASK":'BRUSH_MASK', + "NUDGE":'BRUSH_NUDGE', + "PINCH":'BRUSH_PINCH', + "ROTATE":'BRUSH_ROTATE', + "SCRAPE":'BRUSH_SCRAPE', + "SIMPLIFY":'BRUSH_SUBTRACT', + "SMOOTH":'BRUSH_SMOOTH', + "SNAKE_HOOK":'BRUSH_SNAKE_HOOK', + "THUMB":'BRUSH_THUMB'} + + elif get_mode() == vertex_paint: + icons = {"ADD":'BRUSH_ADD', + "BLUR":'BRUSH_BLUR', + "DARKEN":'BRUSH_DARKEN', + "LIGHTEN":'BRUSH_LIGHTEN', + "MIX":'BRUSH_MIX', + "MUL":'BRUSH_MULTIPLY', + "SUB":'BRUSH_SUBTRACT'} + + elif get_mode() == weight_paint: + icons = {"ADD":'BRUSH_ADD', + "BLUR":'BRUSH_BLUR', + "DARKEN":'BRUSH_DARKEN', + "LIGHTEN":'BRUSH_LIGHTEN', + "MIX":'BRUSH_MIX', + "MUL":'BRUSH_MULTIPLY', + "SUB":'BRUSH_SUBTRACT'} + + elif get_mode() == texture_paint: + icons = {"CLONE":'BRUSH_CLONE', + "DRAW":'BRUSH_TEXDRAW', + "FILL":'BRUSH_TEXFILL', + "MASK":'BRUSH_TEXMASK', + "SMEAR":'BRUSH_SMEAR', + "SOFTEN":'BRUSH_SOFTEN'} + + icon = icons[tool] + + return icon + class BrushOptionsMenu(bpy.types.Menu): bl_label = "Brush Options" bl_idname = "VIEW3D_MT_brush_options" @@ -28,20 +80,58 @@ def draw(self, context): self.particle(menu, context) def sculpt(self, menu, context): - menu.add_item().menu("VIEW3D_MT_brushes_menu") + brush = context.tool_settings.sculpt.brush + capabilities = brush.sculpt_capabilities + + menu.add_item().menu("VIEW3D_MT_brushes_menu", icon=get_current_brush_icon(brush.sculpt_tool)) menu.add_item().separator() + menu.add_item().menu(BrushRadiusMenu.bl_idname) menu.add_item().menu(BrushStrengthMenu.bl_idname) - if context.object.use_dynamic_topology_sculpting: + + if context.object.use_dynamic_topology_sculpting and brush.sculpt_tool != 'MASK': menu.add_item().menu(DynDetailMenu.bl_idname) - menu.add_item().menu(BrushAutosmoothMenu.bl_idname) + + if capabilities.has_auto_smooth: + menu.add_item().menu(BrushAutosmoothMenu.bl_idname) + + if capabilities.has_normal_weight: + menu.add_item().prop(brush, "normal_weight", slider=True) + + if capabilities.has_pinch_factor: + menu.add_item().prop(brush, "crease_pinch_factor", text ="Pinch", slider=True) + + if capabilities.has_rake_factor: + menu.add_item().prop(brush, "rake_factor", slider=True) + + if brush.sculpt_tool == 'MASK': + menu.add_item().prop_menu_enum(brush, "mask_tool") + + if capabilities.has_plane_offset: + menu.add_item().prop(brush, "plane_offset", slider=True) + menu.add_item().prop(brush, "use_plane_trim", text="Trim") + if brush.use_plane_trim: + menu.add_item().prop(brush, "plane_trim", slider=True, text="Distance") + + if capabilities.has_height: + menu.add_item().prop(brush, "height", slider=True) + menu.add_item().separator() + menu.add_item().menu(BrushModeMenu.bl_idname) - if context.object.use_dynamic_topology_sculpting: + menu.add_item().menu(DirectionMenu.bl_idname) + + if context.object.use_dynamic_topology_sculpting and brush.sculpt_tool != 'MASK': menu.add_item().menu(DetailMethodMenu.bl_idname) + + menu.add_item().prop(brush, "use_frontface", toggle=True) + + if capabilities.has_accumulate: + menu.add_item().prop(brush, "use_accumulate") + #menu.add_item().prop(context.tool_settings.sculpt.brush, "use_front_face", toggle=True) def vw_paint(self, menu, context): - menu.add_item().menu("VIEW3D_MT_brushes_menu") + menu.add_item().menu("VIEW3D_MT_brushes_menu", icon=get_current_brush_icon(context.tool_settings.vertex_paint.brush.vertex_tool)) menu.add_item().separator() if get_mode() == weight_paint: menu.add_item().menu(BrushWeightMenu.bl_idname) @@ -59,13 +149,40 @@ def texpaint(self, menu, context): menu.add_item().label("Missing Data", icon='ERROR') menu.add_item().label("See Tool Shelf") else: - menu.add_item().menu("VIEW3D_MT_brushes_menu") + menu.add_item().menu("VIEW3D_MT_brushes_menu", icon=get_current_brush_icon(toolsettings.brush.image_tool)) + menu.add_item().separator() - menu.add_item().operator(ColorPickerPopup.bl_idname, icon="COLOR") - menu.add_item().menu(BrushRadiusMenu.bl_idname) + + if toolsettings.brush.image_tool in {'DRAW', 'FILL'} and \ + toolsettings.brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}: + menu.add_item().operator(ColorPickerPopup.bl_idname, icon="COLOR") + + if toolsettings.brush.image_tool not in {'FILL'}: + menu.add_item().menu(BrushRadiusMenu.bl_idname) + menu.add_item().menu(BrushStrengthMenu.bl_idname) + + if toolsettings.brush.image_tool in {'MASK'}: + menu.add_item().menu(BrushWeightMenu.bl_idname, text="Mask Value") + + if toolsettings.brush.image_tool in {'SOFTEN'}: + menu.add_item().prop(toolsettings.brush, "sharp_threshold", text=PIW+"Sharp Threshold") + menu.add_item().separator() - menu.add_item().menu(BrushModeMenu.bl_idname) + + if toolsettings.brush.image_tool in {'DRAW'}: + menu.add_item().menu(BrushModeMenu.bl_idname) + + if toolsettings.brush.image_tool in {'SOFTEN'}: + menu.add_item().menu(DirectionMenu.bl_idname) + menu.add_item().menu(BlurMode.bl_idname) + + if toolsettings.brush.image_tool in {'DRAW', 'CLONE', 'MASK'}: + menu.add_item().prop(toolsettings.brush, "use_accumulate") + + menu.add_item().prop(toolsettings.brush, "use_alpha") + menu.add_item().prop(toolsettings.brush, "use_gradient") + def particle(self, menu, context): if context.tool_settings.particle_edit.tool == 'NONE': @@ -90,13 +207,11 @@ def particle(self, menu, context): if context.tool_settings.particle_edit.tool == 'LENGTH': menu.add_item().separator() - menu.add_item().prop(context.tool_settings.particle_edit.brush, - "length_mode", text="") + menu.add_item().menu(ParticleLengthMenu.bl_idname) if context.tool_settings.particle_edit.tool == 'PUFF': menu.add_item().separator() - menu.add_item().prop(context.tool_settings.particle_edit.brush, - "puff_mode", text="") + menu.add_item().menu(ParticlePuffMenu.bl_idname) menu.add_item().prop(context.tool_settings.particle_edit.brush, "use_puff_volume", toggle=True) @@ -207,9 +322,13 @@ def init(self): datapath = "tool_settings.sculpt.detail_size" slider_setting = "detail_size" - else: + elif bpy.context.tool_settings.sculpt.detail_type_method == 'CONSTANT': datapath = "tool_settings.sculpt.constant_detail" slider_setting = "constant_detail" + + elif bpy.context.tool_settings.sculpt.detail_type_method == 'BRUSH': + datapath = "tool_settings.sculpt.detail_percent" + slider_setting = "detail_percent" return settings, datapath, slider_setting @@ -236,20 +355,12 @@ def draw(self, context): refine_path = "tool_settings.sculpt.detail_refine_method" type_path = "tool_settings.sculpt.detail_type_method" - refine_items = [["Subdivide Edges", 'SUBDIVIDE'], - ["Collapse Edges", 'COLLAPSE'], - ["Subdivide Collapse", 'SUBDIVIDE_COLLAPSE']] - - type_items = [["Relative Detail", 'RELATIVE'], - ["Constant Detail", 'CONSTANT']] - - menu.add_item().label("Refine") menu.add_item().separator() # add the refine menu items - for item in refine_items: - menuprop(menu.add_item(), item[0], item[1], refine_path, disable=True, + for item in context.tool_settings.sculpt.bl_rna.properties['detail_refine_method'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, refine_path, disable=True, icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON') menu.add_item().label("") @@ -258,84 +369,50 @@ def draw(self, context): menu.add_item().separator() # add the type menu items - for item in type_items: - menuprop(menu.add_item(), item[0], item[1], type_path, disable=True, + for item in context.tool_settings.sculpt.bl_rna.properties['detail_type_method'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, type_path, disable=True, icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON') class BrushModeMenu(bpy.types.Menu): - bl_label = "Brush Mode" + bl_label = "Mode" bl_idname = "VIEW3D_MT_brush_mode_menu" def init(self): if get_mode() == sculpt: + enum = bpy.context.tool_settings.sculpt.brush.bl_rna.properties['sculpt_plane'].enum_items path = "tool_settings.sculpt.brush.sculpt_plane" - brushmodes = [["Area Plane", 'AREA'], - ["View Plane", 'VIEW'], - ["X Plane", 'X'], - ["Y Plane", 'Y'], - ["Z Plane", 'Z']] elif get_mode() == texture_paint: + enum = bpy.context.tool_settings.image_paint.brush.bl_rna.properties['blend'].enum_items path = "tool_settings.image_paint.brush.blend" - brushmodes = [["Mix", 'MIX'], - ["Add", 'ADD'], - ["Subtract", 'SUB'], - ["Multiply", 'MUL'], - ["Lighten", 'LIGHTEN'], - ["Darken", 'DARKEN'], - ["Erase Alpha", 'ERASE_ALPHA'], - ["Add Alpha", 'ADD_ALPHA'], - ["Overlay", 'OVERLAY'], - ["Hard Light", 'HARDLIGHT'], - ["Color Burn", 'COLORBURN'], - ["Linear Burn", 'LINEARBURN'], - ["Color Dodge", 'COLORDODGE'], - ["Screen", 'SCREEN'], - ["Soft Light", 'SOFTLIGHT'], - ["Pin Light", 'PINLIGHT'], - ["Vivid Light", 'VIVIDLIGHT'], - ["Linear Light", 'LINEARLIGHT'], - ["Difference", 'DIFFERENCE'], - ["Exclusion", 'EXCLUSION'], - ["Hue", 'HUE'], - ["Saturation", 'SATURATION'], - ["Luminosity", 'LUMINOSITY'], - ["Color", 'COLOR'], - ] else: + enum = bpy.context.tool_settings.vertex_paint.brush.bl_rna.properties['vertex_tool'].enum_items path = "tool_settings.vertex_paint.brush.vertex_tool" - brushmodes = [["Mix", 'MIX'], - ["Add", 'ADD'], - ["Subtract", 'SUB'], - ["Multiply", 'MUL'], - ["Blur", 'BLUR'], - ["Lighten", 'LIGHTEN'], - ["Darken", 'DARKEN']] - return path, brushmodes + return enum, path def draw(self, context): - path, brushmodes = self.init() + enum, path = self.init() menu = Menu(self) - menu.add_item().label(text="Brush Mode") + menu.add_item().label(text="Mode") menu.add_item().separator() if get_mode() == texture_paint: column_flow = menu.add_item("column_flow", columns=2) # add all the brush modes to the menu - for brush in brushmodes: - menuprop(menu.add_item(parent=column_flow), brush[0], - brush[1], path, icon='RADIOBUT_OFF', + for brush in enum: + menuprop(menu.add_item(parent=column_flow), brush.name, + brush.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') else: # add all the brush modes to the menu - for brush in brushmodes: - menuprop(menu.add_item(), brush[0], - brush[1], path, icon='RADIOBUT_OFF', + for brush in enum: + menuprop(menu.add_item(), brush.name, + brush.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') class BrushAutosmoothMenu(bpy.types.Menu): @@ -373,6 +450,15 @@ class BrushWeightMenu(bpy.types.Menu): bl_idname = "VIEW3D_MT_brush_weight_menu" def draw(self, context): + if get_mode() == weight_paint: + brush = context.tool_settings.unified_paint_settings + brushstr = "tool_settings.unified_paint_settings.weight" + name = "Weight" + else: + brush = context.tool_settings.image_paint.brush + brushstr = "tool_settings.image_paint.brush.weight" + name = "Mask Value" + menu = Menu(self) settings = [["1.0", 1.0], ["0.7", 0.7], @@ -382,14 +468,14 @@ def draw(self, context): ["0.1", 0.1]] # add the top slider - menu.add_item().prop(context.tool_settings.unified_paint_settings, - "weight", slider=True) + menu.add_item().prop(brush, + "weight", text=name, slider=True) menu.add_item().separator() # add the rest of the menu items for i in range(len(settings)): menuprop(menu.add_item(), settings[i][0], settings[i][1], - "tool_settings.unified_paint_settings.weight", + brushstr, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') @@ -422,6 +508,41 @@ def draw(self, context): "tool_settings.particle_edit.brush.count", icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') + +class DirectionMenu(bpy.types.Menu): + bl_label = "Direction" + bl_idname = "VIEW3D_MT_direction_menu" + + def draw(self, context): + menu = Menu(self) + if get_mode() == sculpt: + path = context.tool_settings.sculpt.brush + else: + path = context.tool_settings.image_paint.brush + + menu.add_item().label(text="Direction") + menu.add_item().separator() + + # add the menu items + menu.add_item().props_enum(path, "direction") + +class BlurMode(bpy.types.Menu): + bl_label = "Blur Mode" + bl_idname = "VIEW3D_MT_blur_mode" + + def draw(self, context): + menu = Menu(self) + path = "tool_settings.image_paint.brush.blur_mode" + + menu.add_item().label(text="Blur Mode") + menu.add_item().separator() + + # add the menu items + for item in context.tool_settings.image_paint.brush.bl_rna.properties['blur_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON') class ParticleLengthMenu(bpy.types.Menu): bl_label = "Length Mode" @@ -429,16 +550,14 @@ class ParticleLengthMenu(bpy.types.Menu): def draw(self, context): menu = Menu(self) - datapath = "tool_settings.particle_edit.brush.length_mode" + path = "tool_settings.particle_edit.brush.length_mode" # add the menu items - menuprop(menu.add_item(), "Grow", "GROW", - datapath, icon='RADIOBUT_OFF', - disable=True, disable_icon='RADIOBUT_ON') - - menuprop(menu.add_item(), "Shrink", "SHRINK", - datapath, icon='RADIOBUT_OFF', - disable=True, disable_icon='RADIOBUT_ON') + for item in context.tool_settings.particle_edit.brush.bl_rna.properties['length_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON') class ParticlePuffMenu(bpy.types.Menu): bl_label = "Puff Mode" @@ -446,17 +565,43 @@ class ParticlePuffMenu(bpy.types.Menu): def draw(self, context): menu = Menu(self) - datapath = "tool_settings.particle_edit.brush.puff_mode" + path = "tool_settings.particle_edit.brush.puff_mode" # add the menu items - menuprop(menu.add_item(), "Add", "ADD", - datapath, icon='RADIOBUT_OFF', - disable=True, disable_icon='RADIOBUT_ON') - - menuprop(menu.add_item(), "Sub", "SUB", - datapath, icon='RADIOBUT_OFF', - disable=True, disable_icon='RADIOBUT_ON') - + for item in context.tool_settings.particle_edit.brush.bl_rna.properties['puff_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON') + +class FlipColorsTex(bpy.types.Operator): + bl_label = "Flip Colors" + bl_idname = "view3d.flip_colors_tex" + + def execute(self, context): + try: + bpy.ops.paint.brush_colors_flip() + except: + pass + + return {'FINISHED'} + +class FlipColorsVert(bpy.types.Operator): + bl_label = "Flip Colors" + bl_idname = "view3d.flip_colors_vert" + + def execute(self, context): + color = context.tool_settings.vertex_paint.brush.color + secondary_color = context.tool_settings.vertex_paint.brush.secondary_color + + orig_prim = color.hsv + orig_sec = secondary_color.hsv + + color.hsv = orig_sec + secondary_color.hsv = orig_prim + + return {'FINISHED'} + class ColorPickerPopup(bpy.types.Operator): bl_label = "Color" bl_idname = "view3d.color_picker_popup" @@ -478,6 +623,11 @@ def draw(self, context): menu.add_item().template_color_picker(brush, "color", value_slider=True) menu.add_item().prop(brush, "color", text="") + menu.current_item.prop(brush, "secondary_color", text="") + if get_mode() == vertex_paint: + menu.current_item.operator("view3d.flip_colors_vert", icon='FILE_REFRESH', text="") + else: + menu.current_item.operator("view3d.flip_colors_tex", icon='FILE_REFRESH', text="") if settings.palette: menu.add_item("column").template_palette(settings, "palette", color=True) diff --git a/custom_menu.py b/custom_menu.py index ddd2523..51a9063 100644 --- a/custom_menu.py +++ b/custom_menu.py @@ -132,9 +132,12 @@ def fill_operator_list(): ent_op = text.split("\n")[1] op_path = ent_op[8:str.find(ent_op, "(")] if ent_op.startswith("bpy.ops.") and not "import." in ent_op: - op = eval("{0}.get_rna()".format(ent_op[:str.find(ent_op, "(")])) - op_name = op.bl_rna.name - operators.append((op_path, op_path.split(".")[0].upper() + " - " + op_name, op_path)) + try: + op = eval("{0}.get_rna()".format(ent_op[:str.find(ent_op, "(")])) + op_name = op.bl_rna.name + operators.append((op_path, op_path.split(".")[0].upper() + " - " + op_name, op_path)) + except: + print("\nError could not parse operator: {0}\n".format(ent_op[:str.find(ent_op, "(")])) op_list = operators @@ -899,7 +902,7 @@ def register(): default=True, name="Emboss" ) - + # create the global hotkey wm = bpy.context.window_manager modes = [['3D View', 'VIEW_3D'], ['Timeline', 'TIMELINE'], ['Graph Editor', 'GRAPH_EDITOR'], ['Dopesheet', 'DOPESHEET_EDITOR'], ['NLA Editor', 'NLA_EDITOR'], diff --git a/dyntopo_menu.py b/dyntopo_menu.py index dc7553e..7e3e02b 100644 --- a/dyntopo_menu.py +++ b/dyntopo_menu.py @@ -39,20 +39,14 @@ class SymmetrizeMenu(bpy.types.Menu): def draw(self, context): menu = Menu(self) path = "tool_settings.sculpt.symmetrize_direction" - items = [["-X to +X", 'NEGATIVE_X'], - ["+X to -X", 'POSITIVE_X'], - ["-Y to +Y", 'NEGATIVE_Y'], - ["+Y to -Y", 'POSITIVE_Y'], - ["-Z to +Z", 'NEGATIVE_Z'], - ["+Z to -Z", 'POSITIVE_Z']] # add the the symmetrize operator to the menu menu.add_item().operator("sculpt.symmetrize") menu.add_item().separator() # add the rest of the menu items - for item in items: - menuprop(menu.add_item(), item[0], item[1], path, disable=True, + for item in context.tool_settings.sculpt.bl_rna.properties['symmetrize_direction'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, disable=True, icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON') diff --git a/manipulator_menu.py b/manipulator_menu.py index 0271d48..aaa81a6 100644 --- a/manipulator_menu.py +++ b/manipulator_menu.py @@ -66,7 +66,7 @@ def draw(self, context): class TransformOrientationMenu(bpy.types.Menu): bl_label = "Transform Orientation" - bl_idname = "VIEW3D_MT_manipulator_menu_2" + bl_idname = "VIEW3D_MT_transf_orient_menu" hotkey = True @@ -77,7 +77,10 @@ def draw(self, context): menu.add_item().label(text="Transform Orientation") menu.add_item().separator() - menu.add_item().props_enum(bpy.context.space_data, "transform_orientation") + #menu.add_item().props_enum(bpy.context.space_data, "transform_orientation") + for mode in context.space_data.bl_rna.properties['transform_orientation'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "space_data.transform_orientation", + icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') ### ------------ New hotkeys and registration ------------ ### diff --git a/mode_menu.py b/mode_menu.py index 7e47a99..85de46b 100644 --- a/mode_menu.py +++ b/mode_menu.py @@ -70,8 +70,8 @@ def init(self): ["Weight Paint", weight_paint, "WPAINT_HLT"], ["Texture Paint", texture_paint, "TPAINT_HLT"]] - if len(bpy.context.object.particle_systems.items()) > 0: \ - modes.append(["Particle Edit", particle_edit, "PARTICLEMODE"]) + if len(bpy.context.object.particle_systems.items()) > 0: + modes.append(["Particle Edit", particle_edit, "PARTICLEMODE"]) elif ob_type == 'ARMATURE': modes = [["Object", object_mode, "OBJECT_DATAMODE"], diff --git a/proportional_menu.py b/proportional_menu.py index 2f79206..48ca335 100644 --- a/proportional_menu.py +++ b/proportional_menu.py @@ -94,24 +94,13 @@ def poll(self, context): else: return False - def init(self): - modes = [["Disabled", 'DISABLED', "PROP_OFF"], - ["Enabled", 'ENABLED', "PROP_ON"], - ["Projected(2D)", 'PROJECTED', "PROP_ON"], - ["Connected", 'CONNECTED', "PROP_CON"]] - - datapath = "tool_settings.proportional_edit" - - return modes, datapath - def draw(self, context): - modes, datapath = self.init() menu = Menu(self) # add the items to the menu - for mode in modes: - menuprop(menu.add_item(), mode[0], mode[1], datapath, - icon=mode[2], disable=True) + for mode in context.tool_settings.bl_rna.properties['proportional_edit'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.proportional_edit", + icon=mode.icon, disable=True) class FalloffMenu(bpy.types.Menu): bl_label = "Falloff Menu" @@ -126,19 +115,11 @@ def poll(self, context): def draw(self, context): menu = Menu(self) - - modes = [["Smooth", 'SMOOTH', "SMOOTHCURVE"], - ["Sphere", 'SPHERE', "SPHERECURVE"], - ["Root", 'ROOT', "ROOTCURVE"], - ["Sharp", 'SHARP', "SHARPCURVE"], - ["Linear", 'LINEAR', "LINCURVE"], - ["Constant", 'CONSTANT', "NOCURVE"], - ["Random", 'RANDOM', "RNDCURVE"]] # add the items to the menu - for mode in modes: - menuprop(menu.add_item(), mode[0], mode[1], "tool_settings.proportional_edit_falloff", - icon=mode[2], disable=True) + for mode in context.tool_settings.bl_rna.properties['proportional_edit_falloff'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.proportional_edit_falloff", + icon=mode.icon, disable=True) ### ------------ New hotkeys and registration ------------ ### diff --git a/shade_menu.py b/shade_menu.py index 89a0178..1a4a637 100644 --- a/shade_menu.py +++ b/shade_menu.py @@ -87,7 +87,7 @@ def draw(self, context): icon=mode[2], disable=True) # add a shading options menu if object can be shaded smooth/flat - if bpy.context.object.type in ['MESH', 'CURVE', 'SURFACE']: + if bpy.context.object and bpy.context.object.type in ['MESH', 'CURVE', 'SURFACE']: menu.add_item().separator() if context.object.use_dynamic_topology_sculpting: menu.add_item().prop(context.tool_settings.sculpt, "use_smooth_shading", toggle=True) diff --git a/snap_menu.py b/snap_menu.py index 147eedd..7d162fd 100644 --- a/snap_menu.py +++ b/snap_menu.py @@ -50,15 +50,11 @@ def draw(self, context): # menu for node editor if context.space_data.type == 'NODE_EDITOR': - modes = [["Grid", 'GRID', "SNAP_GRID"], - ["Node X", 'NODE_X', "SNAP_EDGE"], - ["Node Y", 'NODE_Y', "SNAP_EDGE"], - ["Node X/Y", 'NODE_XY', "SNAP_EDGE"]] # add the menu items - for mode in modes: - menuprop(menu.add_item(), mode[0], mode[1], "tool_settings.snap_node_element", - icon=mode[2], disable=True) + for mode in context.tool_settings.bl_rna.properties['snap_node_element'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_node_element", + icon=mode.icon, disable=True) if snap_element != "INCREMENT": menu.add_item().separator() @@ -66,16 +62,11 @@ def draw(self, context): # menu for 3d view if context.space_data.type == 'VIEW_3D': - modes = [["Increment", 'INCREMENT', "SNAP_INCREMENT"], - ["Vertex", 'VERTEX', "SNAP_VERTEX"], - ["Edge", 'EDGE', "SNAP_EDGE"], - ["Face", 'FACE', "SNAP_FACE"], - ["Volume", 'VOLUME', "SNAP_VOLUME"]] # add the menu items - for mode in modes: - menuprop(menu.add_item(), mode[0], mode[1], "tool_settings.snap_element", - icon=mode[2], disable=True) + for mode in context.tool_settings.bl_rna.properties['snap_element'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_element", + icon=mode.icon, disable=True) if snap_element != "INCREMENT": menu.add_item().separator() @@ -104,17 +95,13 @@ class SnapTargetMenu(bpy.types.Menu): def draw(self, context): menu = Menu(self) - modes = [["Active", 'ACTIVE'], - ["Median", 'MEDIAN'], - ["Center", 'CENTER'], - ["Closest", 'CLOSEST']] menu.add_item().label(text="Snap Target") menu.add_item().separator() # add the menu items - for mode in modes: - menuprop(menu.add_item(), mode[0], mode[1], "tool_settings.snap_target", disable=True) + for mode in context.tool_settings.bl_rna.properties['snap_target'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_target", disable=True) ### ------------ New hotkeys and registration ------------ ### diff --git a/stroke_menu.py b/stroke_menu.py index 1dc7607..3e9eac8 100644 --- a/stroke_menu.py +++ b/stroke_menu.py @@ -22,48 +22,63 @@ def poll(self, context): def init(self): if get_mode() == sculpt: - brush = bpy.context.tool_settings.sculpt.brush + settings = bpy.context.tool_settings.sculpt + brush = settings.brush + if bpy.app.version > (2, 71): - stroke_method = bpy.context.tool_settings.sculpt.brush.stroke_method + stroke_method = brush.stroke_method else: - stroke_method = bpy.context.tool_settings.sculpt.brush.sculpt_stroke_method + stroke_method = brush.sculpt_stroke_method elif get_mode() == texture_paint: - brush = bpy.context.tool_settings.image_paint.brush - stroke_method = bpy.context.tool_settings.image_paint.brush.stroke_method + settings = bpy.context.tool_settings.image_paint + brush = settings.brush + stroke_method = brush.stroke_method else: - brush = bpy.context.tool_settings.vertex_paint.brush - stroke_method = bpy.context.tool_settings.vertex_paint.brush.stroke_method + settings = bpy.context.tool_settings.vertex_paint + brush = settings.brush + stroke_method = brush.stroke_method - return stroke_method, brush + return settings, brush, stroke_method def draw(self, context): - stroke_method, brush = self.init() + settings, brush, stroke_method = self.init() menu = Menu(self) menu.add_item().menu(StrokeMethodMenu.bl_idname) + + menu.add_item().separator() if stroke_method == space: - menu.add_item().prop(brush, "spacing", slider=True) + menu.add_item().prop(brush, "spacing", text=PIW+"Spacing", slider=True) elif stroke_method == airbrush: - menu.add_item().prop(brush, "rate", slider=True) - + menu.add_item().prop(brush, "rate", text=PIW+"Rate", slider=True) + + elif stroke_method == anchored: + menu.add_item().prop(brush, "use_edge_to_edge") + else: pass - - menu.add_item().prop(brush, "jitter", slider=True) - menu.add_item().separator() + if get_mode() == sculpt and stroke_method in [drag_dot, anchored]: + pass + else: + menu.add_item().prop(brush, "jitter", text=PIW+"Jitter", slider=True) + + menu.add_item().prop(settings, "input_samples", text=PIW+"Input Samples", slider=True) - menu.add_item().prop(brush, "use_smooth_stroke", toggle=True) + if stroke_method in [dots, space, airbrush]: + menu.add_item().separator() + + menu.add_item().prop(brush, "use_smooth_stroke", toggle=True) - if brush.use_smooth_stroke: - menu.add_item().prop(brush, "smooth_stroke_radius", text="Radius", slider=True) - menu.add_item().prop(brush, "smooth_stroke_factor", text="Factor", slider=True) + if brush.use_smooth_stroke: + menu.add_item().prop(brush, "smooth_stroke_radius", text=PIW+"Radius", slider=True) + menu.add_item().prop(brush, "smooth_stroke_factor", text=PIW+"Factor", slider=True) class StrokeMethodMenu(bpy.types.Menu): bl_label = "Stroke Method" @@ -71,43 +86,32 @@ class StrokeMethodMenu(bpy.types.Menu): def init(self): if get_mode() == sculpt: + brush = bpy.context.tool_settings.sculpt.brush path = "tool_settings.sculpt.brush.stroke_method" - tools = [["Airbrush", airbrush], - ["Anchored", anchored], - ["Space", space], - ["Drag Dot", drag_dot], - ["Dots", dots], - ["Line", line], - ["Curve", curve]] elif get_mode() == texture_paint: + brush = bpy.context.tool_settings.image_paint.brush path = "tool_settings.image_paint.brush.stroke_method" - tools = [["Airbrush", airbrush], - ["Space", space], - ["Dots", dots], - ["Line", line], - ["Curve", curve]] else: + brush = bpy.context.tool_settings.vertex_paint.brush path = "tool_settings.vertex_paint.brush.stroke_method" - tools = [["Airbrush", airbrush], - ["Space", space], - ["Dots", dots], - ["Line", line], - ["Curve", curve]] - return path, tools + return brush, path def draw(self, context): - path, tools = self.init() + brush, path = self.init() menu = Menu(self) menu.add_item().label(text="Stroke Method") - menu.add_item().separator() + menu.add_item().separator() - # add the menu items - for tool in tools: - menuprop(menu.add_item(), tool[0], tool[1], path, + # add the menu items dynamicaly based on values in enum property + for tool in brush.bl_rna.properties['stroke_method'].enum_items: + if tool.identifier in [anchored, drag_dot] and get_mode() in [vertex_paint, weight_paint]: + continue + + menuprop(menu.add_item(), tool.name, tool.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') diff --git a/texture_menu.py b/texture_menu.py index 8696819..7ca8eea 100644 --- a/texture_menu.py +++ b/texture_menu.py @@ -199,46 +199,30 @@ def draw(self, context): if get_mode() == sculpt: path = "tool_settings.sculpt.brush.texture_slot.map_mode" - items = [["View Plane", 'VIEW_PLANE'], - ["Area Plane", 'AREA_PLANE'], - ["Tiled", 'TILED'], - ["3D", '3D'], - ["Random", 'RANDOM'], - ["Stencil", 'STENCIL']] # add the menu items - for item in items: - menuprop(menu.add_item(), item[0], item[1], path, + for item in context.tool_settings.sculpt.brush.texture_slot.bl_rna.properties['map_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') elif get_mode() == vertex_paint: path = "tool_settings.vertex_paint.brush.texture_slot.tex_paint_map_mode" - items = [["View Plane", 'VIEW_PLANE'], - ["Tiled", 'TILED'], - ["3D", '3D'], - ["Random", 'RANDOM'], - ["Stencil", 'STENCIL']] # add the menu items - for item in items: - menuprop(menu.add_item(), item[0], item[1], path, + for item in context.tool_settings.vertex_paint.brush.texture_slot.bl_rna.properties['tex_paint_map_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') else: path = "tool_settings.image_paint.brush.texture_slot.tex_paint_map_mode" - items = [["View Plane", 'VIEW_PLANE'], - ["Tiled", 'TILED'], - ["3D", '3D'], - ["Random", 'RANDOM'], - ["Stencil", 'STENCIL']] # add the menu items - for item in items: - menuprop(menu.add_item(), item[0], item[1], path, + for item in context.tool_settings.image_paint.brush.texture_slot.bl_rna.properties['tex_paint_map_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') @@ -282,17 +266,13 @@ def draw(self, context): menu = Menu(self) path = "tool_settings.image_paint.brush.mask_texture_slot.mask_map_mode" - items = [["View Plane", 'VIEW_PLANE'], - ["Tiled", 'TILED'], - ["Random", 'RANDOM'], - ["Stencil", 'STENCIL']] menu.add_item().label(text="Mask Mapping") menu.add_item().separator() # add the menu items - for item in items: - menuprop(menu.add_item(), item[0], item[1], path, + for item in context.tool_settings.image_paint.brush.mask_texture_slot.bl_rna.properties['mask_map_mode'].enum_items: + menuprop(menu.add_item(), item.name, item.identifier, path, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') @@ -303,17 +283,17 @@ class TextureAngleSource(bpy.types.Menu): def draw(self, context): menu = Menu(self) - items = [["User", 'USER'], - ["Rake", 'RAKE'], - ["Random", 'RANDOM']] if get_mode() == sculpt: + items = context.tool_settings.sculpt.brush.bl_rna.properties['texture_angle_source_random'].enum_items path = "tool_settings.sculpt.brush.texture_angle_source_random" elif get_mode() == vertex_paint: + items = context.tool_settings.vertex_paint.brush.bl_rna.properties['texture_angle_source_random'].enum_items path = "tool_settings.vertex_paint.brush.texture_angle_source_random" else: + items = context.tool_settings.image_paint.brush.bl_rna.properties['texture_angle_source_random'].enum_items path = "tool_settings.image_paint.brush.texture_angle_source_random" # add the menu items From 0ad484fff40c0a15a8220822351841c144eb4732 Mon Sep 17 00:00:00 2001 From: schroef Date: Sat, 12 May 2018 04:03:12 -0400 Subject: [PATCH 2/2] - Added shortcuts to pref panel --- __init__.py | 95 ++++++------ extrude_menu.py | 76 +++++----- layers_window.py | 342 ++++++++++++++++++++++--------------------- manipulator_menu.py | 176 +++++++++++----------- mode_menu.py | 227 ++++++++++++++-------------- preferences.py | 76 ++++++++++ proportional_menu.py | 283 +++++++++++++++++------------------ shade_menu.py | 266 ++++++++++++++++----------------- snap_menu.py | 208 +++++++++++++------------- 9 files changed, 927 insertions(+), 822 deletions(-) create mode 100644 preferences.py diff --git a/__init__.py b/__init__.py index 2a75a54..2245e27 100644 --- a/__init__.py +++ b/__init__.py @@ -20,15 +20,15 @@ """ Copyright 2011 GPL licence applies""" bl_info = { - "name": "Advanced UI Menus Stable Version", - "description": "Menus for advanced interaction with blender's UI", - "author": "Ryan Inch", - "version": (1, "5b"), - "blender": (2, 79), - "location": "View3D - Multiple menus in multiple modes.", - "warning": '', # used for warning icon and text in addons panel - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Advanced_UI_Menus_Full", - "category": "User Interface"} + "name": "Advanced UI Menus Stable Version", + "description": "Menus for advanced interaction with blender's UI", + "author": "Ryan Inch", + "version": (1, "5b"), + "blender": (2, 79), + "location": "View3D - Multiple menus in multiple modes.", + "warning": '', # used for warning icon and text in addons panel + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Advanced_UI_Menus_Full", + "category": "User Interface"} import sys, os @@ -53,46 +53,47 @@ from . import symmetry_menu from . import texture_menu from . import view_menu +from . import preferences -addon_files = [ - brush_menu, - curve_menu, - custom_menu, - delete_menu, - dyntopo_menu, - extrude_menu, - layers_window, - manipulator_menu, - mode_menu, - pivot_menu, - proportional_menu, - selection_menu, - shade_menu, - snap_menu, - stroke_menu, - symmetry_menu, - texture_menu, - view_menu - ] +addon_files = [ + brush_menu, + curve_menu, + custom_menu, + delete_menu, + dyntopo_menu, + extrude_menu, + layers_window, + manipulator_menu, + mode_menu, + pivot_menu, + proportional_menu, + selection_menu, + shade_menu, + snap_menu, + stroke_menu, + symmetry_menu, + texture_menu, + view_menu + ] def register(): - # register all blender classes - bpy.utils.register_module(__name__) - - # register all files - for addon_file in addon_files: - addon_file.register() - + # register all blender classes + bpy.utils.register_module(__name__) + + # register all files + for addon_file in addon_files: + addon_file.register() + def unregister(): - # unregister all files - for addon_file in addon_files: - addon_file.unregister() - - # delete all the properties you have created - del_props() - - # unregister all blender classes - bpy.utils.unregister_module(__name__) - + # unregister all files + for addon_file in addon_files: + addon_file.unregister() + + # delete all the properties you have created + del_props() + + # unregister all blender classes + bpy.utils.unregister_module(__name__) + if __name__ == "__main__": - register() + register() diff --git a/extrude_menu.py b/extrude_menu.py index 46615ab..2bf6e16 100644 --- a/extrude_menu.py +++ b/extrude_menu.py @@ -1,49 +1,53 @@ from .Utils.core import * +from bpy.props import StringProperty class ExtrudeMenuOperator(bpy.types.Operator): - bl_label = "Extrude Menu Operator" - bl_idname = "view3d.extrude_menu_operator" - - def modal(self, context, event): - current_time = time.time() - - # if key has been held for more than 0.3 seconds call the menu - if event.value == 'RELEASE' and current_time > self.start_time + 0.3: - bpy.ops.wm.call_menu(name="VIEW3D_MT_edit_mesh_extrude") - - return {'FINISHED'} - - # else extrude the selection - elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: - bpy.ops.view3d.edit_mesh_extrude_move_normal() - - return {'FINISHED'} - - else: - return {'RUNNING_MODAL'} - - def execute(self, context): - self.start_time = time.time() - context.window_manager.modal_handler_add(self) - - return {'RUNNING_MODAL'} - + bl_label = "Extrude Menu Operator" + bl_idname = "view3d.extrude_menu_operator" + + name = StringProperty(name="Name") + + def modal(self, context, event): + current_time = time.time() + name = "Extrude Menu" + # if key has been held for more than 0.3 seconds call the menu + if event.value == 'RELEASE' and current_time > self.start_time + 0.3: + bpy.ops.wm.call_menu(name="VIEW3D_MT_edit_mesh_extrude") + + return {'FINISHED'} + + # else extrude the selection + elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: + bpy.ops.view3d.edit_mesh_extrude_move_normal() + + return {'FINISHED'} + + else: + return {'RUNNING_MODAL'} + + def execute(self, context): + self.start_time = time.time() + context.window_manager.modal_handler_add(self) + + return {'RUNNING_MODAL'} + ### ------------ New hotkeys and registration ------------ ### addon_keymaps = [] def register(): - # create the global hotkey - wm = bpy.context.window_manager - km = wm.keyconfigs.addon.keymaps.new(name='Mesh') - kmi = km.keymap_items.new('view3d.extrude_menu_operator', 'E', 'PRESS') - addon_keymaps.append((km, kmi)) + # create the global hotkey + wm = bpy.context.window_manager + km = wm.keyconfigs.addon.keymaps.new(name='Mesh') + kmi = km.keymap_items.new('view3d.extrude_menu_operator', 'E', 'PRESS') + kmi.properties.name = "Extrude" + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() diff --git a/layers_window.py b/layers_window.py index 62ddd6d..075206e 100644 --- a/layers_window.py +++ b/layers_window.py @@ -1,186 +1,190 @@ from .Utils.core import * - +from bpy.props import StringProperty + def get_layers(context): - # if the layer management addon is enabled name the layers with the layer names - try: - layernames = [] - # if the name has "layer" in front of a number remove "layer" and leave the number - for x in range(20): - layer_name = context.scene.namedlayers.layers[x].name - if layer_name in ["Layer{}".format(x+1), "Layer0{}".format(x+1)]: - layernames.append("{0}".format(x+1)) - else: - # replace blank layer names with a space so the button will be full length - layernames.append(layer_name if layer_name is not "" else " ") - - # if not then name the layers with numbers - except: - layernames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", - "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"] - - return layernames - + # if the layer management addon is enabled name the layers with the layer names + try: + layernames = [] + # if the name has "layer" in front of a number remove "layer" and leave the number + for x in range(20): + layer_name = context.scene.namedlayers.layers[x].name + if layer_name in ["Layer{}".format(x+1), "Layer0{}".format(x+1)]: + layernames.append("{0}".format(x+1)) + else: + # replace blank layer names with a space so the button will be full length + layernames.append(layer_name if layer_name is not "" else " ") + + # if not then name the layers with numbers + except: + layernames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"] + + return layernames + def set_layer_func(self, context, event): - if event.shift: - # toggle the layer on/off - context.scene.layers[self.layer_num] = not context.scene.layers[self.layer_num] - bpy.types.Scene.layer_changed = True - else: - # create a boolian list of which layers on and off - layers = [False]*20 - layers[self.layer_num] = True - - # apply the list to blender's layers - context.scene.layers = layers - - bpy.types.Scene.layer_changed = True - - return {'FINISHED'} - + if event.shift: + # toggle the layer on/off + context.scene.layers[self.layer_num] = not context.scene.layers[self.layer_num] + bpy.types.Scene.layer_changed = True + else: + # create a boolian list of which layers on and off + layers = [False]*20 + layers[self.layer_num] = True + + # apply the list to blender's layers + context.scene.layers = layers + + bpy.types.Scene.layer_changed = True + + return {'FINISHED'} + custom_ops = [] - + def add_set_layer_op(num, layer): - op_name = 'view3d.set_layer_view_'+str(num) - - nc = type( 'DynOpSetLayer_'+str(num), - (bpy.types.Operator, ), - {'bl_idname': op_name, - 'bl_label': "Set Layer View", - 'bl_description': "Visualize this Layer, Shift-Click to select multiple layers\nName: "+layer, - 'layer_num': bpy.props.IntProperty(name="layer_num"), - 'invoke': set_layer_func - }) - custom_ops.append(nc) - bpy.utils.register_class(nc) + op_name = 'view3d.set_layer_view_'+str(num) + + nc = type( 'DynOpSetLayer_'+str(num), + (bpy.types.Operator, ), + {'bl_idname': op_name, + 'bl_label': "Set Layer View", + 'bl_description': "Visualize this Layer, Shift-Click to select multiple layers\nName: "+layer, + 'layer_num': bpy.props.IntProperty(name="layer_num"), + 'invoke': set_layer_func + }) + custom_ops.append(nc) + bpy.utils.register_class(nc) class SetObjectLayer(bpy.types.Operator): - '''Move objects to this Layer, Shift-Click to select multiple layers''' - bl_idname = "view3d.set_object_layer" - bl_label = "Move Object To Layers Operator" - - layer_num = bpy.props.IntProperty(name="layer_num") - - def invoke(self, context, event): - selected_objects = [object for object in context.scene.objects if object.select == True] - - if event.shift: - # toggle the objects on/off of the layer - for object in selected_objects: - if object.layers[self.layer_num] == context.scene.objects.active.layers[self.layer_num]: - enabled = not context.scene.objects.active.layers[self.layer_num] - else: - enabled = True - break - - for object in selected_objects: - layers = object.layers - layers[self.layer_num] = enabled - object.layers = layers - bpy.types.Scene.layer_changed = True - else: - # create a boolian list of which layers on and off - layers = [False]*20 - layers[self.layer_num] = True - - # move the objects to the layer - for object in selected_objects: - object.layers = layers - - bpy.types.Scene.layer_changed = True - - return {'FINISHED'} - + '''Move objects to this Layer, Shift-Click to select multiple layers''' + bl_idname = "view3d.set_object_layer" + bl_label = "Move Object To Layers Operator" + + layer_num = bpy.props.IntProperty(name="layer_num") + + def invoke(self, context, event): + selected_objects = [object for object in context.scene.objects if object.select == True] + + if event.shift: + # toggle the objects on/off of the layer + for object in selected_objects: + if object.layers[self.layer_num] == context.scene.objects.active.layers[self.layer_num]: + enabled = not context.scene.objects.active.layers[self.layer_num] + else: + enabled = True + break + + for object in selected_objects: + layers = object.layers + layers[self.layer_num] = enabled + object.layers = layers + bpy.types.Scene.layer_changed = True + else: + # create a boolian list of which layers on and off + layers = [False]*20 + layers[self.layer_num] = True + + # move the objects to the layer + for object in selected_objects: + object.layers = layers + + bpy.types.Scene.layer_changed = True + + return {'FINISHED'} + class LayersWindow(bpy.types.Operator): - bl_label = "Layers" - bl_idname = "view3d.layers_window" - - current_space = None - - def check(self, context): - if bpy.types.Scene.layer_changed: - bpy.types.Scene.layer_changed = False - return True - else: - return False - - def draw(self, context): - if context.space_data: - self.current_space = context.space_data - - ui = Menu(self) - - column_flow = ui.add_item("column_flow", columns=2, align=True) - - layernames = get_layers(context) - - # add the menu items - for num in range(20): - op_name = 'view3d.set_layer_view_'+str(num) - - has_active = (context.object and context.object.layers[num]) - is_layer_used = self.current_space.layers_used[num] - icon = ('LAYER_ACTIVE' if has_active else 'LAYER_USED') if is_layer_used else 'RADIOBUT_OFF' - - prop = ui.add_item(parent=column_flow).operator("view3d.set_object_layer", "", icon=icon) - prop.layer_num = num - - if num == context.scene.active_layer: - prop = ui.current_item.operator(op_name, layernames[num], icon='FILE_TICK') - - elif context.scene.layers[num]: - prop = ui.current_item.operator(op_name, layernames[num], icon='RESTRICT_VIEW_OFF') - - else: - prop = ui.current_item.operator(op_name, layernames[num], icon='BLANK1') - - ui.current_item.operator_context = 'INVOKE_DEFAULT' - prop.layer_num = num - - ui.current_item.separator() - - if num in [4, 14]: - ui.add_item(parent=column_flow).separator() - ui.add_item(parent=column_flow).separator() - - def invoke(self, context, event): - wm = context.window_manager - - layernames = get_layers(context) - - for op in custom_ops: - bpy.utils.unregister_class(op) - - custom_ops.clear() - - - for num, layer in enumerate(layernames): - add_set_layer_op(num, layer) - - return wm.invoke_props_dialog(self) - - def execute(self, context): - return {'FINISHED'} - + bl_label = "Layers" + bl_idname = "view3d.layers_window" + + name = StringProperty(name="Name") + + current_space = None + + def check(self, context): + if bpy.types.Scene.layer_changed: + bpy.types.Scene.layer_changed = False + return True + else: + return False + + def draw(self, context): + if context.space_data: + self.current_space = context.space_data + + ui = Menu(self) + + column_flow = ui.add_item("column_flow", columns=2, align=True) + + layernames = get_layers(context) + + # add the menu items + for num in range(20): + op_name = 'view3d.set_layer_view_'+str(num) + + has_active = (context.object and context.object.layers[num]) + is_layer_used = self.current_space.layers_used[num] + icon = ('LAYER_ACTIVE' if has_active else 'LAYER_USED') if is_layer_used else 'RADIOBUT_OFF' + + prop = ui.add_item(parent=column_flow).operator("view3d.set_object_layer", "", icon=icon) + prop.layer_num = num + + if num == context.scene.active_layer: + prop = ui.current_item.operator(op_name, layernames[num], icon='FILE_TICK') + + elif context.scene.layers[num]: + prop = ui.current_item.operator(op_name, layernames[num], icon='RESTRICT_VIEW_OFF') + + else: + prop = ui.current_item.operator(op_name, layernames[num], icon='BLANK1') + + ui.current_item.operator_context = 'INVOKE_DEFAULT' + prop.layer_num = num + + ui.current_item.separator() + + if num in [4, 14]: + ui.add_item(parent=column_flow).separator() + ui.add_item(parent=column_flow).separator() + + def invoke(self, context, event): + wm = context.window_manager + + layernames = get_layers(context) + + for op in custom_ops: + bpy.utils.unregister_class(op) + + custom_ops.clear() + + + for num, layer in enumerate(layernames): + add_set_layer_op(num, layer) + + return wm.invoke_props_dialog(self) + + def execute(self, context): + return {'FINISHED'} + ### ------------ New hotkeys and registration ------------ ### addon_keymaps = [] def register(): - - set_prop("BoolProperty", "bpy.types.Scene.layer_changed", name="layer_changed") - # create the global menu hotkey - wm = bpy.context.window_manager - km = wm.keyconfigs.addon.keymaps.new(name='Object Mode') - kmi = km.keymap_items.new('view3d.layers_window', 'M', 'PRESS') - addon_keymaps.append((km, kmi)) + set_prop("BoolProperty", "bpy.types.Scene.layer_changed", name="layer_changed") + + # create the global menu hotkey + wm = bpy.context.window_manager + km = wm.keyconfigs.addon.keymaps.new(name='Object Mode') + kmi = km.keymap_items.new('view3d.layers_window', 'M', 'PRESS') + kmi.properties.name = "Layers" + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() - - for op in custom_ops: - bpy.utils.unregister_class(op) + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() + + for op in custom_ops: + bpy.utils.unregister_class(op) diff --git a/manipulator_menu.py b/manipulator_menu.py index aaa81a6..3e88f7d 100644 --- a/manipulator_menu.py +++ b/manipulator_menu.py @@ -1,101 +1,105 @@ from .Utils.core import * +from bpy.props import StringProperty class ManipulatorMenuOperator(bpy.types.Operator): - bl_label = "Transform Menu Operator" - bl_idname = "view3d.manipulator_operator" - - @classmethod - def poll(self, context): - if get_mode() in [object_mode, edit, particle_edit, pose]: - return True - else: - return False - - def modal(self, context, event): - current_time = time.time() - - # if key has been held for more than 0.3 seconds call the menu - if event.value == 'RELEASE' and current_time > self.start_time + 0.3: - if bpy.context.space_data.show_manipulator == True: - TransformOrientationMenu.hotkey = False - bpy.ops.wm.call_menu(name=ManipulatorMenu.bl_idname) - else: - TransformOrientationMenu.hotkey = True - bpy.ops.wm.call_menu(name=TransformOrientationMenu.bl_idname) - - return {'FINISHED'} - - # else toggle manipulator mode on/off - elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: - if context.space_data.show_manipulator: - context.space_data.show_manipulator = False - - else: - context.space_data.show_manipulator = True - - return {'FINISHED'} - - return {'RUNNING_MODAL'} - - def execute(self, context): - self.start_time = time.time() - context.window_manager.modal_handler_add(self) - - return {'RUNNING_MODAL'} - + bl_label = "Transform Menu Operator" + bl_idname = "view3d.manipulator_operator" + + name = StringProperty(name="Name") + + @classmethod + def poll(self, context): + if get_mode() in [object_mode, edit, particle_edit, pose]: + return True + else: + return False + + def modal(self, context, event): + current_time = time.time() + + # if key has been held for more than 0.3 seconds call the menu + if event.value == 'RELEASE' and current_time > self.start_time + 0.3: + if bpy.context.space_data.show_manipulator == True: + TransformOrientationMenu.hotkey = False + bpy.ops.wm.call_menu(name=ManipulatorMenu.bl_idname) + else: + TransformOrientationMenu.hotkey = True + bpy.ops.wm.call_menu(name=TransformOrientationMenu.bl_idname) + + return {'FINISHED'} + + # else toggle manipulator mode on/off + elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: + if context.space_data.show_manipulator: + context.space_data.show_manipulator = False + + else: + context.space_data.show_manipulator = True + + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def execute(self, context): + self.start_time = time.time() + context.window_manager.modal_handler_add(self) + + return {'RUNNING_MODAL'} + class ManipulatorMenu(bpy.types.Menu): - bl_label = "Manipulator" - bl_idname = "VIEW3D_MT_manipulator_menu" - - def draw(self, context): - menu = Menu(self) - - menuprop(menu.add_item(), "Translate", {'TRANSLATE'}, - "space_data.transform_manipulators", - icon="MAN_TRANS", disable=True) - - menuprop(menu.add_item(), "Rotate", {'ROTATE'}, - "space_data.transform_manipulators", - icon="MAN_ROT", disable=True) - - menuprop(menu.add_item(), "Scale", {'SCALE'}, - "space_data.transform_manipulators", - icon="MAN_SCALE", disable=True) - - menu.add_item().menu(TransformOrientationMenu.bl_idname) + bl_label = "Manipulator" + bl_idname = "VIEW3D_MT_manipulator_menu" + + def draw(self, context): + menu = Menu(self) + + menuprop(menu.add_item(), "Translate", {'TRANSLATE'}, + "space_data.transform_manipulators", + icon="MAN_TRANS", disable=True) + + menuprop(menu.add_item(), "Rotate", {'ROTATE'}, + "space_data.transform_manipulators", + icon="MAN_ROT", disable=True) + + menuprop(menu.add_item(), "Scale", {'SCALE'}, + "space_data.transform_manipulators", + icon="MAN_SCALE", disable=True) + + menu.add_item().menu(TransformOrientationMenu.bl_idname) class TransformOrientationMenu(bpy.types.Menu): - bl_label = "Transform Orientation" - bl_idname = "VIEW3D_MT_transf_orient_menu" - - hotkey = True - - def draw(self, context): - menu = Menu(self) - - if not self.hotkey: - menu.add_item().label(text="Transform Orientation") - menu.add_item().separator() - - #menu.add_item().props_enum(bpy.context.space_data, "transform_orientation") - for mode in context.space_data.bl_rna.properties['transform_orientation'].enum_items: - menuprop(menu.add_item(), mode.name, mode.identifier, "space_data.transform_orientation", - icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') + bl_label = "Transform Orientation" + bl_idname = "VIEW3D_MT_transf_orient_menu" + + hotkey = True + + def draw(self, context): + menu = Menu(self) + + if not self.hotkey: + menu.add_item().label(text="Transform Orientation") + menu.add_item().separator() + + #menu.add_item().props_enum(bpy.context.space_data, "transform_orientation") + for mode in context.space_data.bl_rna.properties['transform_orientation'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "space_data.transform_orientation", + icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON') ### ------------ New hotkeys and registration ------------ ### addon_keymaps = [] def register(): - # create the global menu hotkey - wm = bpy.context.window_manager - km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') - kmi = km.keymap_items.new('view3d.manipulator_operator', 'SPACE', 'PRESS', ctrl=True) - addon_keymaps.append((km, kmi)) + # create the global menu hotkey + wm = bpy.context.window_manager + km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') + kmi = km.keymap_items.new('view3d.manipulator_operator', 'SPACE', 'PRESS', ctrl=True) + kmi.properties.name = "Manipulator" + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() diff --git a/mode_menu.py b/mode_menu.py index 85de46b..8d8399d 100644 --- a/mode_menu.py +++ b/mode_menu.py @@ -1,126 +1,131 @@ from .Utils.core import * +from bpy.props import StringProperty class EditorModeOperator(bpy.types.Operator): - bl_label = "Editor Mode Operator" - bl_idname = "view3d.editor_mode_operator" - - last_mode = ['EDIT', 'OBJECT'] - - def init(self): - # populate the list of last modes - if get_mode() not in self.last_mode: - self.last_mode.append(get_mode()) - - # keep the list to 2 items - if len(self.last_mode) > 2: - del self.last_mode[1] - - def modal(self, context, event): - current_time = time.time() - - # if key has been held for more than 0.3 seconds call the menu - if event.value == 'RELEASE' and current_time > self.start_time + 0.3: - bpy.ops.wm.call_menu(name=EditorModeMenu.bl_idname) - - return {'FINISHED'} - - # else toggle between edit mode and your last used mode - elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: - if get_mode() != self.last_mode[0]: - bpy.ops.object.mode_set(mode=self.last_mode[0]) - - else: - bpy.ops.object.mode_set(mode=self.last_mode[1]) - - return {'FINISHED'} - - return {'RUNNING_MODAL'} - - def execute(self, context): - if not context.object: - return {'FINISHED'} - - if context.object.type in ["EMPTY", "SPEAKER", "CAMERA", "LAMP"]: - if bpy.context.gpencil_data: - self.last_mode = ['GPENCIL_EDIT', 'OBJECT'] - else: - return {'FINISHED'} - - self.init() - self.start_time = time.time() - context.window_manager.modal_handler_add(self) - - return {'RUNNING_MODAL'} + bl_label = "Editor Mode Operator" + bl_idname = "view3d.editor_mode_operator" + + name = StringProperty(name="Name") + + last_mode = ['EDIT', 'OBJECT'] + + def init(self): + # populate the list of last modes + if get_mode() not in self.last_mode: + self.last_mode.append(get_mode()) + + # keep the list to 2 items + if len(self.last_mode) > 2: + del self.last_mode[1] + + def modal(self, context, event): + current_time = time.time() + + # if key has been held for more than 0.3 seconds call the menu + if event.value == 'RELEASE' and current_time > self.start_time + 0.3: + bpy.ops.wm.call_menu(name=EditorModeMenu.bl_idname) + + return {'FINISHED'} + + # else toggle between edit mode and your last used mode + elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: + if get_mode() != self.last_mode[0]: + bpy.ops.object.mode_set(mode=self.last_mode[0]) + + else: + bpy.ops.object.mode_set(mode=self.last_mode[1]) + + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def execute(self, context): + if not context.object: + return {'FINISHED'} + + if context.object.type in ["EMPTY", "SPEAKER", "CAMERA", "LAMP"]: + if bpy.context.gpencil_data: + self.last_mode = ['GPENCIL_EDIT', 'OBJECT'] + else: + return {'FINISHED'} + + self.init() + self.start_time = time.time() + context.window_manager.modal_handler_add(self) + + return {'RUNNING_MODAL'} class EditorModeMenu(bpy.types.Menu): - bl_label = "Editor Menu" - bl_idname = "VIEW3D_MT_mode_menu" - - def init(self): - ob_type = bpy.context.object.type - gpd = bpy.context.gpencil_data - self.mode = get_mode() - - if ob_type == 'MESH': - modes = [["Object", object_mode, "OBJECT_DATAMODE"], - ["Edit", edit, "EDITMODE_HLT"], - ["Sculpt", sculpt, "SCULPTMODE_HLT"], - ["Vertex Paint", vertex_paint, "VPAINT_HLT"], - ["Weight Paint", weight_paint, "WPAINT_HLT"], - ["Texture Paint", texture_paint, "TPAINT_HLT"]] - - if len(bpy.context.object.particle_systems.items()) > 0: - modes.append(["Particle Edit", particle_edit, "PARTICLEMODE"]) - - elif ob_type == 'ARMATURE': - modes = [["Object", object_mode, "OBJECT_DATAMODE"], - ["Edit", edit, "EDITMODE_HLT"], - ["Pose", pose, "POSE_HLT"]] - - else: - modes = [["Object", object_mode, "OBJECT_DATAMODE"], - ["Edit", edit, "EDITMODE_HLT"]] - - # remove edit mode if object does not have it - if ob_type in ["EMPTY", "SPEAKER", "CAMERA", "LAMP"]: del modes[1] - - if gpd: modes.append(["Edit Strokes", gpencil_edit, "GREASEPENCIL"]) - - return modes - - def draw(self, context): - modes = self.init() - menu = Menu(self) - - # add the menu items - for mode in modes: - prop = menu.add_item(name=mode[0]).operator("object.mode_set", mode[0], icon=mode[2]) - prop.mode = mode[1] - - # disable the rows that need it - if self.mode == mode[1]: - menu.current_item.enabled = False - + bl_label = "Editor Menu" + bl_idname = "VIEW3D_MT_mode_menu" + + def init(self): + ob_type = bpy.context.object.type + gpd = bpy.context.gpencil_data + self.mode = get_mode() + + if ob_type == 'MESH': + modes = [["Object", object_mode, "OBJECT_DATAMODE"], + ["Edit", edit, "EDITMODE_HLT"], + ["Sculpt", sculpt, "SCULPTMODE_HLT"], + ["Vertex Paint", vertex_paint, "VPAINT_HLT"], + ["Weight Paint", weight_paint, "WPAINT_HLT"], + ["Texture Paint", texture_paint, "TPAINT_HLT"]] + + if len(bpy.context.object.particle_systems.items()) > 0: + modes.append(["Particle Edit", particle_edit, "PARTICLEMODE"]) + + elif ob_type == 'ARMATURE': + modes = [["Object", object_mode, "OBJECT_DATAMODE"], + ["Edit", edit, "EDITMODE_HLT"], + ["Pose", pose, "POSE_HLT"]] + + else: + modes = [["Object", object_mode, "OBJECT_DATAMODE"], + ["Edit", edit, "EDITMODE_HLT"]] + + # remove edit mode if object does not have it + if ob_type in ["EMPTY", "SPEAKER", "CAMERA", "LAMP"]: del modes[1] + + if gpd: modes.append(["Edit Strokes", gpencil_edit, "GREASEPENCIL"]) + + return modes + + def draw(self, context): + modes = self.init() + menu = Menu(self) + + # add the menu items + for mode in modes: + prop = menu.add_item(name=mode[0]).operator("object.mode_set", mode[0], icon=mode[2]) + prop.mode = mode[1] + + # disable the rows that need it + if self.mode == mode[1]: + menu.current_item.enabled = False + ### ------------ New hotkeys and registration ------------ ### addon_keymaps = [] def register(): - # create the global hotkey - wm = bpy.context.window_manager - km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') - kmi = km.keymap_items.new('view3d.editor_mode_operator', 'TAB', 'PRESS') - addon_keymaps.append((km, kmi)) - - km = wm.keyconfigs.addon.keymaps.new(name='Grease Pencil Stroke Edit Mode') - kmi = km.keymap_items.new('view3d.editor_mode_operator', 'TAB', 'PRESS') - addon_keymaps.append((km, kmi)) + # create the global hotkey + wm = bpy.context.window_manager + km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') + kmi = km.keymap_items.new('view3d.editor_mode_operator', 'TAB', 'PRESS') + kmi.properties.name = "Mode" + addon_keymaps.append((km, kmi)) + + km = wm.keyconfigs.addon.keymaps.new(name='Grease Pencil Stroke Edit Mode') + kmi = km.keymap_items.new('view3d.editor_mode_operator', 'TAB', 'PRESS') + kmi.properties.name = "Mode" + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() diff --git a/preferences.py b/preferences.py new file mode 100644 index 0000000..c4d54bd --- /dev/null +++ b/preferences.py @@ -0,0 +1,76 @@ +import bpy +import os +import rna_keymap_ui + +#--------------------------------------- +# Preferences panel +#--------------------------------------- + +def get_hotkey_entry_item(km, kmi_name, properties): #kmi_value, properties): + try: + for i, km_item in enumerate(km.keymap_items): + if km.keymap_items.keys()[i] == kmi_name: + if km.keymap_items[i].properties.name == properties: + return km_item + return None + except: + pass + + +def get_addon_name(): + return os.path.basename(os.path.dirname(os.path.realpath(__file__))) + +addon_files = [ + ('Sculpt',"wm.call_menu","VIEW3D_MT_brush_options", "Brush Options"), + ('Sculpt',"wm.call_menu","VIEW3D_MT_brush_curve_menu", "Curve Menu"), + # ("wm.call_menu","VIEW3D_MT_custom_menu", "Custom Menu"), + ('Mesh',"wm.call_menu","MESH_MT_context_delete_menu", "Delete"), + ('Sculpt',"wm.call_menu","VIEW3D_MT_dyntopo","Dynotopo Menu"), + ('Mesh',"view3d.extrude_menu_operator","Extrude", "Extrude"), + ('Object Mode', "view3d.layers_window","Layers", "Layers"), + ('Object Non-modal', "view3d.manipulator_operator","Manipulator", "Manipulator"), + ('Object Non-modal',"view3d.editor_mode_operator","Mode", "Interactive Mode"), + ('Object Non-modal',"wm.call_menu","VIEW3D_MT_pivot_point", "Pivot Menu"), + ('Mesh',"view3d.proportional_menu_operator","Falloff", "Falloff Menu"), + ('Mesh',"wm.call_menu","VIEW3D_MT_selection_menu", "Selection Menu"), + ('Object Non-modal',"view3d.shading_menu_operator","Shading_Menu", "Shading Menu"), + ('Object Non-modal',"view3d.snap_menu_operator","Snap", "Snapping Menu"), + ('Sculpt',"wm.call_menu","VIEW3D_MT_stroke_options", "Stroke Options"), + ('Sculpt',"wm.call_menu","VIEW3D_MT_master_symmetry_menu", "Symmetry Menu"), + ('Sculpt',"wm.call_menu","VIEW3D_MT_texture_menu", "Texture Menu"), + ('Object Non-modal',"wm.call_menu","VIEW3D_MT_view_menu", "View Menu") + ] +# + +class AdvanceUIPreferences(bpy.types.AddonPreferences): + bl_idname = get_addon_name() + + def draw(self, context): + layout = self.layout + scene = context.scene + + column = layout.column() + column.separator() + + col = layout.column(align = True) + row = col.row() + box=layout.box() + split = box.split() + col = split.column() + col.label('Hotkeys:') + col.label('Do NOT remove hotkeys, disable them instead!') + col.separator() + + wm = bpy.context.window_manager + kc = wm.keyconfigs.user + for addon in addon_files: + km = kc.keymaps[addon[0]] + kmi = get_hotkey_entry_item(km, addon[1], addon[2]) + if kmi: + row = col.row() + row = col.split(percentage=0.25) + row.label(addon[3]) + row.context_pointer_set("keymap", km) + rna_keymap_ui.draw_kmi([], kc, km, kmi, row, 0) + else: + row.label("restore hotkeys from interface tab") diff --git a/proportional_menu.py b/proportional_menu.py index 48ca335..bfe2178 100644 --- a/proportional_menu.py +++ b/proportional_menu.py @@ -1,160 +1,163 @@ from .Utils.core import * - +from bpy.props import StringProperty # adds a proportional mode menu class ProportionalModeOperator(bpy.types.Operator): - bl_label = "Proportional Mode Operator" - bl_idname = "view3d.proportional_menu_operator" - - last_mode = ['DISABLED', 'ENABLED'] - - def init(self, context): - if context.space_data.type == 'DOPESHEET_EDITOR': - if context.tool_settings.use_proportional_action == False: - context.tool_settings.use_proportional_action = True - - else: - context.tool_settings.use_proportional_action = False - - return {'FINISHED'} - - if context.space_data.type == 'GRAPH_EDITOR': - if context.tool_settings.use_proportional_fcurve == False: - context.tool_settings.use_proportional_fcurve = True - - else: - context.tool_settings.use_proportional_fcurve = False - - return {'FINISHED'} - - if context.space_data.type == 'IMAGE_EDITOR': - if context.space_data.show_maskedit: - if context.tool_settings.use_proportional_edit_mask == False: - context.tool_settings.use_proportional_edit_mask = True - - else: - context.tool_settings.use_proportional_edit_mask = False - - return {'FINISHED'} - - if get_mode() == 'OBJECT': - if context.tool_settings.use_proportional_edit_objects == False: - context.tool_settings.use_proportional_edit_objects = True - - else: - context.tool_settings.use_proportional_edit_objects = False - - return {'FINISHED'} - - # populate the list of last modes - if context.tool_settings.proportional_edit not in self.last_mode: - self.last_mode.append(context.tool_settings.proportional_edit) - - # keep the list to 2 items - if len(self.last_mode) > 2: - del self.last_mode[1] - - def modal(self, context, event): - current_time = time.time() - - # if key has been held for more than 0.3 seconds call the menu - if event.value == 'RELEASE' and current_time > self.start_time + 0.3: - bpy.ops.wm.call_menu(name=ProportionalEditingMenu.bl_idname) - - return {'FINISHED'} - - # else toggle between off and your last used mode - elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: - if context.tool_settings.proportional_edit != self.last_mode[0]: - context.tool_settings.proportional_edit = self.last_mode[0] - - else: - context.tool_settings.proportional_edit = self.last_mode[1] - - return {'FINISHED'} - - return {'RUNNING_MODAL'} - - def execute(self, context): - self.init(context) - self.start_time = time.time() - context.window_manager.modal_handler_add(self) - - return {'RUNNING_MODAL'} + bl_label = "Proportional Mode Operator" + bl_idname = "view3d.proportional_menu_operator" + + name = StringProperty(name="Name") + + last_mode = ['DISABLED', 'ENABLED'] + + def init(self, context): + if context.space_data.type == 'DOPESHEET_EDITOR': + if context.tool_settings.use_proportional_action == False: + context.tool_settings.use_proportional_action = True + + else: + context.tool_settings.use_proportional_action = False + + return {'FINISHED'} + + if context.space_data.type == 'GRAPH_EDITOR': + if context.tool_settings.use_proportional_fcurve == False: + context.tool_settings.use_proportional_fcurve = True + + else: + context.tool_settings.use_proportional_fcurve = False + + return {'FINISHED'} + + if context.space_data.type == 'IMAGE_EDITOR': + if context.space_data.show_maskedit: + if context.tool_settings.use_proportional_edit_mask == False: + context.tool_settings.use_proportional_edit_mask = True + + else: + context.tool_settings.use_proportional_edit_mask = False + + return {'FINISHED'} + + if get_mode() == 'OBJECT': + if context.tool_settings.use_proportional_edit_objects == False: + context.tool_settings.use_proportional_edit_objects = True + + else: + context.tool_settings.use_proportional_edit_objects = False + + return {'FINISHED'} + + # populate the list of last modes + if context.tool_settings.proportional_edit not in self.last_mode: + self.last_mode.append(context.tool_settings.proportional_edit) + + # keep the list to 2 items + if len(self.last_mode) > 2: + del self.last_mode[1] + + def modal(self, context, event): + current_time = time.time() + + # if key has been held for more than 0.3 seconds call the menu + if event.value == 'RELEASE' and current_time > self.start_time + 0.3: + bpy.ops.wm.call_menu(name=ProportionalEditingMenu.bl_idname) + + return {'FINISHED'} + + # else toggle between off and your last used mode + elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: + if context.tool_settings.proportional_edit != self.last_mode[0]: + context.tool_settings.proportional_edit = self.last_mode[0] + + else: + context.tool_settings.proportional_edit = self.last_mode[1] + + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def execute(self, context): + self.init(context) + self.start_time = time.time() + context.window_manager.modal_handler_add(self) + + return {'RUNNING_MODAL'} class ProportionalEditingMenu(bpy.types.Menu): - bl_label = "Proportional" - bl_idname = "VIEW3D_MT_proportional_menu" + bl_label = "Proportional" + bl_idname = "VIEW3D_MT_proportional_menu" - @classmethod - def poll(self, context): - if get_mode() in [edit, particle_edit, gpencil_edit]: - return True - else: - return False + @classmethod + def poll(self, context): + if get_mode() in [edit, particle_edit, gpencil_edit]: + return True + else: + return False - def draw(self, context): - menu = Menu(self) + def draw(self, context): + menu = Menu(self) - # add the items to the menu - for mode in context.tool_settings.bl_rna.properties['proportional_edit'].enum_items: - menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.proportional_edit", - icon=mode.icon, disable=True) + # add the items to the menu + for mode in context.tool_settings.bl_rna.properties['proportional_edit'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.proportional_edit", + icon=mode.icon, disable=True) class FalloffMenu(bpy.types.Menu): - bl_label = "Falloff Menu" - bl_idname = "VIEW3D_MT_falloff_menu" - - @classmethod - def poll(self, context): - if get_mode() in [object_mode, edit, particle_edit, gpencil_edit]: - return True - else: - return False - - def draw(self, context): - menu = Menu(self) - - # add the items to the menu - for mode in context.tool_settings.bl_rna.properties['proportional_edit_falloff'].enum_items: - menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.proportional_edit_falloff", - icon=mode.icon, disable=True) - - + bl_label = "Falloff Menu" + bl_idname = "VIEW3D_MT_falloff_menu" + + @classmethod + def poll(self, context): + if get_mode() in [object_mode, edit, particle_edit, gpencil_edit]: + return True + else: + return False + + def draw(self, context): + menu = Menu(self) + + # add the items to the menu + for mode in context.tool_settings.bl_rna.properties['proportional_edit_falloff'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.proportional_edit_falloff", + icon=mode.icon, disable=True) + + ### ------------ New hotkeys and registration ------------ ### addon_keymaps = [] def register(): - # create the global menu hotkeys - wm = bpy.context.window_manager - modes = {'Object Mode':'EMPTY', - 'Mesh':'EMPTY', - 'Curve':'EMPTY', - 'Armature':'EMPTY', - 'Metaball':'EMPTY', - 'Lattice':'EMPTY', - 'Particle':'EMPTY', - 'Object Non-modal':'EMPTY', - 'Graph Editor':'GRAPH_EDITOR', - 'Dopesheet':'DOPESHEET_EDITOR', - 'UV Editor':'EMPTY', - 'Grease Pencil Stroke Edit Mode':'EMPTY', - 'Mask Editing':'EMPTY'} - - for mode, space in modes.items(): - km = wm.keyconfigs.addon.keymaps.new(name=mode, space_type=space) - kmi = km.keymap_items.new('view3d.proportional_menu_operator', 'O', 'PRESS') - addon_keymaps.append((km, kmi)) - - kmi = km.keymap_items.new('wm.call_menu', 'O', 'PRESS', shift=True) - kmi.properties.name = 'VIEW3D_MT_falloff_menu' - addon_keymaps.append((km, kmi)) + # create the global menu hotkeys + wm = bpy.context.window_manager + modes = {'Object Mode':'EMPTY', + 'Mesh':'EMPTY', + 'Curve':'EMPTY', + 'Armature':'EMPTY', + 'Metaball':'EMPTY', + 'Lattice':'EMPTY', + 'Particle':'EMPTY', + 'Object Non-modal':'EMPTY', + 'Graph Editor':'GRAPH_EDITOR', + 'Dopesheet':'DOPESHEET_EDITOR', + 'UV Editor':'EMPTY', + 'Grease Pencil Stroke Edit Mode':'EMPTY', + 'Mask Editing':'EMPTY'} + + for mode, space in modes.items(): + km = wm.keyconfigs.addon.keymaps.new(name=mode, space_type=space) + kmi = km.keymap_items.new('view3d.proportional_menu_operator', 'O', 'PRESS') + kmi.properties.name = 'Falloff' + addon_keymaps.append((km, kmi)) + + kmi = km.keymap_items.new('wm.call_menu', 'O', 'PRESS', shift=True) + kmi.properties.name = 'VIEW3D_MT_falloff_menu' + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() diff --git a/shade_menu.py b/shade_menu.py index 1a4a637..ff88c25 100644 --- a/shade_menu.py +++ b/shade_menu.py @@ -1,150 +1,154 @@ from .Utils.core import * +from bpy.props import StringProperty # adds a shading mode menu class ShadeModeOperator(bpy.types.Operator): - bl_label = "Shading Operator" - bl_idname = "view3d.shading_menu_operator" - - last_mode = ['WIREFRAME'] - - def init(self, context): - # populate the list of last modes - if context.space_data.viewport_shade not in self.last_mode: - self.last_mode.append(context.space_data.viewport_shade) - - # keep the list to 2 items - if len(self.last_mode) > 2: - del self.last_mode[1] - - def modal(self, context, event): - current_time = time.time() - - # if key has been held for more than 0.3 seconds call the menu - if event.value == 'RELEASE' and current_time > self.start_time + 0.3: - bpy.ops.wm.call_menu(name=ShadeModeMenu.bl_idname) - - return {'FINISHED'} - - # else toggle between wireframe and your last used mode - elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: - if context.space_data.viewport_shade != self.last_mode[0]: - context.space_data.viewport_shade = self.last_mode[0] - - else: - context.space_data.viewport_shade = self.last_mode[1] - - return {'FINISHED'} - - return {'RUNNING_MODAL'} - - def execute(self, context): - self.init(context) - self.start_time = time.time() - context.window_manager.modal_handler_add(self) - - return {'RUNNING_MODAL'} + bl_label = "Shading Operator" + bl_idname = "view3d.shading_menu_operator" + + name = StringProperty(name="Name") + + last_mode = ['WIREFRAME'] + + def init(self, context): + # populate the list of last modes + if context.space_data.viewport_shade not in self.last_mode: + self.last_mode.append(context.space_data.viewport_shade) + + # keep the list to 2 items + if len(self.last_mode) > 2: + del self.last_mode[1] + + def modal(self, context, event): + current_time = time.time() + + # if key has been held for more than 0.3 seconds call the menu + if event.value == 'RELEASE' and current_time > self.start_time + 0.3: + bpy.ops.wm.call_menu(name=ShadeModeMenu.bl_idname) + + return {'FINISHED'} + + # else toggle between wireframe and your last used mode + elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: + if context.space_data.viewport_shade != self.last_mode[0]: + context.space_data.viewport_shade = self.last_mode[0] + + else: + context.space_data.viewport_shade = self.last_mode[1] + + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def execute(self, context): + self.init(context) + self.start_time = time.time() + context.window_manager.modal_handler_add(self) + + return {'RUNNING_MODAL'} class ShadeModeMenu(bpy.types.Menu): - bl_label = "Viewport Shading" - bl_idname = "VIEW3D_MT_shade_menu" - - def init(self): - renderer = bpy.context.scene.render.engine - - if renderer == 'BLENDER_RENDER': - modes = [["Solid", 'SOLID', "SOLID"], - ["Wireframe", 'WIREFRAME', "WIRE"], - ["Textured", 'TEXTURED', "TEXTURE_SHADED"], - ["Material", 'MATERIAL', "MATERIAL_DATA"], - ["Rendered", 'RENDERED', "SMOOTH"], - ["Bounding Box", 'BOUNDBOX', "BBOX"]] - - elif renderer == 'CYCLES': - modes = [["Solid", 'SOLID', "SOLID"], - ["Wireframe", 'WIREFRAME', "WIRE"], - ["Textured", 'TEXTURED', "TEXTURE_SHADED"], - ["Material", 'MATERIAL', "MATERIAL_DATA"], - ["Rendered", 'RENDERED', "SMOOTH"], - ["Bounding Box", 'BOUNDBOX', "BBOX"]] - - else: - modes = [["Solid", 'SOLID', "SOLID"], - ["Wireframe", 'WIREFRAME', "WIRE"], - ["Textured", 'TEXTURED', "TEXTURE_SHADED"], - ["Material", 'MATERIAL', "MATERIAL_DATA"], - ["Bounding Box", 'BOUNDBOX', "BBOX"]] - - return modes - - def draw(self, context): - modes = self.init() - menu = Menu(self) - - # add the items to the menu - for mode in modes: - menuprop(menu.add_item(), mode[0], mode[1], "space_data.viewport_shade", - icon=mode[2], disable=True) - - # add a shading options menu if object can be shaded smooth/flat - if bpy.context.object and bpy.context.object.type in ['MESH', 'CURVE', 'SURFACE']: - menu.add_item().separator() - if context.object.use_dynamic_topology_sculpting: - menu.add_item().prop(context.tool_settings.sculpt, "use_smooth_shading", toggle=True) - else: - menu.add_item().menu(MeshShadeMenu.bl_idname) - - if get_mode() != 'EDIT': - menu.add_item().menu(DisplayOptionsMenu.bl_idname) + bl_label = "Viewport Shading" + bl_idname = "VIEW3D_MT_shade_menu" + + def init(self): + renderer = bpy.context.scene.render.engine + + if renderer == 'BLENDER_RENDER': + modes = [["Solid", 'SOLID', "SOLID"], + ["Wireframe", 'WIREFRAME', "WIRE"], + ["Textured", 'TEXTURED', "TEXTURE_SHADED"], + ["Material", 'MATERIAL', "MATERIAL_DATA"], + ["Rendered", 'RENDERED', "SMOOTH"], + ["Bounding Box", 'BOUNDBOX', "BBOX"]] + + elif renderer == 'CYCLES': + modes = [["Solid", 'SOLID', "SOLID"], + ["Wireframe", 'WIREFRAME', "WIRE"], + ["Textured", 'TEXTURED', "TEXTURE_SHADED"], + ["Material", 'MATERIAL', "MATERIAL_DATA"], + ["Rendered", 'RENDERED', "SMOOTH"], + ["Bounding Box", 'BOUNDBOX', "BBOX"]] + + else: + modes = [["Solid", 'SOLID', "SOLID"], + ["Wireframe", 'WIREFRAME', "WIRE"], + ["Textured", 'TEXTURED', "TEXTURE_SHADED"], + ["Material", 'MATERIAL', "MATERIAL_DATA"], + ["Bounding Box", 'BOUNDBOX', "BBOX"]] + + return modes + + def draw(self, context): + modes = self.init() + menu = Menu(self) + + # add the items to the menu + for mode in modes: + menuprop(menu.add_item(), mode[0], mode[1], "space_data.viewport_shade", + icon=mode[2], disable=True) + + # add a shading options menu if object can be shaded smooth/flat + if bpy.context.object and bpy.context.object.type in ['MESH', 'CURVE', 'SURFACE']: + menu.add_item().separator() + if context.object.use_dynamic_topology_sculpting: + menu.add_item().prop(context.tool_settings.sculpt, "use_smooth_shading", toggle=True) + else: + menu.add_item().menu(MeshShadeMenu.bl_idname) + + if get_mode() != 'EDIT': + menu.add_item().menu(DisplayOptionsMenu.bl_idname) class MeshShadeMenu(bpy.types.Menu): - bl_label = "Object Shading" - bl_idname = "VIEW3D_MT_mesh_shade" - - def draw(self, context): - menu = Menu(self) - - menu.add_item().label(text="Object Shading") - menu.add_item().separator() - - if bpy.context.mode == 'EDIT_MESH': - menu.add_item().operator("mesh.faces_shade_flat", "Shade Flat", icon="MESH_ICOSPHERE") - menu.add_item().operator("mesh.faces_shade_smooth", "Shade Smooth", icon="MESH_UVSPHERE") - - else: - menu.add_item().operator("object.shade_flat", "Shade Flat", icon="MESH_ICOSPHERE") - menu.add_item().operator("object.shade_smooth", "Shade Smooth", icon="MESH_UVSPHERE") + bl_label = "Object Shading" + bl_idname = "VIEW3D_MT_mesh_shade" + + def draw(self, context): + menu = Menu(self) + + menu.add_item().label(text="Object Shading") + menu.add_item().separator() + + if bpy.context.mode == 'EDIT_MESH': + menu.add_item().operator("mesh.faces_shade_flat", "Shade Flat", icon="MESH_ICOSPHERE") + menu.add_item().operator("mesh.faces_shade_smooth", "Shade Smooth", icon="MESH_UVSPHERE") + + else: + menu.add_item().operator("object.shade_flat", "Shade Flat", icon="MESH_ICOSPHERE") + menu.add_item().operator("object.shade_smooth", "Shade Smooth", icon="MESH_UVSPHERE") class DisplayOptionsMenu(bpy.types.Menu): - bl_label = "Display Options" - bl_idname = "VIEW3D_MT_display_options" - - def draw(self, context): - menu = Menu(self) - - menu.add_item().label(text="Display Options") - menu.add_item().separator() - - menu.add_item().prop(context.object, 'show_name', toggle=True) - menu.add_item().prop(context.object, 'show_axis', toggle=True) - menu.add_item().prop(context.object, 'show_wire', toggle=True) - menu.add_item().prop(context.object, 'show_x_ray', toggle=True) - menu.add_item().prop(context.object, 'show_all_edges', toggle=True) - + bl_label = "Display Options" + bl_idname = "VIEW3D_MT_display_options" + + def draw(self, context): + menu = Menu(self) + + menu.add_item().label(text="Display Options") + menu.add_item().separator() + + menu.add_item().prop(context.object, 'show_name', toggle=True) + menu.add_item().prop(context.object, 'show_axis', toggle=True) + menu.add_item().prop(context.object, 'show_wire', toggle=True) + menu.add_item().prop(context.object, 'show_x_ray', toggle=True) + menu.add_item().prop(context.object, 'show_all_edges', toggle=True) + ### ------------ New hotkeys and registration ------------ ### addon_keymaps = [] def register(): - # create the global menu hotkey - wm = bpy.context.window_manager - km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') - kmi = km.keymap_items.new('view3d.shading_menu_operator', 'Z', 'PRESS') - addon_keymaps.append((km, kmi)) + # create the global menu hotkey + wm = bpy.context.window_manager + km = wm.keyconfigs.addon.keymaps.new(name='Object Non-modal') + kmi = km.keymap_items.new('view3d.shading_menu_operator', 'Z', 'PRESS') + kmi.properties.name = "Shading_Menu" + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() diff --git a/snap_menu.py b/snap_menu.py index 7d162fd..2e40db2 100644 --- a/snap_menu.py +++ b/snap_menu.py @@ -1,107 +1,110 @@ from .Utils.core import * +from bpy.props import StringProperty # adds a shading mode menu class SnapMenuOperator(bpy.types.Operator): - bl_label = "Snap Menu Operator" - bl_idname = "view3d.snap_menu_operator" - - @classmethod - def poll(self, context): - if get_mode() in [object_mode, edit, particle_edit, gpencil_edit]: - return True - else: - return False - - def modal(self, context, event): - current_time = time.time() - - # if key has been held for more than 0.3 seconds call the menu - if event.value == 'RELEASE' and current_time > self.start_time + 0.3: - bpy.ops.wm.call_menu(name=SnapModeMenu.bl_idname) - - return {'FINISHED'} - - # else toggle snap mode on/off - elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: - if context.tool_settings.use_snap: - context.tool_settings.use_snap = False - - else: - context.tool_settings.use_snap = True - - return {'FINISHED'} - - return {'RUNNING_MODAL'} - - def execute(self, context): - self.start_time = time.time() - context.window_manager.modal_handler_add(self) - - return {'RUNNING_MODAL'} + bl_label = "Snap Menu Operator" + bl_idname = "view3d.snap_menu_operator" + + name = StringProperty(name="Name") + + @classmethod + def poll(self, context): + if get_mode() in [object_mode, edit, particle_edit, gpencil_edit]: + return True + else: + return False + + def modal(self, context, event): + current_time = time.time() + + # if key has been held for more than 0.3 seconds call the menu + if event.value == 'RELEASE' and current_time > self.start_time + 0.3: + bpy.ops.wm.call_menu(name=SnapModeMenu.bl_idname) + + return {'FINISHED'} + + # else toggle snap mode on/off + elif event.value == 'RELEASE' and current_time < self.start_time + 0.3: + if context.tool_settings.use_snap: + context.tool_settings.use_snap = False + + else: + context.tool_settings.use_snap = True + + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def execute(self, context): + self.start_time = time.time() + context.window_manager.modal_handler_add(self) + + return {'RUNNING_MODAL'} class SnapModeMenu(bpy.types.Menu): - bl_label = "Snap Element" - bl_idname = "VIEW3D_MT_snap_menu" - - def draw(self, context): - menu = Menu(self) - snap_element = bpy.context.tool_settings.snap_element - - # menu for node editor - if context.space_data.type == 'NODE_EDITOR': - - # add the menu items - for mode in context.tool_settings.bl_rna.properties['snap_node_element'].enum_items: - menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_node_element", - icon=mode.icon, disable=True) - - if snap_element != "INCREMENT": - menu.add_item().separator() - menu.add_item().menu(SnapTargetMenu.bl_idname) - - # menu for 3d view - if context.space_data.type == 'VIEW_3D': - - # add the menu items - for mode in context.tool_settings.bl_rna.properties['snap_element'].enum_items: - menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_element", - icon=mode.icon, disable=True) - - if snap_element != "INCREMENT": - menu.add_item().separator() - menu.add_item().menu(SnapTargetMenu.bl_idname) - - menu.add_item().separator() - - if snap_element == "INCREMENT": - menu.add_item().prop(bpy.context.tool_settings, "use_snap_grid_absolute", toggle=True) - - if snap_element not in ["INCREMENT", "VOLUME"]: - menu.add_item().prop(bpy.context.tool_settings, "use_snap_align_rotation", toggle=True) - - if snap_element == "FACE": - menu.add_item().prop(bpy.context.tool_settings, "use_snap_project", toggle=True) - - if snap_element == "VOLUME": - menu.add_item().prop(bpy.context.tool_settings, "use_snap_peel_object", toggle=True) + bl_label = "Snap Element" + bl_idname = "VIEW3D_MT_snap_menu" + + def draw(self, context): + menu = Menu(self) + snap_element = bpy.context.tool_settings.snap_element + + # menu for node editor + if context.space_data.type == 'NODE_EDITOR': + + # add the menu items + for mode in context.tool_settings.bl_rna.properties['snap_node_element'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_node_element", + icon=mode.icon, disable=True) + + if snap_element != "INCREMENT": + menu.add_item().separator() + menu.add_item().menu(SnapTargetMenu.bl_idname) + + # menu for 3d view + if context.space_data.type == 'VIEW_3D': + + # add the menu items + for mode in context.tool_settings.bl_rna.properties['snap_element'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_element", + icon=mode.icon, disable=True) + + if snap_element != "INCREMENT": + menu.add_item().separator() + menu.add_item().menu(SnapTargetMenu.bl_idname) + + menu.add_item().separator() + + if snap_element == "INCREMENT": + menu.add_item().prop(bpy.context.tool_settings, "use_snap_grid_absolute", toggle=True) + + if snap_element not in ["INCREMENT", "VOLUME"]: + menu.add_item().prop(bpy.context.tool_settings, "use_snap_align_rotation", toggle=True) + + if snap_element == "FACE": + menu.add_item().prop(bpy.context.tool_settings, "use_snap_project", toggle=True) + + if snap_element == "VOLUME": + menu.add_item().prop(bpy.context.tool_settings, "use_snap_peel_object", toggle=True) class SnapTargetMenu(bpy.types.Menu): - bl_label = "Snap Target" - bl_idname = "VIEW3D_MT_snap_target_menu" + bl_label = "Snap Target" + bl_idname = "VIEW3D_MT_snap_target_menu" + + def draw(self, context): + menu = Menu(self) - def draw(self, context): - menu = Menu(self) - - menu.add_item().label(text="Snap Target") - menu.add_item().separator() + menu.add_item().label(text="Snap Target") + menu.add_item().separator() - # add the menu items - for mode in context.tool_settings.bl_rna.properties['snap_target'].enum_items: - menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_target", disable=True) + # add the menu items + for mode in context.tool_settings.bl_rna.properties['snap_target'].enum_items: + menuprop(menu.add_item(), mode.name, mode.identifier, "tool_settings.snap_target", disable=True) ### ------------ New hotkeys and registration ------------ ### @@ -109,18 +112,19 @@ def draw(self, context): addon_keymaps = [] def register(): - # create the global menu hotkey - wm = bpy.context.window_manager - modes = {'Object Non-modal':'EMPTY', 'Grease Pencil Stroke Edit Mode':'EMPTY', 'Node Editor':'NODE_EDITOR'} - - for mode, space in modes.items(): - km = wm.keyconfigs.addon.keymaps.new(name=mode, space_type=space) - kmi = km.keymap_items.new('view3d.snap_menu_operator', 'TAB', 'PRESS', shift=True) - addon_keymaps.append((km, kmi)) + # create the global menu hotkey + wm = bpy.context.window_manager + modes = {'Object Non-modal':'EMPTY', 'Grease Pencil Stroke Edit Mode':'EMPTY', 'Node Editor':'NODE_EDITOR'} + + for mode, space in modes.items(): + km = wm.keyconfigs.addon.keymaps.new(name=mode, space_type=space) + kmi = km.keymap_items.new('view3d.snap_menu_operator', 'TAB', 'PRESS', shift=True) + kmi.properties.name = 'Snap' + addon_keymaps.append((km, kmi)) def unregister(): - # remove keymaps when add-on is deactivated - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymaps when add-on is deactivated + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear()