brush menus alt/v: T42564

This commit is contained in:
Brendon Murphy 2017-03-20 09:50:42 +11:00
parent 7f6ae93c54
commit 9007bcd107
10 changed files with 1661 additions and 0 deletions

View File

@ -0,0 +1,204 @@
import bpy
import time
import sys
import os
import re
object_mode = 'OBJECT'
edit = 'EDIT'
sculpt = 'SCULPT'
vertex_paint = 'VERTEX_PAINT'
weight_paint = 'WEIGHT_PAINT'
texture_paint = 'TEXTURE_PAINT'
particle_edit = 'PARTICLE_EDIT'
pose = 'POSE'
gpencil_edit = 'GPENCIL_EDIT'
PIW = ' '
a_props = []
class Menu():
def __init__(self, menu):
self.layout = menu.layout
self.items = {}
self.current_item = None
def add_item(self, ui_type="row", parent=None, name=None, **kwargs):
# set the parent layout
if parent:
layout = parent
else:
layout = self.layout
# 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)
return self.current_item
elif ui_type == "column":
self.current_item = self.items[name] = layout.column(**kwargs)
return self.current_item
elif ui_type == "column_flow":
self.current_item = self.items[name] = layout.column_flow(**kwargs)
return self.current_item
elif ui_type == "box":
self.current_item = self.items[name] = layout.box(**kwargs)
return self.current_item
elif ui_type == "split":
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
def menuprop(item, name, value, data_path,
icon='NONE', disable=False, disable_icon=None,
custom_disable_exp=None, method=None, path=False):
# disable the ui
if disable:
disabled = False
# used if you need a custom expression to disable the ui
if custom_disable_exp:
if custom_disable_exp[0] == custom_disable_exp[1]:
item.enabled = False
disabled = True
# check if the ui should be disabled for numbers
elif isinstance(eval("bpy.context.{}".format(data_path)), float):
if round(eval("bpy.context.{}".format(data_path)), 2) == value:
item.enabled = False
disabled = True
# check if the ui should be disabled for anything else
else:
if eval("bpy.context.{}".format(data_path)) == value:
item.enabled = False
disabled = True
# change the icon to the disable_icon if the ui has been disabled
if disable_icon and disabled:
icon = disable_icon
# creates the menu item
prop = item.operator("wm.context_set_value", text=name, icon=icon)
# sets what the menu item changes
if path:
prop.value = value
value = eval(value)
elif type(value) == str:
prop.value = "'{}'".format(value)
else:
prop.value = '{}'.format(value)
# 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)

View File

