diff options
Diffstat (limited to 'space_view3d_brush_menus')
-rw-r--r-- | space_view3d_brush_menus/Utils/__init__.py | 0 | ||||
-rw-r--r-- | space_view3d_brush_menus/__init__.py | 169 | ||||
-rw-r--r-- | space_view3d_brush_menus/brush_menu.py | 630 | ||||
-rw-r--r-- | space_view3d_brush_menus/brushes.py | 134 | ||||
-rw-r--r-- | space_view3d_brush_menus/curve_menu.py | 58 | ||||
-rw-r--r-- | space_view3d_brush_menus/dyntopo_menu.py | 77 | ||||
-rw-r--r-- | space_view3d_brush_menus/stroke_menu.py | 128 | ||||
-rw-r--r-- | space_view3d_brush_menus/symmetry_menu.py | 55 | ||||
-rw-r--r-- | space_view3d_brush_menus/texture_menu.py | 344 | ||||
-rw-r--r-- | space_view3d_brush_menus/utils_core.py (renamed from space_view3d_brush_menus/Utils/core.py) | 153 |
10 files changed, 973 insertions, 775 deletions
diff --git a/space_view3d_brush_menus/Utils/__init__.py b/space_view3d_brush_menus/Utils/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/space_view3d_brush_menus/Utils/__init__.py +++ /dev/null diff --git a/space_view3d_brush_menus/__init__.py b/space_view3d_brush_menus/__init__.py index 6613b82f..a591187c 100644 --- a/space_view3d_brush_menus/__init__.py +++ b/space_view3d_brush_menus/__init__.py @@ -17,122 +17,115 @@ # ##### END GPL LICENSE BLOCK ##### # Modified by Meta-Androcto - """ Copyright 2011 GPL licence applies""" bl_info = { "name": "Sculpt/Paint Brush Menus", "description": "Fast access to brushes & tools in Sculpt and Paint Modes", "author": "Ryan Inch (Imaginer)", - "version": (1, 1, 3), + "version": (1, 1, 4), "blender": (2, 7, 8), "location": "Alt V in Sculpt/Paint 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", + "warning": '', + "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/" + "Scripts/3D_interaction/Advanced_UI_Menus", "category": "3D View"} -import sys -import os -from bl_ui.properties_paint_common import ( - UnifiedPaintPanel, - brush_texture_settings, - brush_texpaint_common, - brush_mask_texture_settings, - ) -from .Utils.core import * -from . import brush_menu -from . import brushes -from . import curve_menu -from . import dyntopo_menu -from . import stroke_menu -from . import symmetry_menu -from . import texture_menu +if "bpy" in locals(): + import importlib + importlib.reload(utils_core) + importlib.reload(brush_menu) + importlib.reload(brushes) + importlib.reload(curve_menu) + importlib.reload(dyntopo_menu) + importlib.reload(stroke_menu) + importlib.reload(symmetry_menu) + importlib.reload(texture_menu) +else: + from . import utils_core + from . import brush_menu + from . import brushes + from . import curve_menu + from . import dyntopo_menu + from . import stroke_menu + from . import symmetry_menu + from . import texture_menu + + +import bpy +from bpy.types import AddonPreferences +from bpy.props import ( + EnumProperty, + IntProperty, + ) -# Use compact brushes menus # -def UseBrushesLists(): - # separate function just for more convience - useLists = bpy.context.user_preferences.addons[__name__].preferences.use_brushes_lists - return bool(useLists) +class VIEW3D_MT_Brushes_Pref(AddonPreferences): + bl_idname = __name__ -class VIEW3D_MT_Brush_Selection1(bpy.types.Menu): - bl_label = "Brush Tool" + use_brushes_menu_type = EnumProperty( + name="Choose Brushes Selection", + description="", + items=[('lists', "Use compact Menus", + "Use more compact menus instead \n" + "of thumbnails for displaying brushes"), + ('template', "Template ID Preview", + "Use Template ID preview menu (thumbnails) for brushes\n" + "(Still part of the menu)"), + ('popup', "Pop up menu", + "Use a separate pop-up window for accessing brushes") + ], + default='lists' + ) + column_set = IntProperty( + name="Number of Columns", + description="Number of columns used for the brushes menu", + default=2, + min=1, + max=10 + ) def draw(self, context): layout = self.layout - settings = UnifiedPaintPanel.paint_settings(context) - - # check if brush exists (for instance, in paint mode before adding a slot) - if hasattr(settings, 'brush'): - brush = settings.brush - else: - brush = None - - if not brush: - return - - if not context.particle_edit_object: - if UseBrushesLists(): - flow = layout.column_flow(columns=3) - - for brsh in bpy.data.brushes: - if (context.sculpt_object and brsh.use_paint_sculpt): - props = flow.operator("wm.context_set_id", text=brsh.name, - icon_value=layout.icon(brsh)) - props.data_path = "tool_settings.sculpt.brush" - props.value = brsh.name - elif (context.image_paint_object and brsh.use_paint_image): - props = flow.operator("wm.context_set_id", text=brsh.name, - icon_value=layout.icon(brsh)) - props.data_path = "tool_settings.image_paint.brush" - props.value = brsh.name - elif (context.vertex_paint_object and brsh.use_paint_vertex): - props = flow.operator("wm.context_set_id", text=brsh.name, - icon_value=layout.icon(brsh)) - props.data_path = "tool_settings.vertex_paint.brush" - props.value = brsh.name - elif (context.weight_paint_object and brsh.use_paint_weight): - props = flow.operator("wm.context_set_id", text=brsh.name, - icon_value=layout.icon(brsh)) - props.data_path = "tool_settings.weight_paint.brush" - props.value = brsh.name - else: - layout.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8) - - -class VIEW3D_MT_Brushes_Pref(bpy.types.AddonPreferences): - bl_idname = __name__ + col = layout.column(align=True) + row = col.row(align=True) + row.prop(self, "use_brushes_menu_type", expand=True) + col.prop(self, "column_set", slider=True) - use_brushes_lists = bpy.props.BoolProperty( - name="Use compact menus for brushes", - default=True, - description=("Use more compact menus instead \n" - "of thumbnails for displaying brushes") - ) - def draw(self, context): - layout = self.layout - row = layout.row() - row.prop(self, "use_brushes_lists") +# New hotkeys and registration + +addon_keymaps = [] + def register(): # register all blender classes bpy.utils.register_module(__name__) - - # register brush menu - brush_menu.register() + + # set the add-on name variable to access the preferences + utils_core.get_addon_name = __name__ + + # register hotkeys + wm = bpy.context.window_manager + modes = ['Sculpt', 'Vertex Paint', 'Weight Paint', 'Image Paint', 'Particle'] + + for mode in modes: + km = wm.keyconfigs.addon.keymaps.new(name=mode) + kmi = km.keymap_items.new('wm.call_menu', 'V', 'PRESS', alt=True) + kmi.properties.name = "VIEW3D_MT_sv3_brush_options" + addon_keymaps.append((km, kmi)) + def unregister(): - # unregister brush menu - brush_menu.unregister() - - # delete all the properties you have created - del_props() - + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() + # unregister all blender classes bpy.utils.unregister_module(__name__) + if __name__ == "__main__": register() diff --git a/space_view3d_brush_menus/brush_menu.py b/space_view3d_brush_menus/brush_menu.py index 91daf19c..6940304e 100644 --- a/space_view3d_brush_menus/brush_menu.py +++ b/space_view3d_brush_menus/brush_menu.py @@ -1,156 +1,212 @@ -from bpy.props import * -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) + +import bpy +from bpy.types import ( + Operator, + Menu, + ) +from bpy.props import BoolProperty +from . import utils_core +from bl_ui.properties_paint_common import UnifiedPaintPanel + 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'} - + if utils_core.get_mode() == utils_core.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 utils_core.get_mode() == utils_core.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 utils_core.get_mode() == utils_core.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 utils_core.get_mode() == utils_core.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): + +class BrushOptionsMenu(Menu): bl_label = "Brush Options" bl_idname = "VIEW3D_MT_sv3_brush_options" @classmethod def poll(self, context): - if get_mode() in [sculpt, vertex_paint, weight_paint, texture_paint, particle_edit]: - return True + return utils_core.get_mode() in ( + utils_core.sculpt, utils_core.vertex_paint, + utils_core.weight_paint, utils_core.texture_paint, + utils_core.particle_edit + ) + + def draw_brushes(self, menu, h_brush, ico, context): + if utils_core.addon_settings(lists=True) == 'popup' or not h_brush: + menu.add_item().operator( + "view3d.sv3_brush_menu_popup", text="Brush", + icon=ico + ) else: - return False + menu.add_item().menu( + "VIEW3D_MT_sv3_brushes_menu", text="Brush", + icon=ico + ) def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) - if get_mode() == sculpt: + if utils_core.get_mode() == utils_core.sculpt: self.sculpt(menu, context) - elif get_mode() in [vertex_paint, weight_paint]: + elif utils_core.get_mode() in (utils_core.vertex_paint, + utils_core.weight_paint): self.vw_paint(menu, context) - elif get_mode() == texture_paint: + elif utils_core.get_mode() == utils_core.texture_paint: self.texpaint(menu, context) else: self.particle(menu, context) def sculpt(self, menu, context): - menu.add_item().menu("VIEW3D_MT_Brush_Selection1", text="Brush", icon=get_current_brush_icon(context.tool_settings.sculpt.brush.sculpt_tool)) + has_brush = utils_core.get_brush_link(context, types="brush") + icons = get_current_brush_icon(has_brush.sculpt_tool) if \ + has_brush else "BRUSH_DATA" + + self.draw_brushes(menu, has_brush, icons, context) + menu.add_item().menu(BrushRadiusMenu.bl_idname) - menu.add_item().menu(BrushStrengthMenu.bl_idname) - menu.add_item().menu(BrushAutosmoothMenu.bl_idname) - menu.add_item().menu(BrushModeMenu.bl_idname) - menu.add_item().menu("VIEW3D_MT_sv3_texture_menu") - menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") - menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") + + if has_brush: + # if the active brush is unlinked these menus don't do anything + menu.add_item().menu(BrushStrengthMenu.bl_idname) + menu.add_item().menu(BrushAutosmoothMenu.bl_idname) + menu.add_item().menu(BrushModeMenu.bl_idname) + menu.add_item().menu("VIEW3D_MT_sv3_texture_menu") + menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") + menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") + menu.add_item().menu("VIEW3D_MT_sv3_dyntopo") menu.add_item().menu("VIEW3D_MT_sv3_master_symmetry_menu") - + def vw_paint(self, menu, context): - if get_mode() == vertex_paint: + has_brush = utils_core.get_brush_link(context, types="brush") + icons = get_current_brush_icon(has_brush.vertex_tool) if \ + has_brush else "BRUSH_DATA" + + if utils_core.get_mode() == utils_core.vertex_paint: menu.add_item().operator(ColorPickerPopup.bl_idname, icon="COLOR") menu.add_item().separator() - menu.add_item().menu("VIEW3D_MT_Brush_Selection1", text="Brush", icon=get_current_brush_icon(context.tool_settings.vertex_paint.brush.vertex_tool)) + + self.draw_brushes(menu, has_brush, icons, context) + + if utils_core.get_mode() == utils_core.vertex_paint: menu.add_item().menu(BrushRadiusMenu.bl_idname) - menu.add_item().menu(BrushStrengthMenu.bl_idname) - menu.add_item().menu(BrushModeMenu.bl_idname) - menu.add_item().menu("VIEW3D_MT_sv3_texture_menu") - menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") - menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") - if get_mode() == weight_paint: - menu.add_item().menu("VIEW3D_MT_Brush_Selection1", text="Brush", icon=get_current_brush_icon(context.tool_settings.vertex_paint.brush.vertex_tool)) + + if has_brush: + # if the active brush is unlinked these menus don't do anything + menu.add_item().menu(BrushStrengthMenu.bl_idname) + menu.add_item().menu(BrushModeMenu.bl_idname) + menu.add_item().menu("VIEW3D_MT_sv3_texture_menu") + menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") + menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") + + if utils_core.get_mode() == utils_core.weight_paint: menu.add_item().menu(BrushWeightMenu.bl_idname) menu.add_item().menu(BrushRadiusMenu.bl_idname) - menu.add_item().menu(BrushStrengthMenu.bl_idname) - menu.add_item().menu(BrushModeMenu.bl_idname) - menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") - menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") + + if has_brush: + # if the active brush is unlinked these menus don't do anything + menu.add_item().menu(BrushStrengthMenu.bl_idname) + menu.add_item().menu(BrushModeMenu.bl_idname) + menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") + menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") def texpaint(self, menu, context): toolsettings = context.tool_settings.image_paint - + if context.image_paint_object and not toolsettings.detect_data(): - menu.add_item().label("Missing Data", icon='ERROR') - menu.add_item().label("See Tool Shelf") + menu.add_item().label("Missing Data", icon="INFO") + menu.add_item().label("See Tool Shelf", icon="BACK") else: - if toolsettings.brush.image_tool in {'DRAW', 'FILL'} and \ - toolsettings.brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}: + has_brush = utils_core.get_brush_link(context, types="brush") + if has_brush and has_brush.image_tool in {'DRAW', 'FILL'} and \ + has_brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}: menu.add_item().operator(ColorPickerPopup.bl_idname, icon="COLOR") menu.add_item().separator() - - menu.add_item().menu("VIEW3D_MT_Brush_Selection1", text="Brush", icon=get_current_brush_icon(toolsettings.brush.image_tool)) - - if toolsettings.brush.image_tool in {'MASK'}: - menu.add_item().menu(BrushWeightMenu.bl_idname, text="Mask Value") - - 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 {'DRAW'}: - menu.add_item().menu(BrushModeMenu.bl_idname) - menu.add_item().menu("VIEW3D_MT_sv3_texture_menu") - menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") - menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") - menu.add_item().menu("VIEW3D_MT_sv3_master_symmetry_menu") + icons = get_current_brush_icon(has_brush.image_tool) if \ + has_brush else "BRUSH_DATA" + + self.draw_brushes(menu, has_brush, icons, context) + + if has_brush: + # if the active brush is unlinked these menus don't do anything + if has_brush and has_brush.image_tool in {'MASK'}: + menu.add_item().menu(BrushWeightMenu.bl_idname, text="Mask Value") + + if has_brush and has_brush.image_tool not in {'FILL'}: + menu.add_item().menu(BrushRadiusMenu.bl_idname) + + menu.add_item().menu(BrushStrengthMenu.bl_idname) + + if has_brush and has_brush.image_tool in {'DRAW'}: + menu.add_item().menu(BrushModeMenu.bl_idname) + + menu.add_item().menu("VIEW3D_MT_sv3_texture_menu") + menu.add_item().menu("VIEW3D_MT_sv3_stroke_options") + menu.add_item().menu("VIEW3D_MT_sv3_brush_curve_menu") + + menu.add_item().menu("VIEW3D_MT_sv3_master_symmetry_menu") def particle(self, menu, context): if context.tool_settings.particle_edit.tool == 'NONE': - menu.add_item().label("No Brush Selected") - menu.add_item().menu("VIEW3D_MT_sv3_brushes_menu", text="Select Brush") + menu.add_item().label("No Brush Selected", icon="INFO") + menu.add_item().separator() + menu.add_item().menu("VIEW3D_MT_sv3_brushes_menu", + text="Select Brush", icon="BRUSH_DATA") else: - menu.add_item().menu("VIEW3D_MT_sv3_brushes_menu") + menu.add_item().menu("VIEW3D_MT_sv3_brushes_menu", + icon="BRUSH_DATA") menu.add_item().menu(BrushRadiusMenu.bl_idname) + if context.tool_settings.particle_edit.tool != 'ADD': menu.add_item().menu(BrushStrengthMenu.bl_idname) - else: menu.add_item().menu(ParticleCountMenu.bl_idname) menu.add_item().separator() @@ -173,19 +229,20 @@ class BrushOptionsMenu(bpy.types.Menu): "use_puff_volume", toggle=True) -class BrushRadiusMenu(bpy.types.Menu): +class BrushRadiusMenu(Menu): bl_label = "Radius" bl_idname = "VIEW3D_MT_sv3_brush_radius_menu" + bl_description = "Change the size of the brushes" def init(self, context): - if get_mode() == particle_edit: + if utils_core.get_mode() == utils_core.particle_edit: settings = [["100", 100], ["70", 70], ["50", 50], ["30", 30], ["20", 20], ["10", 10]] - + datapath = "tool_settings.particle_edit.brush.size" proppath = context.tool_settings.particle_edit.brush @@ -196,7 +253,7 @@ class BrushRadiusMenu(bpy.types.Menu): ["50", 50], ["35", 35], ["10", 10]] - + datapath = "tool_settings.unified_paint_settings.size" proppath = context.tool_settings.unified_paint_settings @@ -204,7 +261,7 @@ class BrushRadiusMenu(bpy.types.Menu): def draw(self, context): settings, datapath, proppath = self.init(context) - menu = Menu(self) + menu = utils_core.Menu(self) # add the top slider menu.add_item().prop(proppath, "size", slider=True) @@ -212,12 +269,14 @@ class BrushRadiusMenu(bpy.types.Menu): # add the rest of the menu items for i in range(len(settings)): - menuprop(menu.add_item(), settings[i][0], settings[i][1], - datapath, icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') + utils_core.menuprop( + menu.add_item(), settings[i][0], settings[i][1], + datapath, icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) -class BrushStrengthMenu(bpy.types.Menu): +class BrushStrengthMenu(Menu): bl_label = "Strength" bl_idname = "VIEW3D_MT_sv3_brush_strength_menu" @@ -229,21 +288,19 @@ class BrushStrengthMenu(bpy.types.Menu): ["0.2", 0.2], ["0.1", 0.1]] - if get_mode() == sculpt: + proppath = utils_core.get_brush_link(context, types="brush") + + if utils_core.get_mode() == utils_core.sculpt: datapath = "tool_settings.sculpt.brush.strength" - proppath = context.tool_settings.sculpt.brush - elif get_mode() == vertex_paint: + elif utils_core.get_mode() == utils_core.vertex_paint: datapath = "tool_settings.vertex_paint.brush.strength" - proppath = context.tool_settings.vertex_paint.brush - elif get_mode() == weight_paint: + elif utils_core.get_mode() == utils_core.weight_paint: datapath = "tool_settings.weight_paint.brush.strength" - proppath = context.tool_settings.weight_paint.brush - elif get_mode() == texture_paint: + elif utils_core.get_mode() == utils_core.texture_paint: datapath = "tool_settings.image_paint.brush.strength" - proppath = context.tool_settings.image_paint.brush else: datapath = "tool_settings.particle_edit.brush.strength" @@ -253,63 +310,80 @@ class BrushStrengthMenu(bpy.types.Menu): def draw(self, context): settings, datapath, proppath = self.init(context) - menu = Menu(self) + menu = utils_core.Menu(self) # add the top slider - menu.add_item().prop(proppath, "strength", slider=True) - menu.add_item().separator() + if proppath: + menu.add_item().prop(proppath, "strength", 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], - datapath, icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') + # add the rest of the menu items + for i in range(len(settings)): + utils_core.menuprop( + menu.add_item(), settings[i][0], settings[i][1], + datapath, icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) + else: + menu.add_item().label("No brushes available", icon="INFO") -class BrushModeMenu(bpy.types.Menu): +class BrushModeMenu(Menu): bl_label = "Brush Mode" bl_idname = "VIEW3D_MT_sv3_brush_mode_menu" def init(self): - if get_mode() == sculpt: - enum = bpy.context.tool_settings.sculpt.brush.bl_rna.properties['sculpt_plane'].enum_items + has_brush = utils_core.get_brush_link(bpy.context, types="brush") + + if utils_core.get_mode() == utils_core.sculpt: + enum = has_brush.bl_rna.properties['sculpt_plane'].enum_items if \ + has_brush else None path = "tool_settings.sculpt.brush.sculpt_plane" - elif get_mode() == texture_paint: - enum = bpy.context.tool_settings.image_paint.brush.bl_rna.properties['blend'].enum_items + elif utils_core.get_mode() == utils_core.texture_paint: + enum = has_brush.bl_rna.properties['blend'].enum_items if \ + has_brush else None path = "tool_settings.image_paint.brush.blend" else: - enum = bpy.context.tool_settings.vertex_paint.brush.bl_rna.properties['vertex_tool'].enum_items + enum = has_brush.bl_rna.properties['vertex_tool'].enum_items if \ + has_brush else None path = "tool_settings.vertex_paint.brush.vertex_tool" return enum, path def draw(self, context): enum, path = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) + colum_n = utils_core.addon_settings(lists=False) menu.add_item().label(text="Brush 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 enum: - menuprop(menu.add_item(parent=column_flow), brush.name, - brush.identifier, path, icon='RADIOBUT_OFF', - disable=True, disable_icon='RADIOBUT_ON') - + if enum: + if utils_core.get_mode() == utils_core.texture_paint: + column_flow = menu.add_item("column_flow", columns=colum_n) + + # add all the brush modes to the menu + for brush in enum: + utils_core.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 enum: + utils_core.menuprop( + menu.add_item(), 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 enum: - menuprop(menu.add_item(), brush.name, - brush.identifier, path, icon='RADIOBUT_OFF', - disable=True, disable_icon='RADIOBUT_ON') + menu.add_item().label("No brushes available", icon="INFO") -class BrushAutosmoothMenu(bpy.types.Menu): +class BrushAutosmoothMenu(Menu): bl_label = "Autosmooth" bl_idname = "VIEW3D_MT_sv3_brush_autosmooth_menu" @@ -325,27 +399,32 @@ class BrushAutosmoothMenu(bpy.types.Menu): def draw(self, context): settings = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) + has_brush = utils_core.get_brush_link(context, types="brush") - # add the top slider - menu.add_item().prop(context.tool_settings.sculpt.brush, - "auto_smooth_factor", slider=True) - menu.add_item().separator() + if has_brush: + # add the top slider + menu.add_item().prop(has_brush, "auto_smooth_factor", 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.sculpt.brush.auto_smooth_factor", - icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') + # add the rest of the menu items + for i in range(len(settings)): + utils_core.menuprop( + menu.add_item(), settings[i][0], settings[i][1], + "tool_settings.sculpt.brush.auto_smooth_factor", + icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) + else: + menu.add_item().label("No Smooth options available", icon="INFO") -class BrushWeightMenu(bpy.types.Menu): +class BrushWeightMenu(Menu): bl_label = "Weight" bl_idname = "VIEW3D_MT_sv3_brush_weight_menu" def draw(self, context): - if get_mode() == weight_paint: + if utils_core.get_mode() == utils_core.weight_paint: brush = context.tool_settings.unified_paint_settings brushstr = "tool_settings.unified_paint_settings.weight" name = "Weight" @@ -353,29 +432,33 @@ class BrushWeightMenu(bpy.types.Menu): brush = context.tool_settings.image_paint.brush brushstr = "tool_settings.image_paint.brush.weight" name = "Mask Value" - - menu = Menu(self) + + menu = utils_core.Menu(self) settings = [["1.0", 1.0], ["0.7", 0.7], ["0.5", 0.5], ["0.3", 0.3], ["0.2", 0.2], ["0.1", 0.1]] + if brush: + # add the top slider + menu.add_item().prop(brush, + "weight", text=name, slider=True) + menu.add_item().separator() - # add the top slider - 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], - brushstr, - icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') + # add the rest of the menu items + for i in range(len(settings)): + utils_core.menuprop( + menu.add_item(), settings[i][0], settings[i][1], + brushstr, + icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) + else: + menu.add_item().label("No brush available", icon="INFO") -class ParticleCountMenu(bpy.types.Menu): +class ParticleCountMenu(Menu): bl_label = "Count" bl_idname = "VIEW3D_MT_sv3_particle_count_menu" @@ -391,7 +474,7 @@ class ParticleCountMenu(bpy.types.Menu): def draw(self, context): settings = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) # add the top slider menu.add_item().prop(context.tool_settings.particle_edit.brush, @@ -400,123 +483,168 @@ class ParticleCountMenu(bpy.types.Menu): # 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.particle_edit.brush.count", - icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') + utils_core.menuprop( + menu.add_item(), settings[i][0], settings[i][1], + "tool_settings.particle_edit.brush.count", + icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) -class ParticleLengthMenu(bpy.types.Menu): +class ParticleLengthMenu(Menu): bl_label = "Length Mode" bl_idname = "VIEW3D_MT_sv3_particle_length_menu" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) path = "tool_settings.particle_edit.brush.length_mode" # add the menu items - 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') + for item in context.tool_settings.particle_edit.brush. \ + bl_rna.properties['length_mode'].enum_items: + utils_core.menuprop( + menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON' + ) -class ParticlePuffMenu(bpy.types.Menu): + +class ParticlePuffMenu(Menu): bl_label = "Puff Mode" bl_idname = "VIEW3D_MT_sv3_particle_puff_menu" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) path = "tool_settings.particle_edit.brush.puff_mode" # add the menu items - 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') + for item in context.tool_settings.particle_edit.brush. \ + bl_rna.properties['puff_mode'].enum_items: + utils_core.menuprop( + menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON' + ) + -class FlipColorsTex(bpy.types.Operator): +class FlipColorsAll(Operator): bl_label = "Flip Colors" - bl_idname = "view3d.sv3_flip_colors_tex" + bl_idname = "view3d.sv3_flip_colors_all" + bl_description = "Switch between Foreground and Background colors" + + is_tex = BoolProperty( + default=False, + options={'HIDDEN'} + ) def execute(self, context): try: - bpy.ops.paint.brush_colors_flip() - except: - pass + if self.is_tex is False: + color = context.tool_settings.vertex_paint.brush.color + secondary_color = context.tool_settings.vertex_paint.brush.secondary_color - return {'FINISHED'} - -class FlipColorsVert(bpy.types.Operator): - bl_label = "Flip Colors" - bl_idname = "view3d.sv3_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): + orig_prim = color.hsv + orig_sec = secondary_color.hsv + + color.hsv = orig_sec + secondary_color.hsv = orig_prim + else: + bpy.ops.paint.brush_colors_flip() + + return {'FINISHED'} + + except Exception as e: + utils_core.error_handlers(self, "view3d.sv3_flip_colors_all", e, + "Flip Colors could not be completed") + + return {'CANCELLED'} + + +class ColorPickerPopup(Operator): bl_label = "Color" bl_idname = "view3d.sv3_color_picker_popup" bl_options = {'REGISTER'} + @classmethod + def poll(self, context): + return utils_core.get_mode() in ( + utils_core.vertex_paint, + utils_core.texture_paint + ) + def check(self, context): return True - + def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) - if get_mode() == texture_paint: + if utils_core.get_mode() == utils_core.texture_paint: settings = context.tool_settings.image_paint - brush = settings.brush - + brush = getattr(settings, "brush", None) else: settings = context.tool_settings.vertex_paint brush = settings.brush + brush = getattr(settings, "brush", None) + + if brush: + menu.add_item().template_color_picker(brush, "color", value_slider=True) + menu.add_item("row", align=True).prop(brush, "color", text="") + menu.current_item.prop(brush, "secondary_color", text="") + + if utils_core.get_mode() == utils_core.vertex_paint: + menu.current_item.operator( + FlipColorsAll.bl_idname, + icon='FILE_REFRESH', text="" + ).is_tex = False + else: + menu.current_item.operator( + FlipColorsAll.bl_idname, + icon='FILE_REFRESH', text="" + ).is_tex = True - 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(FlipColorsVert.bl_idname, icon='FILE_REFRESH', text="") + if settings.palette: + menu.add_item("column").template_palette(settings, "palette", color=True) + + menu.add_item().template_ID(settings, "palette", new="palette.new") else: - menu.current_item.operator(FlipColorsTex.bl_idname, icon='FILE_REFRESH', text="") + menu.add_item().label("No brushes currently available", icon="INFO") + + return - if settings.palette: - menu.add_item("column").template_palette(settings, "palette", color=True) - - menu.add_item().template_ID(settings, "palette", new="palette.new") - def execute(self, context): return context.window_manager.invoke_popup(self, width=180) -### ------------ New hotkeys and registration ------------ ### +class BrushMenuPopup(Operator): + bl_label = "Color" + bl_idname = "view3d.sv3_brush_menu_popup" + bl_options = {'REGISTER'} -addon_keymaps = [] + @classmethod + def poll(self, context): + return utils_core.get_mode() in ( + utils_core.vertex_paint, + utils_core.texture_paint, + utils_core.sculpt, + utils_core.weight_paint + ) + def check(self, context): + return True -def register(): - wm = bpy.context.window_manager - modes = ['Sculpt', 'Vertex Paint', 'Weight Paint', 'Image Paint', 'Particle'] + def draw(self, context): + layout = self.layout + settings = UnifiedPaintPanel.paint_settings(context) + colum_n = utils_core.addon_settings(lists=False) - for mode in modes: - km = wm.keyconfigs.addon.keymaps.new(name=mode) - kmi = km.keymap_items.new('wm.call_menu', 'V', 'PRESS', alt=True) - kmi.properties.name = "VIEW3D_MT_sv3_brush_options" - addon_keymaps.append((km, kmi)) + if utils_core.addon_settings(lists=True) != 'popup': + layout.label(text="Seems no active brush", icon="INFO") + layout.label(text="in the Tool Shelf", icon="BACK") + layout.template_ID_preview(settings, "brush", + new="brush.add", rows=3, cols=colum_n) -def unregister(): - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + def execute(self, context): + return context.window_manager.invoke_popup(self, width=180) diff --git a/space_view3d_brush_menus/brushes.py b/space_view3d_brush_menus/brushes.py index 48a0ca38..280b0367 100644 --- a/space_view3d_brush_menus/brushes.py +++ b/space_view3d_brush_menus/brushes.py @@ -1,14 +1,17 @@ -from bpy.props import * -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) +import bpy +from bpy.types import Menu +from . import utils_core +from bl_ui.properties_paint_common import UnifiedPaintPanel - -class BrushesMenu(bpy.types.Menu): + +class BrushesMenu(Menu): bl_label = "Brush" bl_idname = "VIEW3D_MT_sv3_brushes_menu" def init(self): - if get_mode() == sculpt: + if utils_core.get_mode() == utils_core.sculpt: datapath = "tool_settings.sculpt.brush" icon = {"BLOB": 'BRUSH_BLOB', "CLAY": 'BRUSH_CLAY', @@ -29,8 +32,7 @@ class BrushesMenu(bpy.types.Menu): "SMOOTH": 'BRUSH_SMOOTH', "SNAKE_HOOK": 'BRUSH_SNAKE_HOOK', "THUMB": 'BRUSH_THUMB'} - - elif get_mode() == vertex_paint: + elif utils_core.get_mode() == utils_core.vertex_paint: datapath = "tool_settings.vertex_paint.brush" icon = {"ADD": 'BRUSH_ADD', "BLUR": 'BRUSH_BLUR', @@ -39,8 +41,7 @@ class BrushesMenu(bpy.types.Menu): "MIX": 'BRUSH_MIX', "MUL": 'BRUSH_MULTIPLY', "SUB": 'BRUSH_SUBTRACT'} - - elif get_mode() == weight_paint: + elif utils_core.get_mode() == utils_core.weight_paint: datapath = "tool_settings.weight_paint.brush" icon = {"ADD": 'BRUSH_ADD', "BLUR": 'BRUSH_BLUR', @@ -49,8 +50,7 @@ class BrushesMenu(bpy.types.Menu): "MIX": 'BRUSH_MIX', "MUL": 'BRUSH_MULTIPLY', "SUB": 'BRUSH_SUBTRACT'} - - elif get_mode() == texture_paint: + elif utils_core.get_mode() == utils_core.texture_paint: datapath = "tool_settings.image_paint.brush" icon = {"CLONE": 'BRUSH_CLONE', "DRAW": 'BRUSH_TEXDRAW', @@ -58,11 +58,9 @@ class BrushesMenu(bpy.types.Menu): "MASK": 'BRUSH_TEXMASK', "SMEAR": 'BRUSH_SMEAR', "SOFTEN": 'BRUSH_SOFTEN'} - - elif get_mode() == particle_edit: + elif utils_core.get_mode() == utils_core.particle_edit: datapath = "tool_settings.particle_edit.tool" icon = None - else: datapath = "" @@ -70,18 +68,21 @@ class BrushesMenu(bpy.types.Menu): def draw(self, context): datapath, icon = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) + settings = UnifiedPaintPanel.paint_settings(context) + colum_n = utils_core.addon_settings(lists=False) menu.add_item().label(text="Brush") menu.add_item().separator() - current_brush = eval("bpy.context.{}".format(datapath)) + has_brush = utils_core.get_brush_link(context, types="brush") + current_brush = eval("bpy.context.{}".format(datapath)) if has_brush else None # get the current brush's name - if current_brush and get_mode() != particle_edit: + if current_brush and utils_core.get_mode() != utils_core.particle_edit: current_brush = current_brush.name - if get_mode() == particle_edit: + if utils_core.get_mode() == utils_core.particle_edit: particle_tools = [["None", 'NONE'], ["Comb", 'COMB'], ["Smooth", 'SMOOTH'], @@ -93,45 +94,60 @@ class BrushesMenu(bpy.types.Menu): # if you are in particle edit mode add the menu items for particle mode for tool in particle_tools: - menuprop(menu.add_item(), tool[0], tool[1], datapath, - icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') - + utils_core.menuprop( + menu.add_item(), tool[0], tool[1], datapath, + icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) else: - # iterate over all the brushes - for item in bpy.data.brushes: - if get_mode() == sculpt: - if item.use_paint_sculpt: - # if you are in sculpt mode and the brush is a sculpt brush add the brush to the menu - menuprop(menu.add_item(), item.name, - 'bpy.data.brushes["%s"]' % item.name, - datapath, icon=icon[item.sculpt_tool], - disable=True, custom_disable_exp=[item.name, current_brush], - path=True) - - if get_mode() == vertex_paint: - if item.use_paint_vertex: - # if you are in vertex paint mode and the brush is a vertex paint brush add the brush to the menu - menuprop(menu.add_item(), item.name, - 'bpy.data.brushes["%s"]' % item.name, - datapath, icon=icon[item.vertex_tool], - disable=True, custom_disable_exp=[item.name, current_brush], - path=True) - - if get_mode() == weight_paint: - if item.use_paint_weight: - # if you are in weight paint mode and the brush is a weight paint brush add the brush to the menu - menuprop(menu.add_item(), item.name, - 'bpy.data.brushes["%s"]' % item.name, - datapath, icon=icon[item.vertex_tool], - disable=True, custom_disable_exp=[item.name, current_brush], - path=True) - - if get_mode() == texture_paint: - if item.use_paint_image: - # if you are in texture paint mode and the brush is a texture paint brush add the brush to the menu - menuprop(menu.add_item(), item.name, - 'bpy.data.brushes["%s"]' % item.name, - datapath, icon=icon[item.image_tool], - disable=True, custom_disable_exp=[item.name, current_brush], - path=True) + column_flow = menu.add_item("column_flow", columns=colum_n) + if utils_core.addon_settings(lists=True) == 'template': + self.layout.template_ID_preview(settings, "brush", + new="brush.add", rows=3, cols=colum_n) + else: + # iterate over all the brushes + for item in bpy.data.brushes: + if utils_core.get_mode() == utils_core.sculpt: + if item.use_paint_sculpt: + # if you are in sculpt mode and the brush + # is a sculpt brush add the brush to the menu + utils_core.menuprop( + menu.add_item(parent=column_flow), item.name, + 'bpy.data.brushes["%s"]' % item.name, + datapath, icon=icon[item.sculpt_tool], + disable=True, custom_disable_exp=[item.name, current_brush], + path=True + ) + if utils_core.get_mode() == utils_core.vertex_paint: + if item.use_paint_vertex: + # if you are in vertex paint mode and the brush + # is a vertex paint brush add the brush to the menu + utils_core.menuprop( + menu.add_item(parent=column_flow), item.name, + 'bpy.data.brushes["%s"]' % item.name, + datapath, icon=icon[item.vertex_tool], + disable=True, custom_disable_exp=[item.name, current_brush], + path=True + ) + if utils_core.get_mode() == utils_core.weight_paint: + if item.use_paint_weight: + # if you are in weight paint mode and the brush + # is a weight paint brush add the brush to the menu + utils_core.menuprop( + menu.add_item(parent=column_flow), item.name, + 'bpy.data.brushes["%s"]' % item.name, + datapath, icon=icon[item.vertex_tool], + disable=True, custom_disable_exp=[item.name, current_brush], + path=True + ) + if utils_core.get_mode() == utils_core.texture_paint: + if item.use_paint_image: + # if you are in texture paint mode and the brush + # is a texture paint brush add the brush to the menu + utils_core.menuprop( + menu.add_item(parent=column_flow), item.name, + 'bpy.data.brushes["%s"]' % item.name, + datapath, icon=icon[item.image_tool], + disable=True, custom_disable_exp=[item.name, current_brush], + path=True + ) diff --git a/space_view3d_brush_menus/curve_menu.py b/space_view3d_brush_menus/curve_menu.py index b7762e01..32d488bd 100644 --- a/space_view3d_brush_menus/curve_menu.py +++ b/space_view3d_brush_menus/curve_menu.py @@ -1,19 +1,26 @@ -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) +from bpy.types import ( + Operator, + Menu, + ) +from . import utils_core -class BrushCurveMenu(bpy.types.Menu): + +class BrushCurveMenu(Menu): bl_label = "Curve" bl_idname = "VIEW3D_MT_sv3_brush_curve_menu" @classmethod def poll(self, context): - if get_mode() in [sculpt, vertex_paint, weight_paint, texture_paint, particle_edit]: - return True - else: - return False + return utils_core.get_mode() in ( + utils_core.sculpt, utils_core.vertex_paint, + utils_core.weight_paint, utils_core.texture_paint, + utils_core.particle_edit + ) def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) curves = [["Smooth", "SMOOTH", "SMOOTHCURVE"], ["Sphere", "ROUND", "SPHERECURVE"], ["Root", "ROOT", "ROOTCURVE"], @@ -27,31 +34,38 @@ class BrushCurveMenu(bpy.types.Menu): # add the rest of the menu items for curve in curves: - item = menu.add_item().operator("brush.curve_preset", text=curve[0], icon=curve[2]) + item = menu.add_item().operator("brush.curve_preset", + text=curve[0], icon=curve[2]) item.shape = curve[1] -class CurvePopup(bpy.types.Operator): +class CurvePopup(Operator): bl_label = "Adjust Curve" bl_idname = "view3d.sv3_curve_popup" bl_options = {'REGISTER'} - def draw(self, context): - menu = Menu(self) - - if get_mode() == sculpt: - brush = context.tool_settings.sculpt.brush - - elif get_mode() == vertex_paint: - brush = context.tool_settings.vertex_paint.brush + @classmethod + def poll(self, context): + return utils_core.get_mode() in ( + utils_core.sculpt, utils_core.vertex_paint, + utils_core.weight_paint, utils_core.texture_paint + ) - elif get_mode() == weight_paint: - brush = context.tool_settings.weight_paint.brush + def draw(self, context): + menu = utils_core.Menu(self) + has_brush = utils_core.get_brush_link(context, types="brush") + if utils_core.get_mode() == utils_core.sculpt or \ + utils_core.get_mode() == utils_core.vertex_paint or \ + utils_core.get_mode() == utils_core.weight_paint or \ + utils_core.get_mode() == utils_core.texture_paint: + if has_brush: + menu.add_item("column").template_curve_mapping(has_brush, + "curve", brush=True) + else: + menu.add_item().label("No brushes available", icon="INFO") else: - brush = context.tool_settings.image_paint.brush - - menu.add_item("column").template_curve_mapping(brush, "curve", brush=True) + menu.add_item().label("No brushes available", icon="INFO") def execute(self, context): return context.window_manager.invoke_popup(self, width=180) diff --git a/space_view3d_brush_menus/dyntopo_menu.py b/space_view3d_brush_menus/dyntopo_menu.py index a15c562c..bab317f6 100644 --- a/space_view3d_brush_menus/dyntopo_menu.py +++ b/space_view3d_brush_menus/dyntopo_menu.py @@ -1,22 +1,24 @@ -from bpy.props import * -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) -class DynTopoMenu(bpy.types.Menu): +import bpy +from bpy.types import Menu +from . import utils_core + + +class DynTopoMenu(Menu): bl_label = "Dyntopo" bl_idname = "VIEW3D_MT_sv3_dyntopo" @classmethod def poll(self, context): - if get_mode() == sculpt: - return True - else: - return False + return utils_core.get_mode() == utils_core.sculpt def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) if context.object.use_dynamic_topology_sculpting: - menu.add_item().operator("sculpt.dynamic_topology_toggle", "Disable Dynamic Topology") + menu.add_item().operator("sculpt.dynamic_topology_toggle", + "Disable Dynamic Topology") menu.add_item().separator() @@ -26,19 +28,21 @@ class DynTopoMenu(bpy.types.Menu): menu.add_item().separator() menu.add_item().operator("sculpt.optimize") - if bpy.context.tool_settings.sculpt.detail_type_method == 'CONSTANT': + if context.tool_settings.sculpt.detail_type_method == 'CONSTANT': menu.add_item().operator("sculpt.detail_flood_fill") menu.add_item().menu(SymmetrizeMenu.bl_idname) - menu.add_item().prop(context.tool_settings.sculpt, "use_smooth_shading", toggle=True) + menu.add_item().prop(context.tool_settings.sculpt, + "use_smooth_shading", toggle=True) else: menu.add_item() menu.current_item.operator_context = 'INVOKE_DEFAULT' - menu.current_item.operator("sculpt.dynamic_topology_toggle", "Enable Dynamic Topology") + menu.current_item.operator("sculpt.dynamic_topology_toggle", + "Enable Dynamic Topology") -class DynDetailMenu(bpy.types.Menu): +class DynDetailMenu(Menu): bl_label = "Detail Size" bl_idname = "VIEW3D_MT_sv3_dyn_detail" @@ -58,25 +62,28 @@ class DynDetailMenu(bpy.types.Menu): def draw(self, context): settings, datapath, slider_setting = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) # add the top slider - menu.add_item().prop(context.tool_settings.sculpt, slider_setting, slider=True) + menu.add_item().prop(context.tool_settings.sculpt, + slider_setting, 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], datapath, - icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON') + utils_core.menuprop( + menu.add_item(), settings[i][0], settings[i][1], datapath, + icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) -class DetailMethodMenu(bpy.types.Menu): +class DetailMethodMenu(Menu): bl_label = "Detail Method" bl_idname = "VIEW3D_MT_sv3_detail_method_menu" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) refine_path = "tool_settings.sculpt.detail_refine_method" type_path = "tool_settings.sculpt.detail_type_method" @@ -92,8 +99,12 @@ class DetailMethodMenu(bpy.types.Menu): # add the refine menu items for item in refine_items: - menuprop(menu.add_item(), item[0], item[1], refine_path, disable=True, - icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON') + utils_core.menuprop( + menu.add_item(), item[0], item[1], + refine_path, disable=True, + icon='RADIOBUT_OFF', + disable_icon='RADIOBUT_ON' + ) menu.add_item().label("") @@ -102,16 +113,19 @@ class DetailMethodMenu(bpy.types.Menu): # add the type menu items for item in type_items: - menuprop(menu.add_item(), item[0], item[1], type_path, disable=True, - icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON') + utils_core.menuprop( + menu.add_item(), item[0], item[1], + type_path, disable=True, + icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON' + ) -class SymmetrizeMenu(bpy.types.Menu): +class SymmetrizeMenu(Menu): bl_label = "Symmetrize" bl_idname = "VIEW3D_MT_sv3_symmetrize_menu" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) path = "tool_settings.sculpt.symmetrize_direction" # add the the symmetrize operator to the menu @@ -119,7 +133,10 @@ class SymmetrizeMenu(bpy.types.Menu): menu.add_item().separator() # add the rest of the menu items - 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') - + for item in context.tool_settings.sculpt. \ + bl_rna.properties['symmetrize_direction'].enum_items: + utils_core.menuprop( + menu.add_item(), item.name, item.identifier, + path, disable=True, + icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON' + ) diff --git a/space_view3d_brush_menus/stroke_menu.py b/space_view3d_brush_menus/stroke_menu.py index ff0708e7..c2163999 100644 --- a/space_view3d_brush_menus/stroke_menu.py +++ b/space_view3d_brush_menus/stroke_menu.py @@ -1,5 +1,8 @@ -from bpy.props import * -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) + +import bpy +from bpy.types import Menu +from . import utils_core airbrush = 'AIRBRUSH' anchored = 'ANCHORED' @@ -10,108 +13,115 @@ line = 'LINE' curve = 'CURVE' -class StrokeOptionsMenu(bpy.types.Menu): +class StrokeOptionsMenu(Menu): bl_label = "Stroke Options" bl_idname = "VIEW3D_MT_sv3_stroke_options" @classmethod def poll(self, context): - if get_mode() in [sculpt, vertex_paint, weight_paint, texture_paint, particle_edit]: - return True - else: - return False + return utils_core.get_mode() in ( + utils_core.sculpt, utils_core.vertex_paint, + utils_core.weight_paint, utils_core.texture_paint, + utils_core.particle_edit + ) def init(self): - if get_mode() == sculpt: + has_brush = utils_core.get_brush_link(bpy.context, types="brush") + if utils_core.get_mode() == utils_core.sculpt: settings = bpy.context.tool_settings.sculpt - brush = settings.brush - - if bpy.app.version > (2, 71): - stroke_method = brush.stroke_method - - else: - stroke_method = brush.sculpt_stroke_method - elif get_mode() == texture_paint: + elif utils_core.get_mode() == utils_core.texture_paint: settings = bpy.context.tool_settings.image_paint - brush = settings.brush - stroke_method = brush.stroke_method else: settings = bpy.context.tool_settings.vertex_paint - brush = settings.brush - stroke_method = brush.stroke_method - return settings, brush, stroke_method + stroke_method = has_brush.stroke_method if has_brush else None + + return settings, has_brush, stroke_method def draw(self, context): settings, brush, stroke_method = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) menu.add_item().menu(StrokeMethodMenu.bl_idname) - menu.add_item().separator() - if stroke_method == space: - menu.add_item().prop(brush, "spacing", text=PIW+"Spacing", slider=True) + if stroke_method: + if stroke_method == space and brush: + menu.add_item().prop(brush, "spacing", + text=utils_core.PIW + "Spacing", slider=True) - elif stroke_method == airbrush: - menu.add_item().prop(brush, "rate", text=PIW+"Rate", slider=True) + elif stroke_method == airbrush and brush: + menu.add_item().prop(brush, "rate", + text=utils_core.PIW + "Rate", slider=True) - elif stroke_method == anchored: + elif stroke_method == anchored and brush: menu.add_item().prop(brush, "use_edge_to_edge") - - else: - pass - if get_mode() == sculpt and stroke_method in [drag_dot, anchored]: - pass - else: - menu.add_item().prop(brush, "jitter", text=PIW+"Jitter", slider=True) + else: + pass - menu.add_item().prop(settings, "input_samples", text=PIW+"Input Samples", slider=True) - - if stroke_method in [dots, space, airbrush]: - menu.add_item().separator() + if utils_core.get_mode() == utils_core.sculpt and stroke_method in (drag_dot, anchored): + pass + else: + if brush: + menu.add_item().prop(brush, "jitter", + text=utils_core.PIW + "Jitter", slider=True) - menu.add_item().prop(brush, "use_smooth_stroke", toggle=True) + menu.add_item().prop(settings, "input_samples", + text=utils_core.PIW + "Input Samples", 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) + if stroke_method in [dots, space, airbrush] and brush: + menu.add_item().separator() + menu.add_item().prop(brush, "use_smooth_stroke", toggle=True) -class StrokeMethodMenu(bpy.types.Menu): + if brush.use_smooth_stroke: + menu.add_item().prop(brush, "smooth_stroke_radius", + text=utils_core.PIW + "Radius", slider=True) + menu.add_item().prop(brush, "smooth_stroke_factor", + text=utils_core.PIW + "Factor", slider=True) + else: + menu.add_item().label("No Stroke Options available", icon="INFO") + + +class StrokeMethodMenu(Menu): bl_label = "Stroke Method" bl_idname = "VIEW3D_MT_sv3_stroke_method" def init(self): - if get_mode() == sculpt: - brush = bpy.context.tool_settings.sculpt.brush + has_brush = utils_core.get_brush_link(bpy.context, types="brush") + if utils_core.get_mode() == utils_core.sculpt: path = "tool_settings.sculpt.brush.stroke_method" - elif get_mode() == texture_paint: - brush = bpy.context.tool_settings.image_paint.brush + elif utils_core.get_mode() == utils_core.texture_paint: path = "tool_settings.image_paint.brush.stroke_method" else: - brush = bpy.context.tool_settings.vertex_paint.brush path = "tool_settings.vertex_paint.brush.stroke_method" - return brush, path + return has_brush, path def draw(self, context): brush, path = self.init() - menu = Menu(self) + menu = utils_core.Menu(self) menu.add_item().label(text="Stroke Method") menu.add_item().separator() - # 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') + if brush: + # 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 \ + utils_core.get_mode() in [utils_core.vertex_paint, + utils_core.weight_paint]: + continue + + utils_core.menuprop( + menu.add_item(), tool.name, tool.identifier, path, + icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON' + ) + else: + menu.add_item().label("No Stroke Method available", icon="INFO") diff --git a/space_view3d_brush_menus/symmetry_menu.py b/space_view3d_brush_menus/symmetry_menu.py index f345e290..6762ddb6 100644 --- a/space_view3d_brush_menus/symmetry_menu.py +++ b/space_view3d_brush_menus/symmetry_menu.py @@ -1,55 +1,64 @@ -from bpy.props import * -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) +from bpy.types import Menu +from . import utils_core -class MasterSymmetryMenu(bpy.types.Menu): + +class MasterSymmetryMenu(Menu): bl_label = "Symmetry Options" bl_idname = "VIEW3D_MT_sv3_master_symmetry_menu" @classmethod def poll(self, context): - if get_mode() in [sculpt, texture_paint]: - return True - else: - return False + return utils_core.get_mode() in ( + utils_core.sculpt, + utils_core.texture_paint + ) def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) - if get_mode() == texture_paint: - menu.add_item().prop(context.tool_settings.image_paint, "use_symmetry_x", toggle=True) - menu.add_item().prop(context.tool_settings.image_paint, "use_symmetry_y", toggle=True) - menu.add_item().prop(context.tool_settings.image_paint, "use_symmetry_z", toggle=True) + if utils_core.get_mode() == utils_core.texture_paint: + menu.add_item().prop(context.tool_settings.image_paint, + "use_symmetry_x", toggle=True) + menu.add_item().prop(context.tool_settings.image_paint, + "use_symmetry_y", toggle=True) + menu.add_item().prop(context.tool_settings.image_paint, + "use_symmetry_z", toggle=True) else: - menu.add_item().menu(SymmetryMenu.bl_idname) menu.add_item().menu(SymmetryRadialMenu.bl_idname) - menu.add_item().prop(context.tool_settings.sculpt, "use_symmetry_feather", toggle=True) + menu.add_item().prop(context.tool_settings.sculpt, + "use_symmetry_feather", toggle=True) -class SymmetryMenu(bpy.types.Menu): +class SymmetryMenu(Menu): bl_label = "Symmetry" bl_idname = "VIEW3D_MT_sv3_symmetry_menu" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) menu.add_item().label(text="Symmetry") menu.add_item().separator() - menu.add_item().prop(context.tool_settings.sculpt, "use_symmetry_x", toggle=True) - menu.add_item().prop(context.tool_settings.sculpt, "use_symmetry_y", toggle=True) - menu.add_item().prop(context.tool_settings.sculpt, "use_symmetry_z", toggle=True) + menu.add_item().prop(context.tool_settings.sculpt, + "use_symmetry_x", toggle=True) + menu.add_item().prop(context.tool_settings.sculpt, + "use_symmetry_y", toggle=True) + menu.add_item().prop(context.tool_settings.sculpt, + "use_symmetry_z", toggle=True) -class SymmetryRadialMenu(bpy.types.Menu): +class SymmetryRadialMenu(Menu): bl_label = "Radial" bl_idname = "VIEW3D_MT_sv3_symmetry_radial_menu" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) menu.add_item().label(text="Radial") menu.add_item().separator() - - menu.add_item("column").prop(context.tool_settings.sculpt, "radial_symmetry", text="", slider=True) + + menu.add_item("column").prop(context.tool_settings.sculpt, + "radial_symmetry", text="", slider=True) diff --git a/space_view3d_brush_menus/texture_menu.py b/space_view3d_brush_menus/texture_menu.py index 1f44bc8f..d961410b 100644 --- a/space_view3d_brush_menus/texture_menu.py +++ b/space_view3d_brush_menus/texture_menu.py @@ -1,87 +1,98 @@ -from bpy.props import * -from .Utils.core import * +# gpl author: Ryan Inch (Imaginer) +import bpy +from bpy.types import Menu +from . import utils_core -class TextureMenu(bpy.types.Menu): + +class TextureMenu(Menu): bl_label = "Texture Options" bl_idname = "VIEW3D_MT_sv3_texture_menu" @classmethod def poll(self, context): - if get_mode() in [sculpt, vertex_paint, texture_paint]: - return True - else: - return False + return utils_core.get_mode() in ( + utils_core.sculpt, + utils_core.vertex_paint, + utils_core.texture_paint + ) def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) - if get_mode() == sculpt: + if utils_core.get_mode() == utils_core.sculpt: self.sculpt(menu, context) - elif get_mode() == vertex_paint: + elif utils_core.get_mode() == utils_core.vertex_paint: self.vertpaint(menu, context) else: self.texpaint(menu, context) def sculpt(self, menu, context): - tex_slot = context.tool_settings.sculpt.brush.texture_slot - + has_brush = utils_core.get_brush_link(context, types="brush") + tex_slot = has_brush.texture_slot if has_brush else None + # Menus menu.add_item().menu(Textures.bl_idname) menu.add_item().menu(TextureMapMode.bl_idname) + menu.add_item().separator() # Checkboxes - if tex_slot.map_mode != '3D': - if tex_slot.map_mode in ['RANDOM', 'VIEW_PLANE', 'AREA_PLANE']: - if bpy.app.version >= (2, 75): + if tex_slot: + if tex_slot.map_mode != '3D': + if tex_slot.map_mode in ['RANDOM', 'VIEW_PLANE', 'AREA_PLANE']: menu.add_item().prop(tex_slot, "use_rake", toggle=True) menu.add_item().prop(tex_slot, "use_random", toggle=True) - else: - menu.add_item().menu(TextureAngleSource.bl_idname) - # Sliders - menu.add_item().prop(tex_slot, "angle", text=PIW+"Angle", slider=True) - - if tex_slot.tex_paint_map_mode in ['RANDOM', 'VIEW_PLANE'] and tex_slot.use_random: - menu.add_item().prop(tex_slot, "random_angle", text=PIW+"Random Angle", slider=True) - - # Operator - if tex_slot.tex_paint_map_mode == 'STENCIL': - menu.add_item().operator("brush.stencil_reset_transform") + # Sliders + menu.add_item().prop(tex_slot, "angle", + text=utils_core.PIW + "Angle", slider=True) + + if tex_slot.tex_paint_map_mode in ['RANDOM', 'VIEW_PLANE'] and tex_slot.use_random: + menu.add_item().prop(tex_slot, "random_angle", + text=utils_core.PIW + "Random Angle", slider=True) + + # Operator + if tex_slot.tex_paint_map_mode == 'STENCIL': + menu.add_item().operator("brush.stencil_reset_transform") + else: + menu.add_item().label("No Texture Slot available", icon="INFO") def vertpaint(self, menu, context): - tex_slot = context.tool_settings.vertex_paint.brush.texture_slot - + has_brush = utils_core.get_brush_link(context, types="brush") + tex_slot = has_brush.texture_slot if has_brush else None + # Menus menu.add_item().menu(Textures.bl_idname) menu.add_item().menu(TextureMapMode.bl_idname) # Checkboxes - if tex_slot.tex_paint_map_mode != '3D': + if tex_slot and tex_slot.tex_paint_map_mode != '3D': if tex_slot.tex_paint_map_mode in ['RANDOM', 'VIEW_PLANE']: - if bpy.app.version >= (2, 75): - menu.add_item().prop(tex_slot, "use_rake", toggle=True) - menu.add_item().prop(tex_slot, "use_random", toggle=True) - else: - menu.add_item().menu(TextureAngleSource.bl_idname) + menu.add_item().prop(tex_slot, "use_rake", toggle=True) + menu.add_item().prop(tex_slot, "use_random", toggle=True) # Sliders - menu.add_item().prop(tex_slot, "angle", text=PIW+"Angle", slider=True) - + menu.add_item().prop(tex_slot, "angle", + text=utils_core.PIW + "Angle", slider=True) + if tex_slot.tex_paint_map_mode in ['RANDOM', 'VIEW_PLANE'] and tex_slot.use_random: - menu.add_item().prop(tex_slot, "random_angle", text=PIW+"Random Angle", slider=True) - + menu.add_item().prop(tex_slot, "random_angle", + text=utils_core.PIW + "Random Angle", slider=True) + # Operator if tex_slot.tex_paint_map_mode == 'STENCIL': menu.add_item().operator("brush.stencil_reset_transform") + else: + menu.add_item().label("No Texture Slot available", icon="INFO") def texpaint(self, menu, context): - tex_slot = context.tool_settings.image_paint.brush.texture_slot - mask_tex_slot = context.tool_settings.image_paint.brush.mask_texture_slot - + has_brush = utils_core.get_brush_link(context, types="brush") + tex_slot = has_brush.texture_slot if has_brush else None + mask_tex_slot = has_brush.mask_texture_slot if has_brush else None + # Texture Section menu.add_item().label(text="Texture", icon='TEXTURE') @@ -90,20 +101,19 @@ class TextureMenu(bpy.types.Menu): menu.add_item().menu(TextureMapMode.bl_idname) # Checkboxes - if tex_slot.tex_paint_map_mode != '3D': + if tex_slot and tex_slot.tex_paint_map_mode != '3D': if tex_slot.tex_paint_map_mode in ['RANDOM', 'VIEW_PLANE']: - if bpy.app.version >= (2, 75): - menu.add_item().prop(tex_slot, "use_rake", toggle=True) - menu.add_item().prop(tex_slot, "use_random", toggle=True) - else: - menu.add_item().menu(TextureAngleSource.bl_idname) + menu.add_item().prop(tex_slot, "use_rake", toggle=True) + menu.add_item().prop(tex_slot, "use_random", toggle=True) # Sliders - menu.add_item().prop(tex_slot, "angle", text=PIW+"Angle", slider=True) + menu.add_item().prop(tex_slot, "angle", + text=utils_core.PIW + "Angle", slider=True) if tex_slot.tex_paint_map_mode in ['RANDOM', 'VIEW_PLANE'] and tex_slot.use_random: - menu.add_item().prop(tex_slot, "random_angle", text=PIW+"Random Angle", slider=True) - + menu.add_item().prop(tex_slot, "random_angle", + text=utils_core.PIW + "Random Angle", slider=True) + # Operator if tex_slot.tex_paint_map_mode == 'STENCIL': menu.add_item().operator("brush.stencil_reset_transform") @@ -118,37 +128,40 @@ class TextureMenu(bpy.types.Menu): menu.add_item().menu(MaskMapMode.bl_idname) # Checkboxes - if mask_tex_slot.mask_map_mode in ['RANDOM', 'VIEW_PLANE']: - if bpy.app.version >= (2, 75): + if mask_tex_slot: + if mask_tex_slot.mask_map_mode in ['RANDOM', 'VIEW_PLANE']: menu.add_item().prop(mask_tex_slot, "use_rake", toggle=True) menu.add_item().prop(mask_tex_slot, "use_random", toggle=True) - else: - menu.add_item().menu(TextureAngleSource.bl_idname) - # Sliders - menu.add_item().prop(mask_tex_slot, "angle", text=PIW+"Angle", icon_value=5, slider=True) + # Sliders + menu.add_item().prop(mask_tex_slot, "angle", + text=utils_core.PIW + "Angle", icon_value=5, slider=True) - if mask_tex_slot.mask_map_mode in ['RANDOM', 'VIEW_PLANE'] and mask_tex_slot.use_random: - menu.add_item().prop(mask_tex_slot, "random_angle", text=PIW+"Random Angle", slider=True) - - # Operator - if mask_tex_slot.mask_map_mode == 'STENCIL': - prop = menu.add_item().operator("brush.stencil_reset_transform") - prop.mask = True + if mask_tex_slot.mask_map_mode in ['RANDOM', 'VIEW_PLANE'] and \ + mask_tex_slot.use_random: + menu.add_item().prop(mask_tex_slot, "random_angle", + text=utils_core.PIW + "Random Angle", slider=True) + # Operator + if mask_tex_slot.mask_map_mode == 'STENCIL': + prop = menu.add_item().operator("brush.stencil_reset_transform") + prop.mask = True + else: + menu.add_item().label("Mask Texture not available", icon="INFO") -class Textures(bpy.types.Menu): + +class Textures(Menu): bl_label = "Brush Texture" bl_idname = "VIEW3D_MT_sv3_texture_list" def init(self): - if get_mode() == sculpt: + if utils_core.get_mode() == utils_core.sculpt: datapath = "tool_settings.sculpt.brush.texture" - elif get_mode() == vertex_paint: + elif utils_core.get_mode() == utils_core.vertex_paint: datapath = "tool_settings.vertex_paint.brush.texture" - elif get_mode() == texture_paint: + elif utils_core.get_mode() == utils_core.texture_paint: datapath = "tool_settings.image_paint.brush.texture" else: @@ -158,8 +171,10 @@ class Textures(bpy.types.Menu): def draw(self, context): datapath = self.init() - current_texture = eval("bpy.context.{}".format(datapath)) - menu = Menu(self) + has_brush = utils_core.get_brush_link(context, types="brush") + current_texture = eval("bpy.context.{}".format(datapath)) if \ + has_brush else None + menu = utils_core.Menu(self) # get the current texture's name if current_texture: @@ -169,7 +184,7 @@ class Textures(bpy.types.Menu): menu.add_item().separator() # add an item to set the texture to None - menuprop(menu.add_item(), "None", "None", + utils_core.menuprop(menu.add_item(), "None", "None", datapath, icon='RADIOBUT_OFF', disable=True, disable_icon='RADIOBUT_ON', custom_disable_exp=[None, current_texture], @@ -177,7 +192,7 @@ class Textures(bpy.types.Menu): # add the menu items for item in bpy.data.textures: - menuprop(menu.add_item(), item.name, + utils_core.menuprop(menu.add_item(), item.name, 'bpy.data.textures["%s"]' % item.name, datapath, icon='RADIOBUT_OFF', disable=True, @@ -186,121 +201,156 @@ class Textures(bpy.types.Menu): path=True) -class TextureMapMode(bpy.types.Menu): +class TextureMapMode(Menu): bl_label = "Brush Mapping" bl_idname = "VIEW3D_MT_sv3_texture_map_mode" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) + has_brush = utils_core.get_brush_link(context, types="brush") menu.add_item().label(text="Brush Mapping") menu.add_item().separator() - if get_mode() == sculpt: - path = "tool_settings.sculpt.brush.texture_slot.map_mode" - - # add the menu items - 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" - - # add the menu items - 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') - + if has_brush: + if utils_core.get_mode() == utils_core.sculpt: + path = "tool_settings.sculpt.brush.texture_slot.map_mode" + + # add the menu items + for item in has_brush. \ + texture_slot.bl_rna.properties['map_mode'].enum_items: + utils_core.menuprop( + menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON' + ) + elif utils_core.get_mode() == utils_core.vertex_paint: + path = "tool_settings.vertex_paint.brush.texture_slot.tex_paint_map_mode" + + # add the menu items + for item in has_brush. \ + texture_slot.bl_rna.properties['tex_paint_map_mode'].enum_items: + utils_core.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" + + # add the menu items + for item in has_brush. \ + texture_slot.bl_rna.properties['tex_paint_map_mode'].enum_items: + utils_core.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" - - # add the menu items - 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') + menu.add_item().label("No brushes available", icon="INFO") -class MaskTextures(bpy.types.Menu): +class MaskTextures(Menu): bl_label = "Mask Texture" bl_idname = "VIEW3D_MT_sv3_mask_texture_list" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) datapath = "tool_settings.image_paint.brush.mask_texture" - current_texture = eval("bpy.context.{}".format(datapath)) + has_brush = utils_core.get_brush_link(context, types="brush") + current_texture = eval("bpy.context.{}".format(datapath)) if \ + has_brush else None menu.add_item().label(text="Mask Texture") menu.add_item().separator() - # get the current texture's name - if current_texture: - current_texture = current_texture.name + if has_brush: + # get the current texture's name + if current_texture: + current_texture = current_texture.name - # add an item to set the texture to None - menuprop(menu.add_item(), "None", "None", - datapath, icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON', - custom_disable_exp=[None, current_texture], - path=True) + # add an item to set the texture to None + utils_core.menuprop( + menu.add_item(), "None", "None", + datapath, icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON', + custom_disable_exp=[None, current_texture], + path=True + ) - # add the menu items - for item in bpy.data.textures: - menuprop(menu.add_item(), item.name, 'bpy.data.textures["%s"]' % item.name, - datapath, icon='RADIOBUT_OFF', disable=True, - disable_icon='RADIOBUT_ON', - custom_disable_exp=[item.name, current_texture], - path=True) + # add the menu items + for item in bpy.data.textures: + utils_core.menuprop( + menu.add_item(), item.name, 'bpy.data.textures["%s"]' % item.name, + datapath, icon='RADIOBUT_OFF', disable=True, + disable_icon='RADIOBUT_ON', + custom_disable_exp=[item.name, current_texture], + path=True + ) + else: + menu.add_item().label("No brushes available", icon="INFO") -class MaskMapMode(bpy.types.Menu): +class MaskMapMode(Menu): bl_label = "Mask Mapping" bl_idname = "VIEW3D_MT_sv3_mask_map_mode" def draw(self, context): - menu = Menu(self) - + menu = utils_core.Menu(self) path = "tool_settings.image_paint.brush.mask_texture_slot.mask_map_mode" + has_brush = utils_core.get_brush_link(context, types="brush") menu.add_item().label(text="Mask Mapping") menu.add_item().separator() - - # add the menu items - 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') + if has_brush: + items = has_brush. \ + mask_texture_slot.bl_rna.properties['mask_map_mode'].enum_items + # add the menu items + for item in items: + utils_core.menuprop( + menu.add_item(), item.name, item.identifier, path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON' + ) + else: + menu.add_item().label("No brushes available", icon="INFO") -class TextureAngleSource(bpy.types.Menu): +class TextureAngleSource(Menu): bl_label = "Texture Angle Source" bl_idname = "VIEW3D_MT_sv3_texture_angle_source" def draw(self, context): - menu = Menu(self) + menu = utils_core.Menu(self) + has_brush = utils_core.get_brush_link(context, types="brush") - 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" + if has_brush: + if utils_core.get_mode() == utils_core.sculpt: + items = has_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" + elif utils_core.get_mode() == utils_core.vertex_paint: + items = has_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" + else: + items = has_brush. \ + bl_rna.properties['texture_angle_source_random'].enum_items + path = "tool_settings.image_paint.brush.texture_angle_source_random" - # add the menu items - for item in items: - menuprop(menu.add_item(), item[0], item[1], path, - icon='RADIOBUT_OFF', - disable=True, - disable_icon='RADIOBUT_ON') + # add the menu items + for item in items: + utils_core.menuprop( + menu.add_item(), item[0], item[1], path, + icon='RADIOBUT_OFF', + disable=True, + disable_icon='RADIOBUT_ON' + ) + else: + menu.add_item().label("No brushes available", icon="INFO") diff --git a/space_view3d_brush_menus/Utils/core.py b/space_view3d_brush_menus/utils_core.py index ea73a87b..ecac6073 100644 --- a/space_view3d_brush_menus/Utils/core.py +++ b/space_view3d_brush_menus/utils_core.py @@ -1,8 +1,6 @@ +# gpl author: Ryan Inch (Imaginer) + import bpy -import time -import sys -import os -import re object_mode = 'OBJECT' edit = 'EDIT' @@ -13,10 +11,53 @@ texture_paint = 'TEXTURE_PAINT' particle_edit = 'PARTICLE_EDIT' pose = 'POSE' gpencil_edit = 'GPENCIL_EDIT' +get_addon_name = 'space_view3d_brush_menus' PIW = ' ' -a_props = [] + +# check for (currently) brushes being linked +def get_brush_link(context, types="brush"): + tool_settings = context.tool_settings + has_brush = None + + if get_mode() == sculpt: + datapath = tool_settings.sculpt + + elif get_mode() == vertex_paint: + datapath = tool_settings.vertex_paint + + elif get_mode() == weight_paint: + datapath = tool_settings.weight_paint + + elif get_mode() == texture_paint: + datapath = tool_settings.image_paint + else: + datapath = None + + if types == "brush": + has_brush = getattr(datapath, "brush", None) + + return has_brush + + +# Addon settings +def addon_settings(lists=True): + # separate function just for more convience + addon = bpy.context.user_preferences.addons[get_addon_name] + colum_n = addon.preferences.column_set if addon else 1 + use_list = addon.preferences.use_brushes_menu_type + + return use_list if lists else colum_n + + +def error_handlers(self, op_name, error, reports="ERROR", func=False): + if self and reports: + self.report({'WARNING'}, reports + " (See Console for more info)") + + is_func = "Function" if func else "Operator" + print("\n[Sculpt/Paint Brush Menus]\n{}: {}\nError: {}\n".format(is_func, op_name, error)) + class Menu(): def __init__(self, menu): @@ -34,7 +75,7 @@ class Menu(): # set unique identifier for new items if not name: name = len(self.items) + 1 - + # create and return a ui layout if ui_type == "row": self.current_item = self.items[name] = layout.row(**kwargs) @@ -60,43 +101,21 @@ class Menu(): self.current_item = self.items[name] = layout.split(**kwargs) return self.current_item - else: print("Unknown Type") -def get_selected(): - # get the number of verts from the information string on the info header - sel_verts_num = (e for e in bpy.context.scene.statistics().split(" | ") - if e.startswith("Verts:")).__next__()[6:].split("/") - - # turn the number of verts from a string to an int - sel_verts_num = int(sel_verts_num[0].replace("," ,"")) - - # get the number of edges from the information string on the info header - sel_edges_num = (e for e in bpy.context.scene.statistics().split(" | ") - if e.startswith("Edges:")).__next__()[6:].split("/") - - # turn the number of edges from a string to an int - sel_edges_num = int(sel_edges_num[0].replace(",", "")) - - # get the number of faces from the information string on the info header - sel_faces_num = (e for e in bpy.context.scene.statistics().split(" | ") - if e.startswith("Faces:")).__next__()[6:].split("/") - - # turn the number of faces from a string to an int - sel_faces_num = int(sel_faces_num[0].replace(",", "")) - - return sel_verts_num, sel_edges_num, sel_faces_num - - def get_mode(): - if bpy.context.gpencil_data and \ - bpy.context.object.mode == object_mode and \ - bpy.context.scene.grease_pencil.use_stroke_edit_mode: - return gpencil_edit - else: - return bpy.context.object.mode + try: + if bpy.context.gpencil_data and \ + bpy.context.object.mode == object_mode and \ + bpy.context.scene.grease_pencil.use_stroke_edit_mode: + return gpencil_edit + else: + return bpy.context.object.mode + except: + return None + def menuprop(item, name, value, data_path, icon='NONE', disable=False, disable_icon=None, @@ -144,61 +163,3 @@ def menuprop(item, name, value, data_path, # sets the path to what is changed prop.data_path = data_path - -# used for global blender properties -def set_prop(prop_type, path, **kwargs): - kwstring = "" - - # turn **kwargs into a string that can be used with exec - for k, v in kwargs.items(): - if type(v) is str: - v = '"{}"'.format(v) - - if callable(v): - exec("from {0} import {1}".format(v.__module__, v.__name__)) - v = v.__name__ - - kwstring += "{0}={1}, ".format(k, v) - - kwstring = kwstring[:-2] - - # create the property - exec("{0} = bpy.props.{1}({2})".format(path, prop_type, kwstring)) - - # add the path to a list of property paths - a_props.append(path) - - return eval(path) - -# used for removing properties created with set_prop -def del_props(): - for prop in a_props: - exec("del {}".format(prop)) - - a_props.clear() - -class SendReport(bpy.types.Operator): - bl_label = "Send Report" - bl_idname = "view3d.send_report" - - message = bpy.props.StringProperty() - - def draw(self, context): - self.layout.label("Error", icon='ERROR') - self.layout.label(self.message) - - def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_popup(self, width=400, height=200) - - def execute(self, context): - self.report({'INFO'}, self.message) - print(self.message) - return {'FINISHED'} - -def send_report(message): - def report(scene): - bpy.ops.view3d.send_report('INVOKE_DEFAULT', message=message) - bpy.app.handlers.scene_update_pre.remove(report) - - bpy.app.handlers.scene_update_pre.append(report) |