Sculpt Paint Brush Menus: cleanup, refactor, various fixes

Bumped version to 1.1.4
Remove the Utils folder and move it to file utils_core
Remove star imports and replace them with namespace
Remove unused imports
Use importlib for reloading files
Add customization to the brushes (column size, 3 types of menus)
Remove the VIEW3D_MT_Brush_Selection1 menu
Remove versioning code
Add some helper functions in utils_core
Fix crash with poll functions get_mode if no active object
Fix several crashes with unlinked  missing active brush
(hope i got it all)
Move the shortcut register to the init
Update wiki link

NOTE:
Remove unused operators and functions
Part of it is something to do with properties creation
Haven't seen the code used anywhere so it was removed
If it is needed for something it could be restored later
This commit is contained in:
Vuk Gardašević 2017-04-22 03:54:45 +02:00
parent 3fe42bb946
commit 29f2b2f34a
10 changed files with 970 additions and 772 deletions

View File

@ -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,
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,
)
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
# 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_Brush_Selection1(bpy.types.Menu):
bl_label = "Brush Tool"
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):
class VIEW3D_MT_Brushes_Pref(AddonPreferences):
bl_idname = __name__
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")
)
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
row = layout.row()
row.prop(self, "use_brushes_lists")
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)
# 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()

View File

@ -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'}
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 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 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 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 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'}
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):
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")
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:
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))
menu.add_item().menu(BrushRadiusMenu.bl_idname)
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")
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))
menu.add_item().menu("VIEW3D_MT_sv3_dyntopo")
menu.add_item().menu("VIEW3D_MT_sv3_master_symmetry_menu")
def vw_paint(self, menu, context):
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()
self.draw_brushes(menu, has_brush, icons, context)
if utils_core.get_mode() == utils_core.vertex_paint:
menu.add_item().menu(BrushRadiusMenu.bl_idname)
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")
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'}
orig_prim = color.hsv
orig_sec = secondary_color.hsv
class ColorPickerPopup(bpy.types.Operator):
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)
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 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
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)

View File

@ -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
)

View File

@ -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'}
@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
)
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
elif get_mode() == weight_paint:
brush = context.tool_settings.weight_paint.brush
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)

View File

@ -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'
)

View File

@ -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 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(settings, "input_samples",
text=utils_core.PIW + "Input Samples", 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)
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:
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)
menu.add_item().prop(settings, "input_samples", text=PIW+"Input Samples", slider=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=PIW+"Radius", slider=True)
menu.add_item().prop(brush, "smooth_stroke_factor", text=PIW+"Factor", slider=True)
menu.add_item().label("No Stroke Options available", icon="INFO")
class StrokeMethodMenu(bpy.types.Menu):
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")

View File

@ -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)

View File

@ -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"
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 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')
# 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"
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')
# 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 = 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:
utils_core.menuprop(
menu.add_item(), item[0], item[1], path,
icon='RADIOBUT_OFF',
disable=True,
disable_icon='RADIOBUT_ON'
)
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
for item in items:
menuprop(menu.add_item(), item[0], item[1], path,
icon='RADIOBUT_OFF',
disable=True,
disable_icon='RADIOBUT_ON')
menu.add_item().label("No brushes available", icon="INFO")

View File

@ -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)