brush menus alt/v: T42564
This commit is contained in:
parent
7f6ae93c54
commit
9007bcd107
|
@ -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)
|
|
@ -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()
|
|
@ -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()
|
|
@ -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)
|
|
@ -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)
|
|
@ -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')
|
||||
|
|
@ -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')
|
|
@ -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)
|
|
@ -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')
|
Loading…
Reference in New Issue