@ -0,0 +1,138 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### 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),
"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",
"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
# 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):
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")
)
def draw(self, context):
layout = self.layout
row = layout.row()
row.prop(self, "use_brushes_lists")
def register():
# register all blender classes
bpy.utils.register_module(__name__)
# register brush menu
brush_menu.register()
def unregister():
# unregister brush menu
brush_menu.unregister()
# delete all the properties you have created
del_props()
# unregister all blender classes
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,522 @@
from bpy.props import *
from .Utils.core import *
def get_current_brush_icon(tool):
if get_mode() == sculpt:
icons = {"BLOB":'BRUSH_BLOB',
"CLAY":'BRUSH_CLAY',
"CLAY_STRIPS":'BRUSH_CLAY_STRIPS',
"CREASE":'BRUSH_CREASE',
"DRAW":'BRUSH_SCULPT_DRAW',
"FILL":'BRUSH_FILL',
"FLATTEN":'BRUSH_FLATTEN',
"GRAB":'BRUSH_GRAB',
"INFLATE":'BRUSH_INFLATE',
"LAYER":'BRUSH_LAYER',
"MASK":'BRUSH_MASK',
"NUDGE":'BRUSH_NUDGE',
"PINCH":'BRUSH_PINCH',
"ROTATE":'BRUSH_ROTATE',
"SCRAPE":'BRUSH_SCRAPE',
"SIMPLIFY":'BRUSH_SUBTRACT',
"SMOOTH":'BRUSH_SMOOTH',
"SNAKE_HOOK":'BRUSH_SNAKE_HOOK',
"THUMB":'BRUSH_THUMB'}
elif get_mode() == vertex_paint:
icons = {"ADD":'BRUSH_ADD',
"BLUR":'BRUSH_BLUR',
"DARKEN":'BRUSH_DARKEN',
"LIGHTEN":'BRUSH_LIGHTEN',
"MIX":'BRUSH_MIX',
"MUL":'BRUSH_MULTIPLY',
"SUB":'BRUSH_SUBTRACT'}
elif get_mode() == weight_paint:
icons = {"ADD":'BRUSH_ADD',
"BLUR":'BRUSH_BLUR',
"DARKEN":'BRUSH_DARKEN',
"LIGHTEN":'BRUSH_LIGHTEN',
"MIX":'BRUSH_MIX',
"MUL":'BRUSH_MULTIPLY',
"SUB":'BRUSH_SUBTRACT'}
elif get_mode() == texture_paint:
icons = {"CLONE":'BRUSH_CLONE',
"DRAW":'BRUSH_TEXDRAW',
"FILL":'BRUSH_TEXFILL',
"MASK":'BRUSH_TEXMASK',
"SMEAR":'BRUSH_SMEAR',
"SOFTEN":'BRUSH_SOFTEN'}
icon = icons[tool]
return icon
class BrushOptionsMenu(bpy.types.Menu):
bl_label = "Brush Options"
bl_idname = "VIEW3D_MT_sv3_brush_options"
@classmethod
def poll(self, context):
if get_mode() in [sculpt, vertex_paint, weight_paint, texture_paint, particle_edit]:
return True
else:
return False
def draw(self, context):
menu = Menu(self)
if get_mode() == sculpt:
self.sculpt(menu, context)
elif get_mode() in [vertex_paint, weight_paint]:
self.vw_paint(menu, context)
elif get_mode() == 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))
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)
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))
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")
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")
else:
if toolsettings.brush.image_tool in {'DRAW', 'FILL'} and \
toolsettings.brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
menu.add_item().operator(ColorPickerPopup.bl_idname, icon="COLOR")
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")
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")
else:
menu.add_item().menu("VIEW3D_MT_sv3_brushes_menu")
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()
menu.add_item().prop(context.tool_settings.particle_edit,
"use_default_interpolate", toggle=True)
menu.add_item().prop(context.tool_settings.particle_edit.brush,
"steps", slider=True)
menu.add_item().prop(context.tool_settings.particle_edit,
"default_key_count", slider=True)
if context.tool_settings.particle_edit.tool == 'LENGTH':
menu.add_item().separator()
menu.add_item().menu(ParticleLengthMenu.bl_idname)
if context.tool_settings.particle_edit.tool == 'PUFF':
menu.add_item().separator()
menu.add_item().menu(ParticlePuffMenu.bl_idname)
menu.add_item().prop(context.tool_settings.particle_edit.brush,
"use_puff_volume", toggle=True)
class BrushRadiusMenu(bpy.types.Menu):
bl_label = "Radius"
bl_idname = "VIEW3D_MT_sv3_brush_radius_menu"
def init(self, context):
if get_mode() == 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
else:
settings = [["200", 200],
["150", 150],
["100", 100],
["50", 50],
["35", 35],
["10", 10]]
datapath = "tool_settings.unified_paint_settings.size"
proppath = context.tool_settings.unified_paint_settings
return settings, datapath, proppath
def draw(self, context):
settings, datapath, proppath = self.init(context)
menu = Menu(self)
# add the top slider
menu.add_item().prop(proppath, "size", 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')
class BrushStrengthMenu(bpy.types.Menu):
bl_label = "Strength"
bl_idname = "VIEW3D_MT_sv3_brush_strength_menu"
def init(self, context):
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 get_mode() == sculpt:
datapath = "tool_settings.sculpt.brush.strength"
proppath = context.tool_settings.sculpt.brush
elif get_mode() == vertex_paint:
datapath = "tool_settings.vertex_paint.brush.strength"
proppath = context.tool_settings.vertex_paint.brush
elif get_mode() == weight_paint:
datapath = "tool_settings.weight_paint.brush.strength"
proppath = context.tool_settings.weight_paint.brush
elif get_mode() == texture_paint:
datapath = "tool_settings.image_paint.brush.strength"
proppath = context.tool_settings.image_paint.brush
else:
datapath = "tool_settings.particle_edit.brush.strength"
proppath = context.tool_settings.particle_edit.brush
return settings, datapath, proppath
def draw(self, context):
settings, datapath, proppath = self.init(context)
menu = Menu(self)
# add the top slider
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')
class BrushModeMenu(bpy.types.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
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
path = "tool_settings.image_paint.brush.blend"
else:
enum = bpy.context.tool_settings.vertex_paint.brush.bl_rna.properties['vertex_tool'].enum_items
path = "tool_settings.vertex_paint.brush.vertex_tool"
return enum, path
def draw(self, context):
enum, path = self.init()
menu = Menu(self)
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')
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')
class BrushAutosmoothMenu(bpy.types.Menu):
bl_label = "Autosmooth"
bl_idname = "VIEW3D_MT_sv3_brush_autosmooth_menu"
def init(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]]
return settings
def draw(self, context):
settings = self.init()
menu = Menu(self)
# add the top slider
menu.add_item().prop(context.tool_settings.sculpt.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')
class BrushWeightMenu(bpy.types.Menu):
bl_label = "Weight"
bl_idname = "VIEW3D_MT_sv3_brush_weight_menu"
def draw(self, context):
if get_mode() == weight_paint:
brush = context.tool_settings.unified_paint_settings
brushstr = "tool_settings.unified_paint_settings.weight"
name = "Weight"
else:
brush = context.tool_settings.image_paint.brush
brushstr = "tool_settings.image_paint.brush.weight"
name = "Mask Value"
menu = Menu(self)
settings = [["1.0", 1.0],
["0.7", 0.7],
["0.5", 0.5],
["0.3", 0.3],
["0.2", 0.2],
["0.1", 0.1]]
# 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')
class ParticleCountMenu(bpy.types.Menu):
bl_label = "Count"
bl_idname = "VIEW3D_MT_sv3_particle_count_menu"
def init(self):
settings = [["50", 50],
["25", 25],
["10", 10],
["5", 5],
["3", 3],
["1", 1]]
return settings
def draw(self, context):
settings = self.init()
menu = Menu(self)
# add the top slider
menu.add_item().prop(context.tool_settings.particle_edit.brush,
"count", 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.particle_edit.brush.count",
icon='RADIOBUT_OFF', disable=True,
disable_icon='RADIOBUT_ON')
class ParticleLengthMenu(bpy.types.Menu):
bl_label = "Length Mode"
bl_idname = "VIEW3D_MT_sv3_particle_length_menu"
def draw(self, context):
menu = 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')
class ParticlePuffMenu(bpy.types.Menu):
bl_label = "Puff Mode"
bl_idname = "VIEW3D_MT_sv3_particle_puff_menu"
def draw(self, context):
menu = 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')
class FlipColorsTex(bpy.types.Operator):
bl_label = "Flip Colors"
bl_idname = "view3d.sv3_flip_colors_tex"
def execute(self, context):
try:
bpy.ops.paint.brush_colors_flip()
except:
pass
return {'FINISHED'}
class FlipColorsVert(bpy.types.Operator):
bl_label = "Flip Colors"
bl_idname = "view3d.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):
bl_label = "Color"
bl_idname = "view3d.sv3_color_picker_popup"
bl_options = {'REGISTER'}
def check(self, context):
return True
def draw(self, context):
menu = Menu(self)
if get_mode() == texture_paint:
settings = context.tool_settings.image_paint
brush = settings.brush
else:
settings = context.tool_settings.vertex_paint
brush = settings.brush
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="")
else:
menu.current_item.operator(FlipColorsTex.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")
def execute(self, context):
return context.window_manager.invoke_popup(self, width=180)
### ------------ New hotkeys and registration ------------ ###
addon_keymaps = []
def register():
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():
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()

View File

@ -0,0 +1,137 @@
from bpy.props import *
from .Utils.core import *
class BrushesMenu(bpy.types.Menu):
bl_label = "Brush"
bl_idname = "VIEW3D_MT_sv3_brushes_menu"
def init(self):
if get_mode() == sculpt:
datapath = "tool_settings.sculpt.brush"
icon = {"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:
datapath = "tool_settings.vertex_paint.brush"
icon = {"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:
datapath = "tool_settings.weight_paint.brush"
icon = {"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:
datapath = "tool_settings.image_paint.brush"
icon = {"CLONE": 'BRUSH_CLONE',
"DRAW": 'BRUSH_TEXDRAW',
"FILL": 'BRUSH_TEXFILL',
"MASK": 'BRUSH_TEXMASK',
"SMEAR": 'BRUSH_SMEAR',
"SOFTEN": 'BRUSH_SOFTEN'}
elif get_mode() == particle_edit:
datapath = "tool_settings.particle_edit.tool"
icon = None
else:
datapath = ""
return datapath, icon
def draw(self, context):
datapath, icon = self.init()
menu = Menu(self)
menu.add_item().label(text="Brush")
menu.add_item().separator()
current_brush = eval("bpy.context.{}".format(datapath))
# get the current brush's name
if current_brush and get_mode() != particle_edit:
current_brush = current_brush.name
if get_mode() == particle_edit:
particle_tools = [["None", 'NONE'],
["Comb", 'COMB'],
["Smooth", 'SMOOTH'],
["Add", 'ADD'],
["Length", 'LENGTH'],
["Puff", 'PUFF'],
["Cut", 'CUT'],
["Weight", 'WEIGHT']]
# 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')
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)

View File

@ -0,0 +1,57 @@
from .Utils.core import *
class BrushCurveMenu(bpy.types.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
def draw(self, context):
menu = Menu(self)
curves = [["Smooth", "SMOOTH", "SMOOTHCURVE"],
["Sphere", "ROUND", "SPHERECURVE"],
["Root", "ROOT", "ROOTCURVE"],
["Sharp", "SHARP", "SHARPCURVE"],
["Linear", "LINE", "LINCURVE"],
["Constant", "MAX", "NOCURVE"]]
# add the top slider
menu.add_item().operator(CurvePopup.bl_idname, icon="RNDCURVE")
menu.add_item().separator()
# 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.shape = curve[1]
class CurvePopup(bpy.types.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
elif get_mode() == weight_paint:
brush = context.tool_settings.weight_paint.brush
else:
brush = context.tool_settings.image_paint.brush
menu.add_item("column").template_curve_mapping(brush, "curve", brush=True)
def execute(self, context):
return context.window_manager.invoke_popup(self, width=180)

View File

@ -0,0 +1,125 @@
from bpy.props import *
from .Utils.core import *
class DynTopoMenu(bpy.types.Menu):
bl_label = "Dyntopo"
bl_idname = "VIEW3D_MT_sv3_dyntopo"
@classmethod
def poll(self, context):
if get_mode() == sculpt:
return True
else:
return False
def draw(self, context):
menu = Menu(self)
if context.object.use_dynamic_topology_sculpting:
menu.add_item().operator("sculpt.dynamic_topology_toggle", "Disable Dynamic Topology")
menu.add_item().separator()
menu.add_item().menu(DynDetailMenu.bl_idname)
menu.add_item().menu(DetailMethodMenu.bl_idname)
menu.add_item().separator()
menu.add_item().operator("sculpt.optimize")
if bpy.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)
else:
menu.add_item()
menu.current_item.operator_context = 'INVOKE_DEFAULT'
menu.current_item.operator("sculpt.dynamic_topology_toggle", "Enable Dynamic Topology")
class DynDetailMenu(bpy.types.Menu):
bl_label = "Detail Size"
bl_idname = "VIEW3D_MT_sv3_dyn_detail"
def init(self):
settings = [["40", 40], ["30", 30], ["20", 20],
["10", 10], ["5", 5], ["1", 1]]
if bpy.context.tool_settings.sculpt.detail_type_method == 'RELATIVE':
datapath = "tool_settings.sculpt.detail_size"
slider_setting = "detail_size"
else:
datapath = "tool_settings.sculpt.constant_detail"
slider_setting = "constant_detail"
return settings, datapath, slider_setting
def draw(self, context):
settings, datapath, slider_setting = self.init()
menu = Menu(self)
# add the top slider
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')
class DetailMethodMenu(bpy.types.Menu):
bl_label = "Detail Method"
bl_idname = "VIEW3D_MT_sv3_detail_method_menu"
def draw(self, context):
menu = Menu(self)
refine_path = "tool_settings.sculpt.detail_refine_method"
type_path = "tool_settings.sculpt.detail_type_method"
refine_items = [["Subdivide Edges", 'SUBDIVIDE'],
["Collapse Edges", 'COLLAPSE'],
["Subdivide Collapse", 'SUBDIVIDE_COLLAPSE']]
type_items = [["Relative Detail", 'RELATIVE'],
["Constant Detail", 'CONSTANT']]
menu.add_item().label("Refine")
menu.add_item().separator()
# add the refine menu items
for item in refine_items:
menuprop(menu.add_item(), item[0], item[1], refine_path, disable=True,
icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON')
menu.add_item().label("")
menu.add_item().label("Type")
menu.add_item().separator()
# add the type menu items
for item in type_items:
menuprop(menu.add_item(), item[0], item[1], type_path, disable=True,
icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON')
class SymmetrizeMenu(bpy.types.Menu):
bl_label = "Symmetrize"
bl_idname = "VIEW3D_MT_sv3_symmetrize_menu"
def draw(self, context):
menu = Menu(self)
path = "tool_settings.sculpt.symmetrize_direction"
# add the the symmetrize operator to the menu
menu.add_item().operator("sculpt.symmetrize")
menu.add_item().separator()
# add the rest of the menu items
for item in 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')

View File

@ -0,0 +1,117 @@
from bpy.props import *
from .Utils.core import *
airbrush = 'AIRBRUSH'
anchored = 'ANCHORED'
space = 'SPACE'
drag_dot = 'DRAG_DOT'
dots = 'DOTS'
line = 'LINE'
curve = 'CURVE'
class StrokeOptionsMenu(bpy.types.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
def init(self):
if get_mode() == 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:
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
def draw(self, context):
settings, brush, stroke_method = self.init()
menu = Menu(self)
menu.add_item().menu(StrokeMethodMenu.bl_idname)
menu.add_item().separator()
if stroke_method == space:
menu.add_item().prop(brush, "spacing", text=PIW+"Spacing", slider=True)
elif stroke_method == airbrush:
menu.add_item().prop(brush, "rate", text=PIW+"Rate", slider=True)
elif stroke_method == anchored:
menu.add_item().prop(brush, "use_edge_to_edge")
else:
pass
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)
class StrokeMethodMenu(bpy.types.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
path = "tool_settings.sculpt.brush.stroke_method"
elif get_mode() == texture_paint:
brush = bpy.context.tool_settings.image_paint.brush
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
def draw(self, context):
brush, path = self.init()
menu = 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')

View File

@ -0,0 +1,55 @@
from bpy.props import *
from .Utils.core import *
class MasterSymmetryMenu(bpy.types.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
def draw(self, context):
menu = 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)
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)
class SymmetryMenu(bpy.types.Menu):
bl_label = "Symmetry"
bl_idname = "VIEW3D_MT_sv3_symmetry_menu"
def draw(self, context):
menu = 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)
class SymmetryRadialMenu(bpy.types.Menu):
bl_label = "Radial"
bl_idname = "VIEW3D_MT_sv3_symmetry_radial_menu"
def draw(self, context):
menu = 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)

View File

@ -0,0 +1,306 @@
from bpy.props import *
from .Utils.core import *
class TextureMenu(bpy.types.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
def draw(self, context):
menu = Menu(self)
if get_mode() == sculpt:
self.sculpt(menu, context)
elif get_mode() == 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
# Menus
menu.add_item().menu(Textures.bl_idname)
menu.add_item().menu(TextureMapMode.bl_idname)
# Checkboxes
if tex_slot.map_mode != '3D':
if tex_slot.map_mode in ['RANDOM', 'VIEW_PLANE', 'AREA_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)
# 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")
def vertpaint(self, menu, context):
tex_slot = context.tool_settings.vertex_paint.brush.texture_slot
# 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.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)
# 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")
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
# Texture Section
menu.add_item().label(text="Texture", icon='TEXTURE')
# 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.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)
# 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")
menu.add_item().separator()
# Texture Mask Section
menu.add_item().label(text="Texture Mask", icon='MOD_MASK')
# Menus
menu.add_item().menu(MaskTextures.bl_idname)
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):
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)
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
class Textures(bpy.types.Menu):
bl_label = "Brush Texture"
bl_idname = "VIEW3D_MT_sv3_texture_list"
def init(self):
if get_mode() == sculpt:
datapath = "tool_settings.sculpt.brush.texture"
elif get_mode() == vertex_paint:
datapath = "tool_settings.vertex_paint.brush.texture"
elif get_mode() == texture_paint:
datapath = "tool_settings.image_paint.brush.texture"
else:
datapath = ""
return datapath
def draw(self, context):
datapath = self.init()
current_texture = eval("bpy.context.{}".format(datapath))
menu = Menu(self)
# get the current texture's name
if current_texture:
current_texture = current_texture.name
menu.add_item().label(text="Brush Texture")
menu.add_item().separator()
# 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 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)
class TextureMapMode(bpy.types.Menu):
bl_label = "Brush Mapping"
bl_idname = "VIEW3D_MT_sv3_texture_map_mode"
def draw(self, context):
menu = Menu(self)
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')
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')
class MaskTextures(bpy.types.Menu):
bl_label = "Mask Texture"
bl_idname = "VIEW3D_MT_sv3_mask_texture_list"
def draw(self, context):
menu = Menu(self)
datapath = "tool_settings.image_paint.brush.mask_texture"
current_texture = eval("bpy.context.{}".format(datapath))
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
# 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 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)
class MaskMapMode(bpy.types.Menu):
bl_label = "Mask Mapping"
bl_idname = "VIEW3D_MT_sv3_mask_map_mode"
def draw(self, context):
menu = Menu(self)
path = "tool_settings.image_paint.brush.mask_texture_slot.mask_map_mode"
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')
class TextureAngleSource(bpy.types.Menu):
bl_label = "Texture Angle Source"
bl_idname = "VIEW3D_MT_sv3_texture_angle_source"
def draw(self, context):
menu = Menu(self)
if get_mode() == sculpt:
items = context.tool_settings.sculpt.brush.bl_rna.properties['texture_angle_source_random'].enum_items
path = "tool_settings.sculpt.brush.texture_angle_source_random"
elif get_mode() == vertex_paint:
items = context.tool_settings.vertex_paint.brush.bl_rna.properties['texture_angle_source_random'].enum_items
path = "tool_settings.vertex_paint.brush.texture_angle_source_random"
else:
items = context.tool_settings.image_paint.brush.bl_rna.properties['texture_angle_source_random'].enum_items
path = "tool_settings.image_paint.brush.texture_angle_source_random"
# add the menu items
for item in items:
menuprop(menu.add_item(), item[0], item[1], path,
icon='RADIOBUT_OFF',
disable=True,
disable_icon='RADIOBUT_ON')