Merge commit 'f4128711758e92a755001e51a88d3d4f67100974' into filebrowser_redesign
This commit is contained in:
commit
8f976022ff
|
@ -21,7 +21,7 @@
|
|||
bl_info = {
|
||||
"name": "Import Images as Planes",
|
||||
"author": "Florian Meyer (tstscr), mont29, matali, Ted Schundler (SpkyElctrc)",
|
||||
"version": (3, 3, 0),
|
||||
"version": (3, 3, 1),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "File > Import > Images as Planes or Add > Mesh > Images as Planes",
|
||||
"description": "Imports images and creates planes with the appropriate aspect ratio. "
|
||||
|
@ -1021,7 +1021,16 @@ class IMPORT_IMAGE_OT_to_plane(Operator, AddObjectHelper):
|
|||
node_tree.links.new(core_shader.inputs[0], tex_image.outputs[0])
|
||||
|
||||
if self.use_transparency:
|
||||
node_tree.links.new(core_shader.inputs[18], tex_image.outputs[1])
|
||||
if self.shader == 'PRINCIPLED':
|
||||
node_tree.links.new(core_shader.inputs[18], tex_image.outputs[1])
|
||||
else:
|
||||
bsdf_transparent = node_tree.nodes.new('ShaderNodeBsdfTransparent')
|
||||
|
||||
mix_shader = node_tree.nodes.new('ShaderNodeMixShader')
|
||||
node_tree.links.new(mix_shader.inputs[0], tex_image.outputs[1])
|
||||
node_tree.links.new(mix_shader.inputs[1], bsdf_transparent.outputs[0])
|
||||
node_tree.links.new(mix_shader.inputs[2], core_shader.outputs[0])
|
||||
core_shader = mix_shader
|
||||
|
||||
node_tree.links.new(out_node.inputs[0], core_shader.outputs[0])
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
bl_info = {
|
||||
"name": "FBX format",
|
||||
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
|
||||
"version": (4, 15, 0),
|
||||
"version": (4, 15, 1),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "File > Import-Export",
|
||||
"description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
|
||||
|
|
|
@ -649,7 +649,9 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
|
|||
bl_obj = item.bl_obj
|
||||
|
||||
transform_data = item.fbx_transform_data
|
||||
rot_prev = bl_obj.rotation_euler.copy()
|
||||
rot_eul_prev = bl_obj.rotation_euler.copy()
|
||||
rot_quat_prev = bl_obj.rotation_quaternion.copy()
|
||||
|
||||
|
||||
# Pre-compute inverted local rest matrix of the bone, if relevant.
|
||||
restmat_inv = item.get_bind_matrix().inverted_safe() if item.is_bone else None
|
||||
|
@ -683,13 +685,15 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
|
|||
# Now we have a virtual matrix of transform from AnimCurves, we can insert keyframes!
|
||||
loc, rot, sca = mat.decompose()
|
||||
if rot_mode == 'QUATERNION':
|
||||
pass # nothing to do!
|
||||
if rot_quat_prev.dot(rot) < 0.0:
|
||||
rot = -rot
|
||||
rot_quat_prev = rot
|
||||
elif rot_mode == 'AXIS_ANGLE':
|
||||
vec, ang = rot.to_axis_angle()
|
||||
rot = ang, vec.x, vec.y, vec.z
|
||||
else: # Euler
|
||||
rot = rot.to_euler(rot_mode, rot_prev)
|
||||
rot_prev = rot
|
||||
rot = rot.to_euler(rot_mode, rot_eul_prev)
|
||||
rot_eul_prev = rot
|
||||
for fc, value in zip(blen_curves, chain(loc, rot, sca)):
|
||||
fc.keyframe_points.insert(frame, value, options={'NEEDED', 'FAST'}).interpolation = 'LINEAR'
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (0, 9, 53),
|
||||
"version": (0, 9, 54),
|
||||
'blender': (2, 80, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
|
|
@ -187,10 +187,11 @@ def __get_channel_groups(blender_action: bpy.types.Action, blender_object: bpy.t
|
|||
else:
|
||||
try:
|
||||
target = gltf2_blender_get.get_object_from_datapath(blender_object, object_path)
|
||||
if blender_object.type == "MESH":
|
||||
if blender_object.type == "MESH" and object_path.startswith("key_blocks"):
|
||||
shape_key = blender_object.data.shape_keys.path_resolve(object_path)
|
||||
if shape_key.mute is True:
|
||||
continue
|
||||
target = blender_object.data.shape_keys
|
||||
except ValueError as e:
|
||||
# if the object is a mesh and the action target path can not be resolved, we know that this is a morph
|
||||
# animation.
|
||||
|
|
|
@ -529,7 +529,7 @@ class RenderPovSettingsScene(PropertyGroup):
|
|||
name="Nearest Count",
|
||||
description="Number of old ambient values blended together to "
|
||||
"create a new interpolated value",
|
||||
min=1, max=20, default=5)
|
||||
min=1, max=20, default=1)
|
||||
|
||||
radio_normal: BoolProperty(
|
||||
name="Normals", description="Radiosity estimation can be affected by normals",
|
||||
|
@ -990,6 +990,11 @@ class RenderPovSettingsMaterial(PropertyGroup):
|
|||
name="Alpha",
|
||||
description="Alpha transparency of the material",
|
||||
min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3)
|
||||
|
||||
specular_alpha: FloatProperty(
|
||||
name="Specular alpha",
|
||||
description="Alpha transparency for specular areas",
|
||||
min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=1.0, precision=3)
|
||||
|
||||
ambient: FloatProperty(
|
||||
name="Ambient",
|
||||
|
@ -1409,8 +1414,8 @@ class RenderPovSettingsMaterial(PropertyGroup):
|
|||
|
||||
refraction_type: EnumProperty(
|
||||
items=[
|
||||
("1", "Fake Caustics", "use fake caustics"),
|
||||
("2", "Photons Caustics", "use photons for refractive caustics")],
|
||||
("1", "Z Transparency Fake Caustics", "use fake caustics"),
|
||||
("2", "Raytrace Photons Caustics", "use photons for refractive caustics")],
|
||||
name="Refraction Type:",
|
||||
description="use fake caustics (fast) or true photons for refractive Caustics",
|
||||
default="1")
|
||||
|
@ -1709,15 +1714,66 @@ class MaterialSubsurfaceScattering(PropertyGroup):
|
|||
name="Texture",
|
||||
description="Texture scattering blend factor",
|
||||
min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.0, precision=3)
|
||||
|
||||
|
||||
class MaterialStrandSettings(PropertyGroup):
|
||||
bl_description = "Strand settings for the material",
|
||||
|
||||
blend_distance: FloatProperty(
|
||||
name="Distance",
|
||||
description="Worldspace distance over which to blend in the surface normal",
|
||||
min=0.0, max=10.0, soft_min=0.0, soft_max=10.0, default=0.0, precision=3)
|
||||
|
||||
root_size: FloatProperty(
|
||||
name="Root",
|
||||
description="Start size of strands in pixels or Blender units",
|
||||
min=0.25, default=1.0, precision=5)
|
||||
|
||||
shape: FloatProperty(
|
||||
name="Shape",
|
||||
description="Positive values make strands rounder, negative ones make strands spiky",
|
||||
min=-0.9, max=0.9, default=0.0, precision=3)
|
||||
|
||||
size_min: FloatProperty(
|
||||
name="Minimum",
|
||||
description="Minimum size of strands in pixels",
|
||||
min=0.001, max=10.0, default=1.0, precision=3)
|
||||
|
||||
tip_size: FloatProperty(
|
||||
name="Tip",
|
||||
description="End size of strands in pixels or Blender units",
|
||||
min=0.0, default=1.0, precision=5)
|
||||
|
||||
use_blender_units: BoolProperty(
|
||||
name="Blender Units",
|
||||
description="Use Blender units for widths instead of pixels",
|
||||
default=False)
|
||||
|
||||
use_surface_diffuse: BoolProperty(
|
||||
name="Surface diffuse",
|
||||
description="Make diffuse shading more similar to shading the surface",
|
||||
default=False)
|
||||
|
||||
use_tangent_shading: BoolProperty(
|
||||
name="Tangent Shading",
|
||||
description="Use direction of strands as normal for tangent-shading",
|
||||
default=True)
|
||||
|
||||
uv_layer: StringProperty(
|
||||
name="UV Layer",
|
||||
#icon="GROUP_UVS",
|
||||
description="Name of UV map to override",
|
||||
default="")
|
||||
|
||||
width_fade: FloatProperty(
|
||||
name="Width Fade",
|
||||
description="Transparency along the width of the strand",
|
||||
min=0.0, max=2.0, default=0.0, precision=3)
|
||||
|
||||
|
||||
# halo
|
||||
|
||||
# Halo settings for the material
|
||||
# Type: MaterialHalo, (readonly, never None)
|
||||
# alpha¶
|
||||
|
||||
# Alpha transparency of the material
|
||||
# Type: float in [0, 1], default 0.0
|
||||
|
||||
# ambient
|
||||
|
||||
|
@ -1912,10 +1968,6 @@ class MaterialSubsurfaceScattering(PropertyGroup):
|
|||
# Shadow raytracing bias to prevent terminator problems on shadow boundary
|
||||
# Type: float in [0, 0.25], default 0.0
|
||||
|
||||
# specular_alpha
|
||||
|
||||
# Alpha transparency for specular areas
|
||||
# Type: float in [0, 1], default 0.0
|
||||
|
||||
# specular_color
|
||||
|
||||
|
@ -4298,6 +4350,7 @@ classes = (
|
|||
MaterialRaytraceTransparency,
|
||||
MaterialRaytraceMirror,
|
||||
MaterialSubsurfaceScattering,
|
||||
MaterialStrandSettings,
|
||||
RenderPovSettingsObject,
|
||||
RenderPovSettingsScene,
|
||||
RenderPovSettingsText,
|
||||
|
@ -4337,6 +4390,7 @@ def register():
|
|||
bpy.types.Material.pov_raytrace_transparency = PointerProperty(type=MaterialRaytraceTransparency)
|
||||
bpy.types.Material.pov = PointerProperty(type=RenderPovSettingsMaterial)
|
||||
bpy.types.Material.pov_subsurface_scattering = PointerProperty(type=MaterialSubsurfaceScattering)
|
||||
bpy.types.Material.strand = PointerProperty(type= MaterialStrandSettings)
|
||||
bpy.types.Material.pov_raytrace_mirror = PointerProperty(type=MaterialRaytraceMirror)
|
||||
bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture)
|
||||
bpy.types.Object.pov = PointerProperty(type=RenderPovSettingsObject)
|
||||
|
@ -4353,6 +4407,7 @@ def unregister():
|
|||
del bpy.types.Scene.pov
|
||||
del bpy.types.Material.pov
|
||||
del bpy.types.Material.pov_subsurface_scattering
|
||||
del bpy.types.Material.strand
|
||||
del bpy.types.Material.pov_raytrace_mirror
|
||||
del bpy.types.Material.pov_raytrace_transparency
|
||||
#del bpy.types.Modifier.pov
|
||||
|
|
|
@ -1697,10 +1697,10 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
material = None
|
||||
if material:
|
||||
diffuse_color = material.diffuse_color
|
||||
trans = 1.0 - material.alpha
|
||||
trans = 1.0 - material.pov.alpha
|
||||
if material.use_transparency and material.transparency_method == 'RAYTRACE':
|
||||
povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
|
||||
trans = (1.0 - material.alpha) - povFilter
|
||||
trans = (1.0 - material.pov.alpha) - povFilter
|
||||
else:
|
||||
povFilter = 0.0
|
||||
material_finish = materialNames[material.name]
|
||||
|
@ -1762,10 +1762,10 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
|
||||
if material:
|
||||
diffuse_color = material.diffuse_color
|
||||
trans = 1.0 - material.alpha
|
||||
trans = 1.0 - material.pov.alpha
|
||||
if material.use_transparency and material.transparency_method == 'RAYTRACE':
|
||||
povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
|
||||
trans = (1.0 - material.alpha) - povFilter
|
||||
trans = (1.0 - material.pov.alpha) - povFilter
|
||||
else:
|
||||
povFilter = 0.0
|
||||
|
||||
|
@ -2085,9 +2085,9 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
renderEmitter = True
|
||||
if hasattr(ob, 'particle_systems'):
|
||||
renderEmitter = False
|
||||
if ob.show_instancer_for_render:
|
||||
renderEmitter = True
|
||||
for pSys in ob.particle_systems:
|
||||
if pSys.settings.use_render_emitter:
|
||||
renderEmitter = True
|
||||
for mod in [m for m in ob.modifiers if (m is not None) and (m.type == 'PARTICLE_SYSTEM')]:
|
||||
if (pSys.settings.render_type == 'PATH') and mod.show_render and (pSys.name == mod.particle_system.name):
|
||||
tstart = time.time()
|
||||
|
@ -2113,11 +2113,16 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
strandEnd = 0.01
|
||||
strandShape = 0.0
|
||||
# Set the number of particles to render count rather than 3d view display
|
||||
pSys.set_resolution(scene, ob, 'RENDER')
|
||||
#pSys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
|
||||
# When you render, the entire dependency graph will be
|
||||
# evaluated at render resolution, including the particles.
|
||||
# In the viewport it will be at viewport resolution.
|
||||
# So there is no need fo render engines to use this function anymore,
|
||||
# it's automatic now.
|
||||
steps = pSys.settings.display_step
|
||||
steps = 3 ** steps # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
|
||||
|
||||
totalNumberOfHairs = ( len(pSys.particles) + len(pSys.child_particles) )
|
||||
totalNumberOfHairs = ( pSys.settings.count + pSys.settings.rendered_child_count )
|
||||
#hairCounter = 0
|
||||
file.write('#declare HairArray = array[%i] {\n' % totalNumberOfHairs)
|
||||
for pindex in range(0, totalNumberOfHairs):
|
||||
|
@ -2135,7 +2140,7 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
file.write('linear_spline ')
|
||||
file.write('%i,\n' % (steps))
|
||||
#changing world coordinates to object local coordinates by multiplying with inverted matrix
|
||||
initCo = ob.matrix_world.inverted()*(pSys.co_hair(ob, pindex, 0))
|
||||
initCo = ob.matrix_world.inverted() @ (pSys.co_hair(ob, particle_no = pindex, step = 0))
|
||||
if ob.material_slots[pSys.settings.material - 1].material and ob.active_material is not None:
|
||||
pmaterial = ob.material_slots[pSys.settings.material-1].material
|
||||
for th in pmaterial.texture_slots:
|
||||
|
@ -2159,7 +2164,7 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
#only overwrite variable for each competing texture for now
|
||||
initColor=th.texture.evaluate((initCo[0],initCo[1],initCo[2]))
|
||||
for step in range(0, steps):
|
||||
co = ob.matrix_world.inverted()*(pSys.co_hair(ob, pindex, step))
|
||||
co = ob.matrix_world.inverted() @ (pSys.co_hair(ob, particle_no = pindex, step = step))
|
||||
#for controlPoint in particle.hair_keys:
|
||||
if pSys.settings.clump_factor != 0:
|
||||
hDiameter = pSys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
|
||||
|
@ -2256,8 +2261,12 @@ def write_pov(filename, scene=None, info_callback=None):
|
|||
print('Number of tufts (particle systems)', len(ob.particle_systems))
|
||||
|
||||
# Set back the displayed number of particles to preview count
|
||||
pSys.set_resolution(scene, ob, 'PREVIEW')
|
||||
|
||||
# pSys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
|
||||
# When you render, the entire dependency graph will be
|
||||
# evaluated at render resolution, including the particles.
|
||||
# In the viewport it will be at viewport resolution.
|
||||
# So there is no need fo render engines to use this function anymore,
|
||||
# it's automatic now.
|
||||
if renderEmitter == False:
|
||||
continue #don't render mesh, skip to next object.
|
||||
|
||||
|
|
|
@ -745,7 +745,7 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
|
|||
string_strip_hyphen, safety, col, os, preview_dir, unpacked_images):
|
||||
material_finish = materialNames[mater.name]
|
||||
if mater.pov.use_transparency:
|
||||
trans = 1.0 - mater.alpha
|
||||
trans = 1.0 - mater.pov.alpha
|
||||
else:
|
||||
trans = 0.0
|
||||
if ((mater.specular_color.s == 0.0) or (mater.pov.diffuse_shader == 'MINNAERT')):
|
||||
|
@ -754,9 +754,9 @@ def writeTextureInfluence(mater, materialNames, LocalMaterialNames, path_image,
|
|||
else:
|
||||
colored_specular_found = True
|
||||
|
||||
if mater.pov.use_transparency and mater.transparency_method == 'RAYTRACE':
|
||||
povFilter = mater.raytrace_transparency.filter * (1.0 - mater.alpha)
|
||||
trans = (1.0 - mater.alpha) - povFilter
|
||||
if mater.pov.use_transparency and mater.pov.transparency_method == 'RAYTRACE':
|
||||
povFilter = mater.pov_raytrace_transparency.filter * (1.0 - mater.pov.alpha)
|
||||
trans = (1.0 - mater.pov.alpha) - povFilter
|
||||
else:
|
||||
povFilter = 0.0
|
||||
|
||||
|
|
|
@ -265,6 +265,11 @@ def check_material(mat):
|
|||
return True
|
||||
return False
|
||||
|
||||
def simple_material(mat):
|
||||
if (mat is not None) and (not mat.use_nodes):
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_add_mesh_extra_objects():
|
||||
if "add_mesh_extra_objects" in bpy.context.preferences.addons.keys():
|
||||
return True
|
||||
|
@ -1385,7 +1390,7 @@ class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
|
|||
sub.prop(sss, "back")
|
||||
col.separator()
|
||||
col.prop(sss, "error_threshold", text="Error")
|
||||
|
||||
|
||||
class MATERIAL_PT_povray_activate_node(MaterialButtonsPanel, Panel):
|
||||
bl_label = "Activate Node Settings"
|
||||
bl_context = "material"
|
||||
|
@ -1517,6 +1522,70 @@ class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
|
|||
sub.prop(raym, "gloss_threshold", text="Threshold")
|
||||
sub.prop(raym, "gloss_samples", text="Samples")
|
||||
sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
|
||||
|
||||
class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
|
||||
bl_label = "Transparency"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return check_material(mat) and (mat.pov.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material
|
||||
|
||||
if simple_material(mat):
|
||||
self.layout.prop(mat.pov, "use_transparency", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
base_mat = context.material
|
||||
mat = context.material#FORMERLY active_node_mat(context.material)
|
||||
rayt = mat.pov_raytrace_transparency
|
||||
|
||||
if simple_material(base_mat):
|
||||
row = layout.row()
|
||||
row.active = mat.pov.use_transparency
|
||||
row.prop(mat.pov, "transparency_method", expand=True)
|
||||
|
||||
split = layout.split()
|
||||
split.active = base_mat.pov.use_transparency
|
||||
|
||||
col = split.column()
|
||||
col.prop(mat.pov, "alpha")
|
||||
row = col.row()
|
||||
row.active = (base_mat.pov.transparency_method != 'MASK') and (not mat.pov.use_shadeless)
|
||||
row.prop(mat.pov, "specular_alpha", text="Specular")
|
||||
|
||||
col = split.column()
|
||||
col.active = (not mat.pov.use_shadeless)
|
||||
col.prop(rayt, "fresnel")
|
||||
sub = col.column()
|
||||
sub.active = (rayt.fresnel > 0.0)
|
||||
sub.prop(rayt, "fresnel_factor", text="Blend")
|
||||
|
||||
if base_mat.pov.transparency_method == 'RAYTRACE':
|
||||
layout.separator()
|
||||
split = layout.split()
|
||||
split.active = base_mat.pov.use_transparency
|
||||
|
||||
col = split.column()
|
||||
col.prop(rayt, "ior")
|
||||
col.prop(rayt, "filter")
|
||||
col.prop(rayt, "falloff")
|
||||
col.prop(rayt, "depth_max")
|
||||
col.prop(rayt, "depth")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Gloss:")
|
||||
col.prop(rayt, "gloss_factor", text="Amount")
|
||||
sub = col.column()
|
||||
sub.active = rayt.gloss_factor < 1.0
|
||||
sub.prop(rayt, "gloss_threshold", text="Threshold")
|
||||
sub.prop(rayt, "gloss_samples", text="Samples")
|
||||
|
||||
class MATERIAL_PT_povray_reflection(MaterialButtonsPanel, Panel):
|
||||
bl_label = "POV-Ray Reflection"
|
||||
|
@ -1646,7 +1715,52 @@ class MATERIAL_PT_povray_caustics(MaterialButtonsPanel, Panel):
|
|||
col.label(text="Caustics override is on, ")
|
||||
col.label(text="but you didn't chose any !")
|
||||
|
||||
class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
|
||||
bl_label = "Strand"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return mat and (mat.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material # don't use node material
|
||||
tan = mat.strand
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
sub.label(text="Size:")
|
||||
sub.prop(tan, "root_size", text="Root")
|
||||
sub.prop(tan, "tip_size", text="Tip")
|
||||
sub.prop(tan, "size_min", text="Minimum")
|
||||
sub.prop(tan, "use_blender_units")
|
||||
sub = col.column()
|
||||
sub.active = (not mat.pov.use_shadeless)
|
||||
sub.prop(tan, "use_tangent_shading")
|
||||
col.prop(tan, "shape")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Shading:")
|
||||
col.prop(tan, "width_fade")
|
||||
ob = context.object
|
||||
if ob and ob.type == 'MESH':
|
||||
col.prop_search(tan, "uv_layer", ob.data, "uv_textures", text="")
|
||||
else:
|
||||
col.prop(tan, "uv_layer", text="")
|
||||
col.separator()
|
||||
sub = col.column()
|
||||
sub.active = (not mat.pov.use_shadeless)
|
||||
sub.label("Surface diffuse:")
|
||||
sub = col.column()
|
||||
sub.prop(tan, "blend_distance", text="Distance")
|
||||
|
||||
class MATERIAL_PT_povray_replacement_text(MaterialButtonsPanel, Panel):
|
||||
bl_label = "Custom POV Code"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
@ -3085,9 +3199,11 @@ classes = (
|
|||
MATERIAL_PT_POV_sss,
|
||||
MATERIAL_MT_POV_sss_presets,
|
||||
AddPresetSSS,
|
||||
MATERIAL_PT_strand,
|
||||
MATERIAL_PT_povray_activate_node,
|
||||
MATERIAL_PT_povray_active_node,
|
||||
MATERIAL_PT_POV_mirror,
|
||||
MATERIAL_PT_POV_transp,
|
||||
MATERIAL_PT_povray_reflection,
|
||||
#MATERIAL_PT_POV_interior,
|
||||
MATERIAL_PT_povray_fade_color,
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
# ##### 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": "Dynamic Brush Menus",
|
||||
"description": "Fast access to brushes & tools in Sculpt and Paint Modes",
|
||||
"author": "Ryan Inch (Imaginer)",
|
||||
"version": (1, 1, 7),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "Spacebar in Sculpt/Paint Modes",
|
||||
"warning": '',
|
||||
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
|
||||
"Scripts/3D_interaction/Advanced_UI_Menus",
|
||||
"category": "3D View"}
|
||||
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(utils_core)
|
||||
importlib.reload(brush_menu)
|
||||
importlib.reload(brushes)
|
||||
importlib.reload(curve_menu)
|
||||
importlib.reload(dyntopo_menu)
|
||||
importlib.reload(stroke_menu)
|
||||
importlib.reload(symmetry_menu)
|
||||
importlib.reload(texture_menu)
|
||||
else:
|
||||
from . import utils_core
|
||||
from . import brush_menu
|
||||
from . import brushes
|
||||
from . import curve_menu
|
||||
from . import dyntopo_menu
|
||||
from . import stroke_menu
|
||||
from . import symmetry_menu
|
||||
from . import texture_menu
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.types import AddonPreferences
|
||||
from bpy.props import (
|
||||
EnumProperty,
|
||||
IntProperty,
|
||||
)
|
||||
|
||||
|
||||
addon_files = (
|
||||
brush_menu,
|
||||
brushes,
|
||||
curve_menu,
|
||||
dyntopo_menu,
|
||||
stroke_menu,
|
||||
symmetry_menu,
|
||||
texture_menu,
|
||||
)
|
||||
|
||||
|
||||
|
||||
class VIEW3D_MT_Brushes_Pref(AddonPreferences):
|
||||
bl_idname = __name__
|
||||
|
||||
column_set: IntProperty(
|
||||
name="Number of Columns",
|
||||
description="Number of columns used for the brushes menu",
|
||||
default=2,
|
||||
min=1,
|
||||
max=10
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(self, "column_set", slider=True)
|
||||
|
||||
|
||||
# New hotkeys and registration
|
||||
|
||||
addon_keymaps = []
|
||||
|
||||
|
||||
def register():
|
||||
# register all files
|
||||
for addon_file in addon_files:
|
||||
addon_file.register()
|
||||
|
||||
# set the add-on name variable to access the preferences
|
||||
utils_core.get_addon_name = __name__
|
||||
|
||||
# register preferences
|
||||
bpy.utils.register_class(VIEW3D_MT_Brushes_Pref)
|
||||
|
||||
# register hotkeys
|
||||
wm = bpy.context.window_manager
|
||||
modes = ('Sculpt', 'Vertex Paint', 'Weight Paint', 'Image Paint', 'Particle')
|
||||
|
||||
for mode in modes:
|
||||
km = wm.keyconfigs.addon.keymaps.new(name=mode)
|
||||
kmi = km.keymap_items.new('wm.call_menu', 'SPACE', 'PRESS')
|
||||
kmi.properties.name = "VIEW3D_MT_sv3_brush_options"
|
||||
addon_keymaps.append((km, kmi))
|
||||
|
||||
|
||||
def unregister():
|
||||
# unregister all files
|
||||
for addon_file in addon_files:
|
||||
addon_file.unregister()
|
||||
|
||||
# unregister preferences
|
||||
bpy.utils.unregister_class(VIEW3D_MT_Brushes_Pref)
|
||||
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -0,0 +1,630 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Menu,
|
||||
)
|
||||
from bpy.props import BoolProperty
|
||||
from . import utils_core
|
||||
from . import brushes
|
||||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
|
||||
class BrushOptionsMenu(Menu):
|
||||
bl_label = "Brush Options"
|
||||
bl_idname = "VIEW3D_MT_sv3_brush_options"
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'SCULPT', 'VERTEX_PAINT',
|
||||
'WEIGHT_PAINT', 'TEXTURE_PAINT',
|
||||
'PARTICLE_EDIT'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
mode = utils_core.get_mode()
|
||||
layout = self.layout
|
||||
|
||||
if mode == 'SCULPT':
|
||||
self.sculpt(mode, layout, context)
|
||||
|
||||
elif mode in ('VERTEX_PAINT', 'WEIGHT_PAINT'):
|
||||
self.vw_paint(mode, layout, context)
|
||||
|
||||
elif mode == 'TEXTURE_PAINT':
|
||||
self.texpaint(mode, layout, context)
|
||||
|
||||
else:
|
||||
self.particle(layout, context)
|
||||
|
||||
def sculpt(self, mode, layout, context):
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
icons = brushes.brush_icon[mode][has_brush.sculpt_tool] if \
|
||||
has_brush else "BRUSH_DATA"
|
||||
layout.operator("wm.toolbar", text="Tools", icon='TOOL_SETTINGS')
|
||||
layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
|
||||
icon=icons)
|
||||
|
||||
layout.row().menu(BrushRadiusMenu.bl_idname)
|
||||
|
||||
if has_brush:
|
||||
# if the active brush is unlinked these menus don't do anything
|
||||
layout.row().menu(BrushStrengthMenu.bl_idname)
|
||||
layout.row().menu(BrushAutosmoothMenu.bl_idname)
|
||||
layout.row().menu(BrushModeMenu.bl_idname)
|
||||
layout.row().menu("VIEW3D_MT_sv3_texture_menu")
|
||||
layout.row().menu("VIEW3D_MT_sv3_stroke_options")
|
||||
layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")
|
||||
|
||||
layout.row().menu("VIEW3D_MT_sv3_dyntopo")
|
||||
layout.row().menu("VIEW3D_MT_sv3_master_symmetry_menu")
|
||||
|
||||
def vw_paint(self, mode, layout, context):
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
icons = brushes.brush_icon[mode][has_brush.vertex_tool] if \
|
||||
has_brush else "BRUSH_DATA"
|
||||
|
||||
layout.operator("wm.toolbar", text="Tools", icon='TOOL_SETTINGS')
|
||||
|
||||
if mode == 'VERTEX_PAINT':
|
||||
layout.row().operator(ColorPickerPopup.bl_idname, icon="COLOR")
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
|
||||
icon=icons)
|
||||
|
||||
if mode == 'VERTEX_PAINT':
|
||||
layout.row().menu(BrushRadiusMenu.bl_idname)
|
||||
|
||||
if has_brush:
|
||||
# if the active brush is unlinked these menus don't do anything
|
||||
layout.row().menu(BrushStrengthMenu.bl_idname)
|
||||
layout.row().menu(BrushModeMenu.bl_idname)
|
||||
layout.row().menu("VIEW3D_MT_sv3_texture_menu")
|
||||
layout.row().menu("VIEW3D_MT_sv3_stroke_options")
|
||||
layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")
|
||||
|
||||
if mode == 'WEIGHT_PAINT':
|
||||
layout.row().menu(BrushWeightMenu.bl_idname)
|
||||
layout.row().menu(BrushRadiusMenu.bl_idname)
|
||||
|
||||
if has_brush:
|
||||
# if the active brush is unlinked these menus don't do anything
|
||||
layout.row().menu(BrushStrengthMenu.bl_idname)
|
||||
layout.row().menu(BrushModeMenu.bl_idname)
|
||||
layout.row().menu("VIEW3D_MT_sv3_stroke_options")
|
||||
layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")
|
||||
|
||||
def texpaint(self, mode, layout, context):
|
||||
toolsettings = context.tool_settings.image_paint
|
||||
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
icons = brushes.brush_icon[mode][has_brush.image_tool] if \
|
||||
has_brush else "BRUSH_DATA"
|
||||
|
||||
if context.image_paint_object and not toolsettings.detect_data():
|
||||
if toolsettings.missing_uvs or toolsettings.missing_materials or \
|
||||
toolsettings.missing_texture:
|
||||
layout.row().label(text="Missing Data", icon='ERROR')
|
||||
layout.row().operator_menu_enum("paint.add_texture_paint_slot", \
|
||||
"type", \
|
||||
icon='ADD', \
|
||||
text="Add Texture Paint Slot")
|
||||
|
||||
return
|
||||
|
||||
elif toolsettings.missing_stencil:
|
||||
layout.row().label(text="Missing Data", icon='ERROR')
|
||||
layout.row().label(text="See Mask Properties", icon='FORWARD')
|
||||
layout.row().separator()
|
||||
layout.operator("wm.toolbar", text="Tools", icon='TOOL_SETTINGS')
|
||||
layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
|
||||
icon=icons)
|
||||
|
||||
return
|
||||
|
||||
else:
|
||||
layout.row().label(text="Missing Data", icon="INFO")
|
||||
|
||||
else:
|
||||
layout.operator("wm.toolbar", text="Tools", icon='TOOL_SETTINGS')
|
||||
|
||||
if has_brush and has_brush.image_tool in {'DRAW', 'FILL'} and \
|
||||
has_brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
|
||||
layout.row().operator(ColorPickerPopup.bl_idname, icon="COLOR")
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
|
||||
icon=icons)
|
||||
|
||||
if has_brush:
|
||||
# if the active brush is unlinked these menus don't do anything
|
||||
if has_brush and has_brush.image_tool in {'MASK'}:
|
||||
layout.row().menu(BrushWeightMenu.bl_idname, text="Mask Value")
|
||||
|
||||
if has_brush and has_brush.image_tool not in {'FILL'}:
|
||||
layout.row().menu(BrushRadiusMenu.bl_idname)
|
||||
|
||||
layout.row().menu(BrushStrengthMenu.bl_idname)
|
||||
|
||||
if has_brush and has_brush.image_tool in {'DRAW'}:
|
||||
layout.row().menu(BrushModeMenu.bl_idname)
|
||||
|
||||
layout.row().menu("VIEW3D_MT_sv3_texture_menu")
|
||||
layout.row().menu("VIEW3D_MT_sv3_stroke_options")
|
||||
layout.row().menu("VIEW3D_MT_sv3_brush_curve_menu")
|
||||
|
||||
layout.row().menu("VIEW3D_MT_sv3_master_symmetry_menu")
|
||||
|
||||
def particle(self, layout, context):
|
||||
particle_edit = context.tool_settings.particle_edit
|
||||
|
||||
layout.operator("wm.toolbar", text="Tools", icon='TOOL_SETTINGS')
|
||||
|
||||
layout.row().menu("VIEW3D_MT_sv3_brushes_menu",
|
||||
icon="BRUSH_DATA")
|
||||
layout.row().menu(BrushRadiusMenu.bl_idname)
|
||||
|
||||
if particle_edit.tool != 'ADD':
|
||||
layout.row().menu(BrushStrengthMenu.bl_idname)
|
||||
else:
|
||||
layout.row().menu(ParticleCountMenu.bl_idname)
|
||||
layout.row().separator()
|
||||
layout.row().prop(particle_edit, "use_default_interpolate", toggle=True)
|
||||
|
||||
layout.row().prop(particle_edit.brush, "steps", slider=True)
|
||||
layout.row().prop(particle_edit, "default_key_count", slider=True)
|
||||
|
||||
if particle_edit.tool == 'LENGTH':
|
||||
layout.row().separator()
|
||||
layout.row().menu(ParticleLengthMenu.bl_idname)
|
||||
|
||||
if particle_edit.tool == 'PUFF':
|
||||
layout.row().separator()
|
||||
layout.row().menu(ParticlePuffMenu.bl_idname)
|
||||
layout.row().prop(particle_edit.brush, "use_puff_volume", toggle=True)
|
||||
|
||||
|
||||
class BrushRadiusMenu(Menu):
|
||||
bl_label = "Radius"
|
||||
bl_idname = "VIEW3D_MT_sv3_brush_radius_menu"
|
||||
bl_description = "Change the size of the brushes"
|
||||
|
||||
def init(self):
|
||||
if utils_core.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 = bpy.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 = bpy.context.tool_settings.unified_paint_settings
|
||||
|
||||
return settings, datapath, proppath
|
||||
|
||||
def draw(self, context):
|
||||
settings, datapath, proppath = self.init()
|
||||
layout = self.layout
|
||||
|
||||
# add the top slider
|
||||
layout.row().prop(proppath, "size", slider=True)
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for i in range(len(settings)):
|
||||
utils_core.menuprop(
|
||||
layout.row(), settings[i][0], settings[i][1],
|
||||
datapath, icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
class BrushStrengthMenu(Menu):
|
||||
bl_label = "Strength"
|
||||
bl_idname = "VIEW3D_MT_sv3_brush_strength_menu"
|
||||
|
||||
def init(self):
|
||||
mode = utils_core.get_mode()
|
||||
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))
|
||||
|
||||
proppath = utils_core.get_brush_link(bpy.context, types="brush")
|
||||
|
||||
if mode == 'SCULPT':
|
||||
datapath = "tool_settings.sculpt.brush.strength"
|
||||
|
||||
elif mode == 'VERTEX_PAINT':
|
||||
datapath = "tool_settings.vertex_paint.brush.strength"
|
||||
|
||||
elif mode == 'WEIGHT_PAINT':
|
||||
datapath = "tool_settings.weight_paint.brush.strength"
|
||||
|
||||
elif mode == 'TEXTURE_PAINT':
|
||||
datapath = "tool_settings.image_paint.brush.strength"
|
||||
|
||||
else:
|
||||
datapath = "tool_settings.particle_edit.brush.strength"
|
||||
proppath = bpy.context.tool_settings.particle_edit.brush
|
||||
|
||||
return settings, datapath, proppath
|
||||
|
||||
def draw(self, context):
|
||||
settings, datapath, proppath = self.init()
|
||||
layout = self.layout
|
||||
|
||||
# add the top slider
|
||||
if proppath:
|
||||
layout.row().prop(proppath, "strength", slider=True)
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for i in range(len(settings)):
|
||||
utils_core.menuprop(
|
||||
layout.row(), settings[i][0], settings[i][1],
|
||||
datapath, icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
|
||||
class BrushModeMenu(Menu):
|
||||
bl_label = "Brush Mode"
|
||||
bl_idname = "VIEW3D_MT_sv3_brush_mode_menu"
|
||||
|
||||
def init(self):
|
||||
mode = utils_core.get_mode()
|
||||
has_brush = utils_core.get_brush_link(bpy.context, types="brush")
|
||||
|
||||
if mode == 'SCULPT':
|
||||
enum = has_brush.bl_rna.properties['sculpt_plane'].enum_items if \
|
||||
has_brush else None
|
||||
path = "tool_settings.sculpt.brush.sculpt_plane"
|
||||
|
||||
elif mode == 'VERTEX_PAINT':
|
||||
enum = has_brush.bl_rna.properties['blend'].enum_items if \
|
||||
has_brush else None
|
||||
path = "tool_settings.vertex_paint.brush.blend"
|
||||
|
||||
elif mode == 'WEIGHT_PAINT':
|
||||
enum = has_brush.bl_rna.properties['blend'].enum_items if \
|
||||
has_brush else None
|
||||
path = "tool_settings.weight_paint.brush.blend"
|
||||
|
||||
elif mode == 'TEXTURE_PAINT':
|
||||
enum = has_brush.bl_rna.properties['blend'].enum_items if \
|
||||
has_brush else None
|
||||
path = "tool_settings.image_paint.brush.blend"
|
||||
|
||||
else:
|
||||
enum = None
|
||||
path = ""
|
||||
|
||||
return enum, path
|
||||
|
||||
def draw(self, context):
|
||||
enum, path = self.init()
|
||||
layout = self.layout
|
||||
colum_n = utils_core.addon_settings()
|
||||
|
||||
layout.row().label(text="Brush Mode")
|
||||
layout.row().separator()
|
||||
|
||||
if enum:
|
||||
if utils_core.get_mode() != 'SCULPT':
|
||||
column_flow = layout.column_flow(columns=colum_n)
|
||||
|
||||
# add all the brush modes to the menu
|
||||
for brush in enum:
|
||||
utils_core.menuprop(
|
||||
column_flow.row(), brush.name,
|
||||
brush.identifier, path, icon='RADIOBUT_OFF',
|
||||
disable=True, disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
# add all the brush modes to the menu
|
||||
for brush in enum:
|
||||
utils_core.menuprop(
|
||||
layout.row(), brush.name,
|
||||
brush.identifier, path, icon='RADIOBUT_OFF',
|
||||
disable=True, disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
|
||||
class BrushAutosmoothMenu(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()
|
||||
layout = self.layout
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
|
||||
if has_brush:
|
||||
# add the top slider
|
||||
layout.row().prop(has_brush, "auto_smooth_factor", slider=True)
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for i in range(len(settings)):
|
||||
utils_core.menuprop(
|
||||
layout.row(), settings[i][0], settings[i][1],
|
||||
"tool_settings.sculpt.brush.auto_smooth_factor",
|
||||
icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No Smooth options available", icon="INFO")
|
||||
|
||||
|
||||
class BrushWeightMenu(Menu):
|
||||
bl_label = "Weight"
|
||||
bl_idname = "VIEW3D_MT_sv3_brush_weight_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))
|
||||
|
||||
if utils_core.get_mode() == 'WEIGHT_PAINT':
|
||||
brush = bpy.context.tool_settings.unified_paint_settings
|
||||
brushstr = "tool_settings.unified_paint_settings.weight"
|
||||
name = "Weight"
|
||||
|
||||
else:
|
||||
brush = bpy.context.tool_settings.image_paint.brush
|
||||
brushstr = "tool_settings.image_paint.brush.weight"
|
||||
name = "Mask Value"
|
||||
|
||||
return settings, brush, brushstr, name
|
||||
|
||||
def draw(self, context):
|
||||
settings, brush, brushstr, name = self.init()
|
||||
layout = self.layout
|
||||
|
||||
if brush:
|
||||
# add the top slider
|
||||
layout.row().prop(brush, "weight", text=name, slider=True)
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for i in range(len(settings)):
|
||||
utils_core.menuprop(
|
||||
layout.row(), settings[i][0], settings[i][1],
|
||||
brushstr,
|
||||
icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brush available", icon="INFO")
|
||||
|
||||
|
||||
class ParticleCountMenu(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()
|
||||
layout = self.layout
|
||||
|
||||
# add the top slider
|
||||
layout.row().prop(context.tool_settings.particle_edit.brush,
|
||||
"count", slider=True)
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for i in range(len(settings)):
|
||||
utils_core.menuprop(
|
||||
layout.row(), settings[i][0], settings[i][1],
|
||||
"tool_settings.particle_edit.brush.count",
|
||||
icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
class ParticleLengthMenu(Menu):
|
||||
bl_label = "Length Mode"
|
||||
bl_idname = "VIEW3D_MT_sv3_particle_length_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
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:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
class ParticlePuffMenu(Menu):
|
||||
bl_label = "Puff Mode"
|
||||
bl_idname = "VIEW3D_MT_sv3_particle_puff_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
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:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
class FlipColorsAll(Operator):
|
||||
"""Switch between Foreground and Background colors"""
|
||||
bl_label = "Flip Colors"
|
||||
bl_idname = "view3d.sv3_flip_colors_all"
|
||||
bl_description = "Switch between Foreground and Background colors"
|
||||
|
||||
is_tex: BoolProperty(
|
||||
default=False,
|
||||
options={'HIDDEN'}
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
if self.is_tex is False:
|
||||
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
|
||||
else:
|
||||
color = context.tool_settings.image_paint.brush.color
|
||||
secondary_color = context.tool_settings.image_paint.brush.secondary_color
|
||||
|
||||
orig_prim = color.hsv
|
||||
orig_sec = secondary_color.hsv
|
||||
|
||||
color.hsv = orig_sec
|
||||
secondary_color.hsv = orig_prim
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
except Exception as e:
|
||||
utils_core.error_handlers(self, "view3d.sv3_flip_colors_all", e,
|
||||
"Flip Colors could not be completed")
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
class ColorPickerPopup(Operator):
|
||||
"""Open Color Picker"""
|
||||
bl_label = "Color"
|
||||
bl_idname = "view3d.sv3_color_picker_popup"
|
||||
bl_description = "Open Color Picker"
|
||||
bl_options = {'REGISTER'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'VERTEX_PAINT',
|
||||
'TEXTURE_PAINT'
|
||||
)
|
||||
|
||||
def check(self, context):
|
||||
return True
|
||||
|
||||
def init(self):
|
||||
if utils_core.get_mode() == 'TEXTURE_PAINT':
|
||||
settings = bpy.context.tool_settings.image_paint
|
||||
brush = getattr(settings, "brush", None)
|
||||
else:
|
||||
settings = bpy.context.tool_settings.vertex_paint
|
||||
brush = settings.brush
|
||||
brush = getattr(settings, "brush", None)
|
||||
|
||||
return settings, brush
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings, brush = self.init()
|
||||
|
||||
|
||||
if brush:
|
||||
layout.row().template_color_picker(brush, "color", value_slider=True)
|
||||
prim_sec_row = layout.row(align=True)
|
||||
prim_sec_row.prop(brush, "color", text="")
|
||||
prim_sec_row.prop(brush, "secondary_color", text="")
|
||||
|
||||
if utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
prim_sec_row.operator(
|
||||
FlipColorsAll.bl_idname,
|
||||
icon='FILE_REFRESH', text=""
|
||||
).is_tex = False
|
||||
else:
|
||||
prim_sec_row.operator(
|
||||
FlipColorsAll.bl_idname,
|
||||
icon='FILE_REFRESH', text=""
|
||||
).is_tex = True
|
||||
|
||||
if settings.palette:
|
||||
layout.column().template_palette(settings, "palette", color=True)
|
||||
|
||||
layout.row().template_ID(settings, "palette", new="palette.new")
|
||||
else:
|
||||
layout.row().label(text="No brushes currently available", icon="INFO")
|
||||
|
||||
return
|
||||
|
||||
def execute(self, context):
|
||||
return context.window_manager.invoke_popup(self, width=180)
|
||||
|
||||
|
||||
classes = (
|
||||
BrushOptionsMenu,
|
||||
BrushRadiusMenu,
|
||||
BrushStrengthMenu,
|
||||
BrushModeMenu,
|
||||
BrushAutosmoothMenu,
|
||||
BrushWeightMenu,
|
||||
ParticleCountMenu,
|
||||
ParticleLengthMenu,
|
||||
ParticlePuffMenu,
|
||||
FlipColorsAll,
|
||||
ColorPickerPopup
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,163 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import Menu
|
||||
from . import utils_core
|
||||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
|
||||
# Particle Tools
|
||||
|
||||
particle_tools = (
|
||||
("Comb", 'COMB'),
|
||||
("Smooth", 'SMOOTH'),
|
||||
("Add", 'ADD'),
|
||||
("Length", 'LENGTH'),
|
||||
("Puff", 'PUFF'),
|
||||
("Cut", 'CUT'),
|
||||
("Weight", 'WEIGHT')
|
||||
)
|
||||
|
||||
# Brush Datapaths
|
||||
|
||||
brush_datapath = {
|
||||
'SCULPT': "tool_settings.sculpt.brush",
|
||||
'VERTEX_PAINT': "tool_settings.vertex_paint.brush",
|
||||
'WEIGHT_PAINT': "tool_settings.weight_paint.brush",
|
||||
'TEXTURE_PAINT': "tool_settings.image_paint.brush",
|
||||
'PARTICLE_EDIT': "tool_settings.particle_edit.tool"
|
||||
}
|
||||
|
||||
# Brush Icons
|
||||
|
||||
brush_icon = {
|
||||
'SCULPT': {
|
||||
"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_DATA',
|
||||
"SMOOTH": 'BRUSH_SMOOTH',
|
||||
"SNAKE_HOOK": 'BRUSH_SNAKE_HOOK',
|
||||
"THUMB": 'BRUSH_THUMB'
|
||||
},
|
||||
|
||||
'VERTEX_PAINT': {
|
||||
"AVERAGE": 'BRUSH_BLUR',
|
||||
"BLUR": 'BRUSH_BLUR',
|
||||
"DRAW": 'BRUSH_MIX',
|
||||
"SMEAR": 'BRUSH_BLUR'
|
||||
},
|
||||
|
||||
'WEIGHT_PAINT': {
|
||||
"AVERAGE": 'BRUSH_BLUR',
|
||||
"BLUR": 'BRUSH_BLUR',
|
||||
"DRAW": 'BRUSH_MIX',
|
||||
"SMEAR": 'BRUSH_BLUR'
|
||||
},
|
||||
|
||||
'TEXTURE_PAINT': {
|
||||
"CLONE": 'BRUSH_CLONE',
|
||||
"DRAW": 'BRUSH_TEXDRAW',
|
||||
"FILL": 'BRUSH_TEXFILL',
|
||||
"MASK": 'BRUSH_TEXMASK',
|
||||
"SMEAR": 'BRUSH_SMEAR',
|
||||
"SOFTEN": 'BRUSH_SOFTEN'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BrushesMenu(Menu):
|
||||
bl_label = "Brush"
|
||||
bl_idname = "VIEW3D_MT_sv3_brushes_menu"
|
||||
|
||||
def draw(self, context):
|
||||
mode = utils_core.get_mode()
|
||||
layout = self.layout
|
||||
settings = UnifiedPaintPanel.paint_settings(context)
|
||||
colum_n = utils_core.addon_settings()
|
||||
|
||||
layout.row().label(text="Brush")
|
||||
layout.row().separator()
|
||||
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
current_brush = eval("bpy.context.{}".format(brush_datapath[mode])) if has_brush else None
|
||||
|
||||
# get the current brush's name
|
||||
if current_brush and utils_core.get_mode() != 'PARTICLE_EDIT':
|
||||
current_brush = current_brush.name
|
||||
|
||||
if mode == 'PARTICLE_EDIT':
|
||||
# if you are in particle edit mode add the menu items for particle mode
|
||||
for tool in particle_tools:
|
||||
utils_core.menuprop(
|
||||
layout.row(), tool[0], tool[1], brush_datapath[mode],
|
||||
icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
column_flow = layout.column_flow(columns=colum_n)
|
||||
|
||||
# iterate over all the brushes
|
||||
for item in bpy.data.brushes:
|
||||
if 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
|
||||
utils_core.menuprop(
|
||||
column_flow.row(), item.name,
|
||||
'bpy.data.brushes["%s"]' % item.name,
|
||||
brush_datapath[mode], icon=brush_icon[mode][item.sculpt_tool],
|
||||
disable=True, custom_disable_exp=(item.name, current_brush),
|
||||
path=True
|
||||
)
|
||||
if 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
|
||||
utils_core.menuprop(
|
||||
column_flow.row(), item.name,
|
||||
'bpy.data.brushes["%s"]' % item.name,
|
||||
brush_datapath[mode], icon=brush_icon[mode][item.vertex_tool],
|
||||
disable=True, custom_disable_exp=(item.name, current_brush),
|
||||
path=True
|
||||
)
|
||||
if 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
|
||||
utils_core.menuprop(
|
||||
column_flow.row(), item.name,
|
||||
'bpy.data.brushes["%s"]' % item.name,
|
||||
brush_datapath[mode], icon=brush_icon[mode][item.vertex_tool],
|
||||
disable=True, custom_disable_exp=(item.name, current_brush),
|
||||
path=True
|
||||
)
|
||||
if utils_core.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
|
||||
utils_core.menuprop(
|
||||
column_flow.row(), item.name,
|
||||
'bpy.data.brushes["%s"]' % item.name,
|
||||
brush_datapath[mode], icon=brush_icon[mode][item.image_tool],
|
||||
disable=True, custom_disable_exp=(item.name, current_brush),
|
||||
path=True
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(BrushesMenu)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(BrushesMenu)
|
|
@ -0,0 +1,88 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Menu,
|
||||
)
|
||||
from . import utils_core
|
||||
|
||||
|
||||
class BrushCurveMenu(Menu):
|
||||
bl_label = "Curve"
|
||||
bl_idname = "VIEW3D_MT_sv3_brush_curve_menu"
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'SCULPT', 'VERTEX_PAINT',
|
||||
'WEIGHT_PAINT', 'TEXTURE_PAINT',
|
||||
'PARTICLE_EDIT'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
curves = (("Smooth", "SMOOTH", "SMOOTHCURVE"),
|
||||
("Sphere", "ROUND", "SPHERECURVE"),
|
||||
("Root", "ROOT", "ROOTCURVE"),
|
||||
("Sharp", "SHARP", "SHARPCURVE"),
|
||||
("Linear", "LINE", "LINCURVE"),
|
||||
("Constant", "MAX", "NOCURVE"))
|
||||
|
||||
# add the top slider
|
||||
layout.row().operator(CurvePopup.bl_idname, icon="RNDCURVE")
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for curve in curves:
|
||||
item = layout.row().operator("brush.curve_preset",
|
||||
text=curve[0], icon=curve[2])
|
||||
item.shape = curve[1]
|
||||
|
||||
|
||||
class CurvePopup(Operator):
|
||||
"""Edit Falloff Curve"""
|
||||
bl_label = "Adjust Curve"
|
||||
bl_idname = "view3d.sv3_curve_popup"
|
||||
bl_description = "Edit Falloff Curve"
|
||||
bl_options = {'REGISTER'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'SCULPT', 'VERTEX_PAINT',
|
||||
'WEIGHT_PAINT', 'TEXTURE_PAINT'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
|
||||
if utils_core.get_mode() == 'SCULPT' or \
|
||||
utils_core.get_mode() == 'VERTEX_PAINT' or \
|
||||
utils_core.get_mode() == 'WEIGHT_PAINT' or \
|
||||
utils_core.get_mode() == 'TEXTURE_PAINT':
|
||||
if has_brush:
|
||||
layout.column().template_curve_mapping(has_brush,
|
||||
"curve", brush=True)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
def execute(self, context):
|
||||
return context.window_manager.invoke_popup(self, width=180)
|
||||
|
||||
|
||||
classes = (
|
||||
BrushCurveMenu,
|
||||
CurvePopup
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,172 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import Menu
|
||||
from . import utils_core
|
||||
|
||||
|
||||
class DynTopoMenu(Menu):
|
||||
bl_label = "Dyntopo"
|
||||
bl_idname = "VIEW3D_MT_sv3_dyntopo"
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() == 'SCULPT'
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
if context.object.use_dynamic_topology_sculpting:
|
||||
layout.row().operator("sculpt.dynamic_topology_toggle",
|
||||
text="Disable Dynamic Topology")
|
||||
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().menu(DynDetailMenu.bl_idname)
|
||||
layout.row().menu(DetailMethodMenu.bl_idname)
|
||||
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().operator("sculpt.optimize")
|
||||
if context.tool_settings.sculpt.detail_type_method == 'CONSTANT':
|
||||
layout.row().operator("sculpt.detail_flood_fill")
|
||||
|
||||
layout.row().menu(SymmetrizeMenu.bl_idname)
|
||||
layout.row().prop(context.tool_settings.sculpt,
|
||||
"use_smooth_shading", toggle=True)
|
||||
|
||||
else:
|
||||
row = layout.row()
|
||||
row.operator_context = 'INVOKE_DEFAULT'
|
||||
row.operator("sculpt.dynamic_topology_toggle",
|
||||
text="Enable Dynamic Topology")
|
||||
|
||||
|
||||
class DynDetailMenu(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"
|
||||
|
||||
elif bpy.context.tool_settings.sculpt.detail_type_method == 'CONSTANT':
|
||||
datapath = "tool_settings.sculpt.constant_detail_resolution"
|
||||
slider_setting = "constant_detail_resolution"
|
||||
else:
|
||||
datapath = "tool_settings.sculpt.detail_percent"
|
||||
slider_setting = "detail_percent"
|
||||
settings = (("100", 100),
|
||||
("75", 75),
|
||||
("50", 50),
|
||||
("25", 25),
|
||||
("10", 10),
|
||||
("5", 5))
|
||||
|
||||
return settings, datapath, slider_setting
|
||||
|
||||
def draw(self, context):
|
||||
settings, datapath, slider_setting = self.init()
|
||||
layout = self.layout
|
||||
|
||||
# add the top slider
|
||||
layout.row().prop(context.tool_settings.sculpt,
|
||||
slider_setting, slider=True)
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for i in range(len(settings)):
|
||||
utils_core.menuprop(
|
||||
layout.row(), settings[i][0], settings[i][1], datapath,
|
||||
icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
class DetailMethodMenu(Menu):
|
||||
bl_label = "Detail Method"
|
||||
bl_idname = "VIEW3D_MT_sv3_detail_method_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
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'),
|
||||
("Brush Detail", 'BRUSH'))
|
||||
|
||||
layout.row().label(text="Refine")
|
||||
layout.row().separator()
|
||||
|
||||
# add the refine menu items
|
||||
for item in refine_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item[0], item[1],
|
||||
refine_path, disable=True,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
layout.row().label(text="")
|
||||
|
||||
layout.row().label(text="Type")
|
||||
layout.row().separator()
|
||||
|
||||
# add the type menu items
|
||||
for item in type_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item[0], item[1],
|
||||
type_path, disable=True,
|
||||
icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
class SymmetrizeMenu(Menu):
|
||||
bl_label = "Symmetrize"
|
||||
bl_idname = "VIEW3D_MT_sv3_symmetrize_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
path = "tool_settings.sculpt.symmetrize_direction"
|
||||
|
||||
# add the the symmetrize operator to the menu
|
||||
layout.row().operator("sculpt.symmetrize")
|
||||
layout.row().separator()
|
||||
|
||||
# add the rest of the menu items
|
||||
for item in context.tool_settings.sculpt. \
|
||||
bl_rna.properties['symmetrize_direction'].enum_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier,
|
||||
path, disable=True,
|
||||
icon='RADIOBUT_OFF', disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
DynTopoMenu,
|
||||
DynDetailMenu,
|
||||
DetailMethodMenu,
|
||||
SymmetrizeMenu
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,200 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import Menu
|
||||
from . import utils_core
|
||||
from .brushes import brush_datapath
|
||||
|
||||
# stroke methods: 'AIRBRUSH' 'ANCHORED' 'SPACE' 'DRAG_DOT' 'DOTS' 'LINE' 'CURVE'
|
||||
|
||||
class PaintCurvesMenu(Menu):
|
||||
bl_label = "Paint Curves"
|
||||
bl_idname = "VIEW3D_MT_sv3_paint_curves_menu"
|
||||
|
||||
def draw(self, context):
|
||||
mode = utils_core.get_mode()
|
||||
layout = self.layout
|
||||
colum_n = utils_core.addon_settings()
|
||||
|
||||
layout.row().label(text="Paint Curves")
|
||||
layout.row().separator()
|
||||
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
|
||||
has_current_curve = has_brush.paint_curve if has_brush else None
|
||||
current_curve = has_current_curve.name if has_current_curve else ''
|
||||
|
||||
column_flow = layout.column_flow(columns=colum_n)
|
||||
|
||||
if len(bpy.data.paint_curves) != 0:
|
||||
for x, item in enumerate(bpy.data.paint_curves):
|
||||
utils_core.menuprop(
|
||||
column_flow.row(),
|
||||
item.name,
|
||||
'bpy.data.paint_curves["%s"]' % item.name,
|
||||
brush_datapath[mode] + ".paint_curve",
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON',
|
||||
custom_disable_exp=(item.name, current_curve),
|
||||
path=True
|
||||
)
|
||||
|
||||
else:
|
||||
layout.row().label(text="No Paint Curves Available", icon="INFO")
|
||||
|
||||
class StrokeOptionsMenu(Menu):
|
||||
bl_label = "Stroke Options"
|
||||
bl_idname = "VIEW3D_MT_sv3_stroke_options"
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'SCULPT', 'VERTEX_PAINT',
|
||||
'WEIGHT_PAINT', 'TEXTURE_PAINT',
|
||||
'PARTICLE_EDIT'
|
||||
)
|
||||
|
||||
def init(self):
|
||||
has_brush = utils_core.get_brush_link(bpy.context, types="brush")
|
||||
if utils_core.get_mode() == 'SCULPT':
|
||||
settings = bpy.context.tool_settings.sculpt
|
||||
|
||||
elif utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
settings = bpy.context.tool_settings.vertex_paint
|
||||
|
||||
elif utils_core.get_mode() == 'WEIGHT_PAINT':
|
||||
settings = bpy.context.tool_settings.weight_paint
|
||||
|
||||
elif utils_core.get_mode() == 'TEXTURE_PAINT':
|
||||
settings = bpy.context.tool_settings.image_paint
|
||||
|
||||
else:
|
||||
settings = None
|
||||
|
||||
stroke_method = has_brush.stroke_method if has_brush else None
|
||||
|
||||
return settings, has_brush, stroke_method
|
||||
|
||||
def draw(self, context):
|
||||
settings, brush, stroke_method = self.init()
|
||||
layout = self.layout
|
||||
|
||||
layout.row().menu(StrokeMethodMenu.bl_idname)
|
||||
layout.row().separator()
|
||||
|
||||
if stroke_method:
|
||||
|
||||
if stroke_method in ('SPACE', 'LINE') and brush:
|
||||
layout.row().prop(brush, "spacing",
|
||||
text=utils_core.PIW + "Spacing", slider=True)
|
||||
|
||||
elif stroke_method == 'AIRBRUSH' and brush:
|
||||
layout.row().prop(brush, "rate",
|
||||
text=utils_core.PIW + "Rate", slider=True)
|
||||
|
||||
elif stroke_method == 'ANCHORED' and brush:
|
||||
layout.row().prop(brush, "use_edge_to_edge")
|
||||
|
||||
elif stroke_method == 'CURVE' and brush:
|
||||
has_current_curve = brush.paint_curve if brush else None
|
||||
current_curve = has_current_curve.name if has_current_curve else 'No Curve Selected'
|
||||
|
||||
layout.row().menu(PaintCurvesMenu.bl_idname, text=current_curve,
|
||||
icon='CURVE_BEZCURVE')
|
||||
layout.row().operator("paintcurve.new", icon='ADD')
|
||||
layout.row().operator("paintcurve.draw")
|
||||
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().prop(brush, "spacing",
|
||||
text=utils_core.PIW + "Spacing",
|
||||
slider=True)
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
if utils_core.get_mode() == 'SCULPT' and stroke_method in ('DRAG_DOT', 'ANCHORED'):
|
||||
pass
|
||||
else:
|
||||
if brush:
|
||||
layout.row().prop(brush, "jitter",
|
||||
text=utils_core.PIW + "Jitter", slider=True)
|
||||
|
||||
layout.row().prop(settings, "input_samples",
|
||||
text=utils_core.PIW + "Input Samples", slider=True)
|
||||
|
||||
if stroke_method in ('DOTS', 'SPACE', 'AIRBRUSH') and brush:
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().prop(brush, "use_smooth_stroke", toggle=True)
|
||||
|
||||
if brush.use_smooth_stroke:
|
||||
layout.row().prop(brush, "smooth_stroke_radius",
|
||||
text=utils_core.PIW + "Radius", slider=True)
|
||||
layout.row().prop(brush, "smooth_stroke_factor",
|
||||
text=utils_core.PIW + "Factor", slider=True)
|
||||
else:
|
||||
layout.row().label(text="No Stroke Options available", icon="INFO")
|
||||
|
||||
|
||||
class StrokeMethodMenu(Menu):
|
||||
bl_label = "Stroke Method"
|
||||
bl_idname = "VIEW3D_MT_sv3_stroke_method"
|
||||
|
||||
def init(self):
|
||||
has_brush = utils_core.get_brush_link(bpy.context, types="brush")
|
||||
if utils_core.get_mode() == 'SCULPT':
|
||||
path = "tool_settings.sculpt.brush.stroke_method"
|
||||
|
||||
elif utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
path = "tool_settings.vertex_paint.brush.stroke_method"
|
||||
|
||||
elif utils_core.get_mode() == 'WEIGHT_PAINT':
|
||||
path = "tool_settings.weight_paint.brush.stroke_method"
|
||||
|
||||
elif utils_core.get_mode() == 'TEXTURE_PAINT':
|
||||
path = "tool_settings.image_paint.brush.stroke_method"
|
||||
|
||||
else:
|
||||
path = ""
|
||||
|
||||
return has_brush, path
|
||||
|
||||
def draw(self, context):
|
||||
brush, path = self.init()
|
||||
layout = self.layout
|
||||
|
||||
layout.row().label(text="Stroke Method")
|
||||
layout.row().separator()
|
||||
|
||||
if brush:
|
||||
# add the menu items dynamically based on values in enum property
|
||||
for tool in brush.bl_rna.properties['stroke_method'].enum_items:
|
||||
if tool.identifier in ('ANCHORED', 'DRAG_DOT') and \
|
||||
utils_core.get_mode() in ('VERTEX_PAINT',
|
||||
'WEIGHT_PAINT'):
|
||||
continue
|
||||
|
||||
utils_core.menuprop(
|
||||
layout.row(), tool.name, tool.identifier, path,
|
||||
icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No Stroke Method available", icon="INFO")
|
||||
|
||||
|
||||
classes = (
|
||||
PaintCurvesMenu,
|
||||
StrokeOptionsMenu,
|
||||
StrokeMethodMenu
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,80 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import Menu
|
||||
from . import utils_core
|
||||
|
||||
|
||||
class MasterSymmetryMenu(Menu):
|
||||
bl_label = "Symmetry Options"
|
||||
bl_idname = "VIEW3D_MT_sv3_master_symmetry_menu"
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'SCULPT',
|
||||
'TEXTURE_PAINT'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
if utils_core.get_mode() == 'TEXTURE_PAINT':
|
||||
layout.row().prop(context.tool_settings.image_paint,
|
||||
"use_symmetry_x", toggle=True)
|
||||
layout.row().prop(context.tool_settings.image_paint,
|
||||
"use_symmetry_y", toggle=True)
|
||||
layout.row().prop(context.tool_settings.image_paint,
|
||||
"use_symmetry_z", toggle=True)
|
||||
else:
|
||||
layout.row().menu(SymmetryMenu.bl_idname)
|
||||
layout.row().menu(SymmetryRadialMenu.bl_idname)
|
||||
layout.row().prop(context.tool_settings.sculpt,
|
||||
"use_symmetry_feather", toggle=True)
|
||||
|
||||
|
||||
class SymmetryMenu(Menu):
|
||||
bl_label = "Symmetry"
|
||||
bl_idname = "VIEW3D_MT_sv3_symmetry_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.row().label(text="Symmetry")
|
||||
layout.row().separator()
|
||||
|
||||
layout.row().prop(context.tool_settings.sculpt,
|
||||
"use_symmetry_x", toggle=True)
|
||||
layout.row().prop(context.tool_settings.sculpt,
|
||||
"use_symmetry_y", toggle=True)
|
||||
layout.row().prop(context.tool_settings.sculpt,
|
||||
"use_symmetry_z", toggle=True)
|
||||
|
||||
|
||||
class SymmetryRadialMenu(Menu):
|
||||
bl_label = "Radial"
|
||||
bl_idname = "VIEW3D_MT_sv3_symmetry_radial_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.row().label(text="Radial")
|
||||
layout.row().separator()
|
||||
|
||||
layout.column().prop(context.tool_settings.sculpt,
|
||||
"radial_symmetry", text="", slider=True)
|
||||
|
||||
|
||||
classes = (
|
||||
MasterSymmetryMenu,
|
||||
SymmetryMenu,
|
||||
SymmetryRadialMenu
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,415 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
from bpy.types import Menu
|
||||
from . import utils_core
|
||||
|
||||
|
||||
class TextureMenu(Menu):
|
||||
bl_label = "Texture Options"
|
||||
bl_idname = "VIEW3D_MT_sv3_texture_menu"
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return utils_core.get_mode() in (
|
||||
'SCULPT',
|
||||
'VERTEX_PAINT',
|
||||
'TEXTURE_PAINT'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
if utils_core.get_mode() == 'SCULPT':
|
||||
self.sculpt(layout, context)
|
||||
|
||||
elif utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
self.vertpaint(layout, context)
|
||||
|
||||
else:
|
||||
self.texpaint(layout, context)
|
||||
|
||||
def sculpt(self, layout, context):
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
tex_slot = has_brush.texture_slot if has_brush else None
|
||||
|
||||
# Menus
|
||||
layout.row().menu(Textures.bl_idname)
|
||||
layout.row().menu(TextureMapMode.bl_idname)
|
||||
layout.row().separator()
|
||||
|
||||
# Checkboxes
|
||||
if tex_slot:
|
||||
if tex_slot.map_mode != '3D':
|
||||
if tex_slot.map_mode in ('RANDOM', 'VIEW_PLANE', 'AREA_PLANE'):
|
||||
layout.row().prop(tex_slot, "use_rake", toggle=True)
|
||||
layout.row().prop(tex_slot, "use_random", toggle=True)
|
||||
|
||||
# Sliders
|
||||
layout.row().prop(tex_slot, "angle",
|
||||
text=utils_core.PIW + "Angle", slider=True)
|
||||
|
||||
if tex_slot.tex_paint_map_mode in ('RANDOM', 'VIEW_PLANE') and tex_slot.use_random:
|
||||
layout.row().prop(tex_slot, "random_angle",
|
||||
text=utils_core.PIW + "Random Angle", slider=True)
|
||||
|
||||
# Operator
|
||||
if tex_slot.tex_paint_map_mode == 'STENCIL':
|
||||
if has_brush.texture and has_brush.texture.type == 'IMAGE':
|
||||
layout.row().operator("brush.stencil_fit_image_aspect")
|
||||
|
||||
layout.row().operator("brush.stencil_reset_transform")
|
||||
|
||||
else:
|
||||
layout.row().label(text="No Texture Slot available", icon="INFO")
|
||||
|
||||
def vertpaint(self, layout, context):
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
tex_slot = has_brush.texture_slot if has_brush else None
|
||||
|
||||
# Menus
|
||||
layout.row().menu(Textures.bl_idname)
|
||||
layout.row().menu(TextureMapMode.bl_idname)
|
||||
|
||||
# Checkboxes
|
||||
if tex_slot:
|
||||
if tex_slot.tex_paint_map_mode != '3D':
|
||||
if tex_slot.tex_paint_map_mode in ('RANDOM', 'VIEW_PLANE'):
|
||||
layout.row().prop(tex_slot, "use_rake", toggle=True)
|
||||
layout.row().prop(tex_slot, "use_random", toggle=True)
|
||||
|
||||
# Sliders
|
||||
layout.row().prop(tex_slot, "angle",
|
||||
text=utils_core.PIW + "Angle", slider=True)
|
||||
|
||||
if tex_slot.tex_paint_map_mode in ('RANDOM', 'VIEW_PLANE') and tex_slot.use_random:
|
||||
layout.row().prop(tex_slot, "random_angle",
|
||||
text=utils_core.PIW + "Random Angle", slider=True)
|
||||
|
||||
# Operator
|
||||
if tex_slot.tex_paint_map_mode == 'STENCIL':
|
||||
if has_brush.texture and has_brush.texture.type == 'IMAGE':
|
||||
layout.row().operator("brush.stencil_fit_image_aspect")
|
||||
|
||||
layout.row().operator("brush.stencil_reset_transform")
|
||||
|
||||
else:
|
||||
layout.row().label(text="No Texture Slot available", icon="INFO")
|
||||
|
||||
def texpaint(self, layout, context):
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
tex_slot = has_brush.texture_slot if has_brush else None
|
||||
mask_tex_slot = has_brush.mask_texture_slot if has_brush else None
|
||||
|
||||
# Texture Section
|
||||
layout.row().label(text="Texture", icon='TEXTURE')
|
||||
|
||||
# Menus
|
||||
layout.row().menu(Textures.bl_idname)
|
||||
layout.row().menu(TextureMapMode.bl_idname)
|
||||
|
||||
# Checkboxes
|
||||
if tex_slot:
|
||||
if tex_slot.tex_paint_map_mode != '3D':
|
||||
if tex_slot.tex_paint_map_mode in ('RANDOM', 'VIEW_PLANE'):
|
||||
layout.row().prop(tex_slot, "use_rake", toggle=True)
|
||||
layout.row().prop(tex_slot, "use_random", toggle=True)
|
||||
|
||||
# Sliders
|
||||
layout.row().prop(tex_slot, "angle",
|
||||
text=utils_core.PIW + "Angle", slider=True)
|
||||
|
||||
if tex_slot.tex_paint_map_mode in ('RANDOM', 'VIEW_PLANE') and tex_slot.use_random:
|
||||
layout.row().prop(tex_slot, "random_angle",
|
||||
text=utils_core.PIW + "Random Angle", slider=True)
|
||||
|
||||
# Operator
|
||||
if tex_slot.tex_paint_map_mode == 'STENCIL':
|
||||
if has_brush.texture and has_brush.texture.type == 'IMAGE':
|
||||
layout.row().operator("brush.stencil_fit_image_aspect")
|
||||
|
||||
layout.row().operator("brush.stencil_reset_transform")
|
||||
|
||||
else:
|
||||
layout.row().label(text="No Texture Slot available", icon="INFO")
|
||||
|
||||
layout.row().separator()
|
||||
|
||||
# Texture Mask Section
|
||||
layout.row().label(text="Texture Mask", icon='MOD_MASK')
|
||||
|
||||
# Menus
|
||||
layout.row().menu(MaskTextures.bl_idname)
|
||||
layout.row().menu(MaskMapMode.bl_idname)
|
||||
layout.row().menu(MaskPressureModeMenu.bl_idname)
|
||||
|
||||
# Checkboxes
|
||||
if mask_tex_slot:
|
||||
if mask_tex_slot.mask_map_mode in ('RANDOM', 'VIEW_PLANE'):
|
||||
layout.row().prop(mask_tex_slot, "use_rake", toggle=True)
|
||||
layout.row().prop(mask_tex_slot, "use_random", toggle=True)
|
||||
|
||||
# Sliders
|
||||
layout.row().prop(mask_tex_slot, "angle",
|
||||
text=utils_core.PIW + "Angle", icon_value=5, slider=True)
|
||||
|
||||
if mask_tex_slot.mask_map_mode in ('RANDOM', 'VIEW_PLANE') and mask_tex_slot.use_random:
|
||||
layout.row().prop(mask_tex_slot, "random_angle",
|
||||
text=utils_core.PIW + "Random Angle", slider=True)
|
||||
|
||||
# Operator
|
||||
if mask_tex_slot.mask_map_mode == 'STENCIL':
|
||||
if has_brush.mask_texture and has_brush.mask_texture.type == 'IMAGE':
|
||||
layout.row().operator("brush.stencil_fit_image_aspect")
|
||||
|
||||
prop = layout.row().operator("brush.stencil_reset_transform")
|
||||
prop.mask = True
|
||||
|
||||
else:
|
||||
layout.row().label(text="Mask Texture not available", icon="INFO")
|
||||
|
||||
|
||||
class Textures(Menu):
|
||||
bl_label = "Brush Texture"
|
||||
bl_idname = "VIEW3D_MT_sv3_texture_list"
|
||||
|
||||
def init(self):
|
||||
if utils_core.get_mode() == 'SCULPT':
|
||||
datapath = "tool_settings.sculpt.brush.texture"
|
||||
|
||||
elif utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
datapath = "tool_settings.vertex_paint.brush.texture"
|
||||
|
||||
elif utils_core.get_mode() == 'TEXTURE_PAINT':
|
||||
datapath = "tool_settings.image_paint.brush.texture"
|
||||
|
||||
else:
|
||||
datapath = ""
|
||||
|
||||
return datapath
|
||||
|
||||
def draw(self, context):
|
||||
datapath = self.init()
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
current_texture = eval("bpy.context.{}".format(datapath)) if \
|
||||
has_brush else None
|
||||
layout = self.layout
|
||||
|
||||
# get the current texture's name
|
||||
if current_texture:
|
||||
current_texture = current_texture.name
|
||||
|
||||
layout.row().label(text="Brush Texture")
|
||||
layout.row().separator()
|
||||
|
||||
# add an item to set the texture to None
|
||||
utils_core.menuprop(layout.row(), "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:
|
||||
utils_core.menuprop(layout.row(), 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(Menu):
|
||||
bl_label = "Brush Mapping"
|
||||
bl_idname = "VIEW3D_MT_sv3_texture_map_mode"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
|
||||
layout.row().label(text="Brush Mapping")
|
||||
layout.row().separator()
|
||||
|
||||
if has_brush:
|
||||
if utils_core.get_mode() == 'SCULPT':
|
||||
path = "tool_settings.sculpt.brush.texture_slot.map_mode"
|
||||
|
||||
# add the menu items
|
||||
for item in has_brush. \
|
||||
texture_slot.bl_rna.properties['map_mode'].enum_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
elif utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
path = "tool_settings.vertex_paint.brush.texture_slot.tex_paint_map_mode"
|
||||
|
||||
# add the menu items
|
||||
for item in has_brush. \
|
||||
texture_slot.bl_rna.properties['tex_paint_map_mode'].enum_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
path = "tool_settings.image_paint.brush.texture_slot.tex_paint_map_mode"
|
||||
|
||||
# add the menu items
|
||||
for item in has_brush. \
|
||||
texture_slot.bl_rna.properties['tex_paint_map_mode'].enum_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
|
||||
class MaskTextures(Menu):
|
||||
bl_label = "Mask Texture"
|
||||
bl_idname = "VIEW3D_MT_sv3_mask_texture_list"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
datapath = "tool_settings.image_paint.brush.mask_texture"
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
current_texture = eval("bpy.context.{}".format(datapath)) if \
|
||||
has_brush else None
|
||||
|
||||
layout.row().label(text="Mask Texture")
|
||||
layout.row().separator()
|
||||
|
||||
if has_brush:
|
||||
# get the current texture's name
|
||||
if current_texture:
|
||||
current_texture = current_texture.name
|
||||
|
||||
# add an item to set the texture to None
|
||||
utils_core.menuprop(
|
||||
layout.row(), "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:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, 'bpy.data.textures["%s"]' % item.name,
|
||||
datapath, icon='RADIOBUT_OFF', disable=True,
|
||||
disable_icon='RADIOBUT_ON',
|
||||
custom_disable_exp=(item.name, current_texture),
|
||||
path=True
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
|
||||
class MaskMapMode(Menu):
|
||||
bl_label = "Mask Mapping"
|
||||
bl_idname = "VIEW3D_MT_sv3_mask_map_mode"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
path = "tool_settings.image_paint.brush.mask_texture_slot.mask_map_mode"
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
|
||||
layout.row().label(text="Mask Mapping")
|
||||
layout.row().separator()
|
||||
if has_brush:
|
||||
items = has_brush. \
|
||||
mask_texture_slot.bl_rna.properties['mask_map_mode'].enum_items
|
||||
# add the menu items
|
||||
for item in items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
|
||||
class TextureAngleSource(Menu):
|
||||
bl_label = "Texture Angle Source"
|
||||
bl_idname = "VIEW3D_MT_sv3_texture_angle_source"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
has_brush = utils_core.get_brush_link(context, types="brush")
|
||||
|
||||
if has_brush:
|
||||
if utils_core.get_mode() == 'SCULPT':
|
||||
items = has_brush. \
|
||||
bl_rna.properties['texture_angle_source_random'].enum_items
|
||||
path = "tool_settings.sculpt.brush.texture_angle_source_random"
|
||||
|
||||
elif utils_core.get_mode() == 'VERTEX_PAINT':
|
||||
items = has_brush. \
|
||||
bl_rna.properties['texture_angle_source_random'].enum_items
|
||||
path = "tool_settings.vertex_paint.brush.texture_angle_source_random"
|
||||
|
||||
else:
|
||||
items = has_brush. \
|
||||
bl_rna.properties['texture_angle_source_random'].enum_items
|
||||
path = "tool_settings.image_paint.brush.texture_angle_source_random"
|
||||
|
||||
# add the menu items
|
||||
for item in items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item[0], item[1], path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
else:
|
||||
layout.row().label(text="No brushes available", icon="INFO")
|
||||
|
||||
class MaskPressureModeMenu(Menu):
|
||||
bl_label = "Mask Pressure Mode"
|
||||
bl_idname = "VIEW3D_MT_sv3_mask_pressure_mode_menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
path = "tool_settings.image_paint.brush.use_pressure_masking"
|
||||
|
||||
layout.row().label(text="Mask Pressure Mode")
|
||||
layout.row().separator()
|
||||
|
||||
# add the menu items
|
||||
for item in context.tool_settings.image_paint.brush. \
|
||||
bl_rna.properties['use_pressure_masking'].enum_items:
|
||||
utils_core.menuprop(
|
||||
layout.row(), item.name, item.identifier, path,
|
||||
icon='RADIOBUT_OFF',
|
||||
disable=True,
|
||||
disable_icon='RADIOBUT_ON'
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
TextureMenu,
|
||||
Textures,
|
||||
TextureMapMode,
|
||||
MaskTextures,
|
||||
MaskMapMode,
|
||||
TextureAngleSource,
|
||||
MaskPressureModeMenu
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -0,0 +1,105 @@
|
|||
# gpl author: Ryan Inch (Imaginer)
|
||||
|
||||
import bpy
|
||||
|
||||
get_addon_name = 'space_view3d_brush_menus'
|
||||
|
||||
# Property Icon Width
|
||||
PIW = ' '
|
||||
|
||||
|
||||
# check for (currently) brushes being linked
|
||||
def get_brush_link(context, types="brush"):
|
||||
tool_settings = context.tool_settings
|
||||
has_brush = None
|
||||
|
||||
if get_mode() == 'SCULPT':
|
||||
datapath = tool_settings.sculpt
|
||||
|
||||
elif get_mode() == 'VERTEX_PAINT':
|
||||
datapath = tool_settings.vertex_paint
|
||||
|
||||
elif get_mode() == 'WEIGHT_PAINT':
|
||||
datapath = tool_settings.weight_paint
|
||||
|
||||
elif get_mode() == 'TEXTURE_PAINT':
|
||||
datapath = tool_settings.image_paint
|
||||
else:
|
||||
datapath = None
|
||||
|
||||
if types == "brush":
|
||||
has_brush = getattr(datapath, "brush", None)
|
||||
|
||||
return has_brush
|
||||
|
||||
|
||||
# Addon settings
|
||||
def addon_settings():
|
||||
# separate function just for more convenience
|
||||
addon = bpy.context.preferences.addons[get_addon_name]
|
||||
colum_n = addon.preferences.column_set if addon else 1
|
||||
|
||||
return colum_n
|
||||
|
||||
|
||||
def error_handlers(self, op_name, error, reports="ERROR", func=False):
|
||||
if self and reports:
|
||||
self.report({'WARNING'}, reports + " (See Console for more info)")
|
||||
|
||||
is_func = "Function" if func else "Operator"
|
||||
print("\n[Sculpt/Paint Brush Menus]\n{}: {}\nError: {}\n".format(is_func, op_name, error))
|
||||
|
||||
|
||||
# Object modes:
|
||||
# 'OBJECT' 'EDIT' 'SCULPT'
|
||||
# 'VERTEX_PAINT' 'WEIGHT_PAINT' 'TEXTURE_PAINT'
|
||||
# 'PARTICLE_EDIT' 'POSE' 'GPENCIL_EDIT'
|
||||
def get_mode():
|
||||
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
|
|
@ -196,25 +196,6 @@ class PIE_OT_VertsEdgesFaces(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Grease Pencil Interactive Mode
|
||||
class PIE_OT_InteractiveModeGreasePencil(Operator):
|
||||
bl_idname = "view3d.pie_interactive_mode_grease_pencil"
|
||||
bl_label = "Edit Strokes"
|
||||
bl_description = "Toggle Edit Strokes for Grease Pencil"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.gpencil_data is not None)
|
||||
|
||||
def execute(self, context):
|
||||
try:
|
||||
bpy.ops.gpencil.editmode_toggle()
|
||||
except:
|
||||
self.report({'WARNING'},
|
||||
"It is not possible to enter into the interactive mode")
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Menus
|
||||
class PIE_MT_ObjectEditotherModes(Menu):
|
||||
"""Edit/Object Others modes"""
|
||||
|
@ -267,13 +248,12 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
# 9 - TOP - RIGHT
|
||||
pie.operator("class.pievertexpaint", text="Vertex Paint", icon='VPAINT_HLT')
|
||||
# 1 - BOTTOM - LEFT
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.object.particle_systems:
|
||||
pie.operator("class.pieparticleedit", text="Particle Edit", icon='PARTICLEMODE')
|
||||
else:
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
|
||||
elif ob and ob.type == 'MESH' and ob.mode in {'EDIT'}:
|
||||
pie = layout.menu_pie()
|
||||
|
@ -290,13 +270,12 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
# 9 - TOP - RIGHT
|
||||
pie.operator("class.pievertexpaint", text="Vertex Paint", icon='VPAINT_HLT')
|
||||
# 1 - BOTTOM - LEFT
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.object.particle_systems:
|
||||
pie.operator("class.pieparticleedit", text="Particle Edit", icon='PARTICLEMODE')
|
||||
else:
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
|
||||
elif ob and ob.type == 'CURVE':
|
||||
pie = layout.menu_pie()
|
||||
|
@ -315,8 +294,7 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
# 1 - BOTTOM - LEFT
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
pie.separator()
|
||||
|
||||
elif ob and ob.type == 'ARMATURE':
|
||||
pie = layout.menu_pie()
|
||||
|
@ -335,8 +313,7 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
# 1 - BOTTOM - LEFT
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
pie.separator()
|
||||
|
||||
elif ob and ob.type == 'FONT':
|
||||
pie = layout.menu_pie()
|
||||
|
@ -348,8 +325,7 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
pie.separator()
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
pie.separator()
|
||||
|
||||
elif ob and ob.type == 'SURFACE':
|
||||
pie = layout.menu_pie()
|
||||
|
@ -361,8 +337,7 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
pie.separator()
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
pie.separator()
|
||||
|
||||
elif ob and ob.type == 'META':
|
||||
pie = layout.menu_pie()
|
||||
|
@ -374,8 +349,7 @@ class PIE_MT_ObjectEditMode(Menu):
|
|||
pie.separator()
|
||||
pie.separator()
|
||||
# 3 - BOTTOM - RIGHT
|
||||
if context.gpencil_data:
|
||||
pie.operator("view3d.pie_interactive_mode_grease_pencil", icon="GREASEPENCIL")
|
||||
pie.separator()
|
||||
|
||||
elif ob and ob.type == 'LATTICE':
|
||||
pie = layout.menu_pie()
|
||||
|
@ -429,7 +403,6 @@ classes = (
|
|||
PIE_OT_ClassWeightPaint,
|
||||
PIE_OT_ClassVertexPaint,
|
||||
PIE_OT_ClassParticleEdit,
|
||||
PIE_OT_InteractiveModeGreasePencil,
|
||||
PIE_OT_VertsEdgesFaces,
|
||||
PIE_OT_SetObjectModePie,
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,20 +31,6 @@ from bpy.props import (
|
|||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
|
||||
|
||||
# Animation Menus
|
||||
class VIEW3D_MT_KeyframeMenu(Menu):
|
||||
bl_label = "Keyframe"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("anim.keyframe_insert_menu",
|
||||
text="Insert Keyframe...")
|
||||
layout.operator("anim.keyframe_delete_v3d",
|
||||
text="Delete Keyframe...")
|
||||
layout.operator("anim.keying_set_active_set",
|
||||
text="Change Keying Set...")
|
||||
|
||||
|
||||
|
||||
# Animation Player (Thanks to marvin.k.breuer) #
|
||||
class VIEW3D_MT_Animation_Player(Menu):
|
||||
|
@ -67,14 +53,13 @@ class VIEW3D_MT_Animation_Player(Menu):
|
|||
layout.operator("screen.frame_jump", text="Jump REW", icon='REW').end = False
|
||||
layout.separator()
|
||||
|
||||
layout.menu("VIEW3D_MT_KeyframeMenu", text="Keyframes", icon='DECORATE_ANIMATE')
|
||||
layout.menu("VIEW3D_MT_object_animation", text="Keyframes", icon='DECORATE_ANIMATE')
|
||||
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_KeyframeMenu,
|
||||
VIEW3D_MT_Animation_Player,
|
||||
)
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ from bpy.props import (
|
|||
BoolProperty,
|
||||
StringProperty,
|
||||
)
|
||||
|
||||
from .object_menus import *
|
||||
|
||||
|
||||
|
@ -39,73 +40,33 @@ class VIEW3D_MT_Edit_Curve(Menu):
|
|||
|
||||
toolsettings = context.tool_settings
|
||||
|
||||
layout.operator("curve.extrude_move")
|
||||
layout.operator("curve.spin")
|
||||
layout.operator_menu_enum("curve.spline_type_set", "type")
|
||||
layout.menu("VIEW3D_MT_mirror")
|
||||
layout.operator("curve.make_segment")
|
||||
layout.menu("VIEW3D_MT_edit_curve_segments")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("curve.duplicate_move")
|
||||
layout.operator("curve.split")
|
||||
layout.operator("curve.separate")
|
||||
layout.operator("curve.make_segment")
|
||||
layout.operator("curve.cyclic_toggle")
|
||||
layout.operator("curve.spin")
|
||||
layout.separator()
|
||||
layout.operator("curve.delete", text="Delete...")
|
||||
|
||||
layout.menu("VIEW3D_MT_edit_curve_showhide")
|
||||
layout.menu("VIEW3D_MT_edit_curve_clean")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_curve_segments")
|
||||
|
||||
# layout.prop_menu_enum(toolsettings, "proportional_edit",
|
||||
# icon="PROP_CON")
|
||||
layout.prop_menu_enum(toolsettings, "proportional_edit_falloff",
|
||||
icon="SMOOTHCURVE")
|
||||
layout.menu("VIEW3D_MT_edit_curve_showhide")
|
||||
|
||||
|
||||
class VIEW3D_MT_EditCurveCtrlpoints(Menu):
|
||||
bl_label = "Control Points"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
edit_object = context.edit_object
|
||||
|
||||
if edit_object.type == 'CURVE':
|
||||
layout.operator("transform.transform").mode = 'TILT'
|
||||
layout.operator("curve.tilt_clear")
|
||||
layout.operator("curve.separate")
|
||||
layout.operator_menu_enum("curve.handle_type_set", "type")
|
||||
layout.menu("VIEW3D_MT_hook")
|
||||
|
||||
|
||||
class VIEW3D_MT_EditCurveSegments(Menu):
|
||||
bl_label = "Curve Segments"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("curve.subdivide")
|
||||
layout.operator("curve.switch_direction")
|
||||
|
||||
|
||||
class VIEW3D_MT_EditCurveSpecials(Menu):
|
||||
bl_label = "Specials"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("curve.subdivide")
|
||||
layout.separator()
|
||||
layout.operator("curve.switch_direction")
|
||||
layout.operator("curve.spline_weight_set")
|
||||
layout.operator("curve.radius_set")
|
||||
layout.separator()
|
||||
layout.operator("curve.smooth")
|
||||
layout.operator("curve.smooth_weight")
|
||||
layout.operator("curve.smooth_radius")
|
||||
layout.operator("curve.smooth_tilt")
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_Edit_Curve,
|
||||
VIEW3D_MT_EditCurveCtrlpoints,
|
||||
VIEW3D_MT_EditCurveSegments,
|
||||
VIEW3D_MT_EditCurveSpecials,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -32,95 +32,8 @@ from .object_menus import *
|
|||
from .snap_origin_cursor import *
|
||||
|
||||
|
||||
# ********** Edit Mirror **********
|
||||
class VIEW3D_MT_MirrorMenuEM(Menu):
|
||||
bl_label = "Mirror"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
props = layout.operator("transform.mirror", text="X Local")
|
||||
props.constraint_axis = (True, False, False)
|
||||
props.orient_type = 'LOCAL'
|
||||
props = layout.operator("transform.mirror", text="Y Local")
|
||||
props.constraint_axis = (False, True, False)
|
||||
props.orient_type = 'LOCAL'
|
||||
props = layout.operator("transform.mirror", text="Z Local")
|
||||
props.constraint_axis = (False, False, True)
|
||||
props.orient_type = 'LOCAL'
|
||||
layout.separator()
|
||||
layout.operator("object.vertex_group_mirror")
|
||||
|
||||
|
||||
# ********** Normals / Auto Smooth Menu **********
|
||||
# Thanks to marvin.k.breuer for the Autosmooth part of the menu
|
||||
class VIEW3D_MT_AutoSmooth(Menu):
|
||||
bl_label = "Normals / Auto Smooth"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
obj = context.object
|
||||
obj_data = context.active_object.data
|
||||
|
||||
# moved the VIEW3D_MT_edit_mesh_normals contents here under an Edit mode check
|
||||
if obj and obj.type == 'MESH' and obj.mode in {'EDIT'}:
|
||||
layout.operator("mesh.normals_make_consistent",
|
||||
text="Recalculate Outside").inside = False
|
||||
layout.operator("mesh.normals_make_consistent",
|
||||
text="Recalculate Inside").inside = True
|
||||
layout.operator("mesh.flip_normals")
|
||||
layout.separator()
|
||||
|
||||
layout.separator()
|
||||
layout.prop(obj_data, "use_auto_smooth", text="Normals: Auto Smooth")
|
||||
|
||||
# Auto Smooth Angle - two tab spaces to align it with the rest of the menu
|
||||
layout.prop(obj_data, "auto_smooth_angle",
|
||||
text=" Auto Smooth Angle")
|
||||
|
||||
|
||||
# Edit Mode Menu's #
|
||||
|
||||
# ********** Edit Mesh **********
|
||||
class VIEW3D_MT_Edit_Mesh(Menu):
|
||||
bl_label = "Mesh"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
toolsettings = context.tool_settings
|
||||
view = context.space_data
|
||||
|
||||
layout.menu("VIEW3D_MT_edit_mesh_vertices", icon='VERTEXSEL')
|
||||
layout.menu("VIEW3D_MT_edit_mesh_edges", icon='EDGESEL')
|
||||
layout.menu("VIEW3D_MT_edit_mesh_faces", icon='FACESEL')
|
||||
layout.separator()
|
||||
layout.operator("mesh.duplicate_move")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_mesh_clean", icon='AUTO')
|
||||
# layout.prop(view, "use_occlude_geometry")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_AutoSmooth", icon='META_DATA')
|
||||
layout.operator("mesh.loopcut_slide",
|
||||
text="Loopcut", icon='UV_EDGESEL')
|
||||
layout.separator()
|
||||
layout.operator("mesh.symmetrize")
|
||||
layout.operator("mesh.symmetry_snap")
|
||||
layout.separator()
|
||||
layout.operator("mesh.bisect")
|
||||
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
|
||||
layout.separator()
|
||||
# layout.prop_menu_enum(toolsettings, "proportional_edit")
|
||||
layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
|
||||
layout.separator()
|
||||
|
||||
layout.prop(toolsettings, "use_mesh_automerge")
|
||||
# Double Threshold - two tab spaces to align it with the rest of the menu
|
||||
layout.prop(toolsettings, "double_threshold", text="Double Threshold")
|
||||
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_mesh_showhide")
|
||||
|
||||
|
||||
# ********** Edit Multiselect **********
|
||||
class VIEW3D_MT_Edit_Multi(Menu):
|
||||
bl_label = "Mode Select"
|
||||
|
@ -167,156 +80,6 @@ class VIEW3D_MT_EditM_Edge(Menu):
|
|||
layout.operator("mesh.region_to_loop")
|
||||
|
||||
|
||||
# ********** Edit Mesh Cursor **********
|
||||
class VIEW3D_MT_EditCursorMenu(Menu):
|
||||
bl_label = "Snap Cursor"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("object.setorigintoselected",
|
||||
text="Origin to Selected V/F/E")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_Snap_Origin")
|
||||
layout.menu("VIEW3D_MT_Snap_Context")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_cursor_to_selected",
|
||||
text="Cursor to Selected")
|
||||
layout.operator("view3d.snap_cursor_to_center",
|
||||
text="Cursor to World Origin")
|
||||
layout.operator("view3d.snap_cursor_to_grid",
|
||||
text="Cursor to Grid")
|
||||
layout.operator("view3d.snap_cursor_to_active",
|
||||
text="Cursor to Active")
|
||||
layout.operator("view3d.snap_cursor_to_edge_intersection",
|
||||
text="Cursor to Edge Intersection")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor").use_offset = False
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor (Keep Offset)").use_offset = True
|
||||
layout.operator("view3d.snap_selected_to_grid",
|
||||
text="Selection to Grid")
|
||||
|
||||
|
||||
# ********** Edit Mesh UV **********
|
||||
class VIEW3D_MT_UV_Map(Menu):
|
||||
bl_label = "UV Mapping"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("uv.unwrap")
|
||||
layout.separator()
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
layout.operator("uv.smart_project")
|
||||
layout.operator("uv.lightmap_pack")
|
||||
layout.operator("uv.follow_active_quads")
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
layout.operator("uv.cube_project")
|
||||
layout.operator("uv.cylinder_project")
|
||||
layout.operator("uv.sphere_project")
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.separator()
|
||||
layout.operator("uv.project_from_view").scale_to_bounds = False
|
||||
layout.operator("uv.project_from_view", text="Project from View (Bounds)").scale_to_bounds = True
|
||||
layout.separator()
|
||||
layout.operator("uv.reset")
|
||||
|
||||
|
||||
# ********** Edit Mesh Transform **********
|
||||
class VIEW3D_MT_TransformMenuEdit(Menu):
|
||||
bl_label = "Transform"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("transform.translate", text="Move")
|
||||
layout.operator("transform.rotate", text="Rotate")
|
||||
layout.operator("transform.resize", text="Scale")
|
||||
layout.separator()
|
||||
layout.operator("transform.tosphere", text="To Sphere")
|
||||
layout.operator("transform.shear", text="Shear")
|
||||
layout.operator("transform.bend", text="Bend")
|
||||
layout.operator("transform.push_pull", text="Push/Pull")
|
||||
layout.operator("transform.vertex_warp", text="Warp")
|
||||
layout.operator("transform.vertex_random", text="Randomize")
|
||||
layout.separator()
|
||||
layout.operator("transform.translate", text="Move Texture Space").texture_space = True
|
||||
layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
|
||||
layout.separator()
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
layout.operator("transform.transform",
|
||||
text="Align to Transform Orientation").mode = 'ALIGN'
|
||||
layout.operator_context = 'EXEC_AREA'
|
||||
layout.operator("object.origin_set",
|
||||
text="Geometry to Origin").type = 'GEOMETRY_ORIGIN'
|
||||
|
||||
|
||||
# Edit Select #
|
||||
class VIEW3D_MT_Select_Edit_Mesh(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("mesh.select_all").action = 'TOGGLE'
|
||||
layout.operator("mesh.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("mesh.select_linked", text="Linked")
|
||||
layout.operator("mesh.faces_select_linked_flat",
|
||||
text="Linked Flat Faces")
|
||||
layout.operator("mesh.select_random", text="Random")
|
||||
layout.operator("mesh.select_nth", text="Every N Number of Verts")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_Edit_Mesh_Select_Trait")
|
||||
layout.menu("VIEW3D_MT_Edit_Mesh_Select_Similar")
|
||||
layout.menu("VIEW3D_MT_Edit_Mesh_Select_More_Less")
|
||||
layout.separator()
|
||||
layout.operator("mesh.select_mirror", text="Mirror")
|
||||
layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
|
||||
layout.operator("mesh.select_axis", text="Side of Active")
|
||||
layout.operator("mesh.shortest_path_select", text="Shortest Path")
|
||||
layout.separator()
|
||||
layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False
|
||||
layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True
|
||||
layout.operator("mesh.loop_to_region")
|
||||
layout.operator("mesh.region_to_loop")
|
||||
|
||||
|
||||
class VIEW3D_MT_Edit_Mesh_Select_Similar(Menu):
|
||||
bl_label = "Select Similar"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_enum("mesh.select_similar", "type")
|
||||
layout.operator("mesh.select_similar_region", text="Face Regions")
|
||||
|
||||
|
||||
class VIEW3D_MT_Edit_Mesh_Select_Trait(Menu):
|
||||
bl_label = "Select All by Trait"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
if context.scene.tool_settings.mesh_select_mode[2] is False:
|
||||
layout.operator("mesh.select_non_manifold", text="Non Manifold")
|
||||
layout.operator("mesh.select_loose", text="Loose Geometry")
|
||||
layout.operator("mesh.select_interior_faces", text="Interior Faces")
|
||||
layout.operator("mesh.select_face_by_sides", text="By Number of Verts")
|
||||
layout.operator("mesh.select_ungrouped", text="Ungrouped Verts")
|
||||
|
||||
|
||||
class VIEW3D_MT_Edit_Mesh_Select_More_Less(Menu):
|
||||
bl_label = "Select More/Less"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("mesh.select_more", text="More")
|
||||
layout.operator("mesh.select_less", text="Less")
|
||||
layout.separator()
|
||||
layout.operator("mesh.select_next_item", text="Next Active")
|
||||
layout.operator("mesh.select_prev_item", text="Previous Active")
|
||||
|
||||
|
||||
# multiple edit select modes.
|
||||
class VIEW3D_OT_selecteditVertex(Operator):
|
||||
bl_idname = "selectedit.vertex"
|
||||
|
@ -433,21 +196,26 @@ class VIEW3D_OT_selecteditVertsEdgesFaces(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
# ********** Normals / Auto Smooth Menu **********
|
||||
# Thanks to marvin.k.breuer for the Autosmooth part of the menu
|
||||
|
||||
def menu_func(self, context):
|
||||
layout = self.layout
|
||||
obj = context.object
|
||||
obj_data = context.active_object.data
|
||||
layout.separator()
|
||||
layout.prop(obj_data, "use_auto_smooth", text="Normals: Auto Smooth")
|
||||
|
||||
# Auto Smooth Angle - two tab spaces to align it with the rest of the menu
|
||||
layout.prop(obj_data, "auto_smooth_angle",
|
||||
text=" Auto Smooth Angle")
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_MirrorMenuEM,
|
||||
VIEW3D_MT_AutoSmooth,
|
||||
VIEW3D_MT_Edit_Mesh,
|
||||
VIEW3D_MT_Edit_Multi,
|
||||
VIEW3D_MT_EditM_Edge,
|
||||
VIEW3D_MT_EditCursorMenu,
|
||||
VIEW3D_MT_UV_Map,
|
||||
VIEW3D_MT_TransformMenuEdit,
|
||||
VIEW3D_MT_Select_Edit_Mesh,
|
||||
VIEW3D_MT_Edit_Mesh_Select_Similar,
|
||||
VIEW3D_MT_Edit_Mesh_Select_Trait,
|
||||
VIEW3D_MT_Edit_Mesh_Select_More_Less,
|
||||
VIEW3D_OT_selecteditVertex,
|
||||
VIEW3D_OT_selecteditEdge,
|
||||
VIEW3D_OT_selecteditFace,
|
||||
|
@ -463,6 +231,7 @@ def register():
|
|||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.VIEW3D_MT_edit_mesh_normals.append(menu_func)
|
||||
|
||||
# Unregister Classes & Hotkeys #
|
||||
def unregister():
|
||||
|
@ -470,6 +239,7 @@ def unregister():
|
|||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
bpy.types.VIEW3D_MT_edit_mesh_normals.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
|
|
@ -30,7 +30,8 @@ from bpy.props import (
|
|||
|
||||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
|
||||
|
||||
from . edit_mesh import *
|
||||
from . view_menus import *
|
||||
# Object Menus #
|
||||
|
||||
# ********** Object Menu **********
|
||||
|
@ -41,119 +42,39 @@ class VIEW3D_MT_Object(Menu):
|
|||
def draw(self, context):
|
||||
layout = self.layout
|
||||
view = context.space_data
|
||||
is_local_view = (view.local_view is not None)
|
||||
|
||||
layout.operator("object.delete", text="Delete...").use_global = False
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_mirror")
|
||||
layout.menu("VIEW3D_MT_object_parent")
|
||||
layout.menu("VIEW3D_MT_Duplicate")
|
||||
layout.operator("object.join")
|
||||
layout.menu("VIEW3D_MT_make_links", text="Make Links")
|
||||
layout.menu("VIEW3D_MT_object_relations")
|
||||
layout.separator()
|
||||
|
||||
if is_local_view:
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
layout.operator("object.move_to_layer", text="Move out of Local View")
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
ob = context.active_object
|
||||
if ob and ob.type == 'GPENCIL' and context.gpencil_data:
|
||||
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to")
|
||||
else:
|
||||
layout.operator_menu_enum("object.convert", "target")
|
||||
|
||||
layout.menu("VIEW3D_MT_make_links", text="Make Links...")
|
||||
layout.menu("VIEW3D_MT_Object_Data_Link")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_AutoSmooth", icon='ALIASED')
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_object_constraints")
|
||||
layout.menu("VIEW3D_MT_object_track")
|
||||
layout.menu("VIEW3D_MT_object_animation")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_object_showhide")
|
||||
layout.separator()
|
||||
layout.operator_menu_enum("object.convert", "target")
|
||||
|
||||
|
||||
# ********** Add Menu **********
|
||||
class VIEW3D_MT_AddMenu(Menu):
|
||||
bl_label = "Add Object"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
|
||||
layout.menu("VIEW3D_MT_mesh_add", text="Add Mesh",
|
||||
icon='OUTLINER_OB_MESH')
|
||||
layout.menu("VIEW3D_MT_curve_add", text="Add Curve",
|
||||
icon='OUTLINER_OB_CURVE')
|
||||
layout.menu("VIEW3D_MT_surface_add", text="Add Surface",
|
||||
icon='OUTLINER_OB_SURFACE')
|
||||
layout.operator_menu_enum("object.metaball_add", "type",
|
||||
icon='OUTLINER_OB_META')
|
||||
layout.operator("object.text_add", text="Add Text",
|
||||
icon='OUTLINER_OB_FONT')
|
||||
layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_armature_add", text="Add Armature",
|
||||
icon='OUTLINER_OB_ARMATURE')
|
||||
layout.operator("object.add", text="Lattice",
|
||||
icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
|
||||
layout.menu("VIEW3D_MT_object_constraints")
|
||||
layout.menu("VIEW3D_MT_object_track")
|
||||
layout.separator()
|
||||
|
||||
layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY')
|
||||
layout.menu("VIEW3D_MT_image_add", text="Image", icon='OUTLINER_OB_IMAGE')
|
||||
layout.menu("VIEW3D_MT_object_rigid_body")
|
||||
layout.menu("VIEW3D_MT_object_quick_effects")
|
||||
layout.separator()
|
||||
|
||||
layout.operator_menu_enum("object.light_add", "type",
|
||||
icon="OUTLINER_OB_LIGHT")
|
||||
layout.menu("VIEW3D_MT_lightprobe_add", icon='OUTLINER_OB_LIGHTPROBE')
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.camera_add", text="Camera",
|
||||
icon='OUTLINER_OB_CAMERA')
|
||||
layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
|
||||
layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
|
||||
layout.separator()
|
||||
|
||||
layout.operator_menu_enum("object.effector_add", "type",
|
||||
text="Force Field",
|
||||
icon='FORCE_FORCE')
|
||||
layout.menu("VIEW3D_MT_object_quick_effects", text="Quick Effects", icon='PARTICLES')
|
||||
layout.separator()
|
||||
|
||||
has_collections = bool(bpy.data.collections)
|
||||
col = layout.column()
|
||||
col.enabled = has_collections
|
||||
|
||||
if not has_collections or len(bpy.data.collections) > 10:
|
||||
col.operator_context = 'INVOKE_REGION_WIN'
|
||||
col.operator(
|
||||
"object.collection_instance_add",
|
||||
text="Collection Instance..." if has_collections else "No Collections to Instance",
|
||||
icon='OUTLINER_OB_GROUP_INSTANCE',
|
||||
)
|
||||
else:
|
||||
col.operator_menu_enum(
|
||||
"object.collection_instance_add",
|
||||
"collection",
|
||||
text="Collection Instance",
|
||||
icon='OUTLINER_OB_GROUP_INSTANCE',
|
||||
)
|
||||
|
||||
|
||||
# ********** Object Mirror **********
|
||||
class VIEW3D_MT_MirrorMenu(Menu):
|
||||
bl_label = "Mirror"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("transform.mirror", text="Interactive Mirror")
|
||||
layout.separator()
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
props = layout.operator("transform.mirror", text="X Global")
|
||||
props.constraint_axis = (True, False, False)
|
||||
props.orient_type = 'GLOBAL'
|
||||
props = layout.operator("transform.mirror", text="Y Global")
|
||||
props.constraint_axis = (False, True, False)
|
||||
props.orient_type = 'GLOBAL'
|
||||
props = layout.operator("transform.mirror", text="Z Global")
|
||||
props.constraint_axis = (False, False, True)
|
||||
props.orient_type = 'GLOBAL'
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
layout.operator("object.delete", text="Delete").use_global = False
|
||||
layout.operator("object.delete", text="Delete Global").use_global = True
|
||||
|
||||
|
||||
# ********** Object Interactive Mode **********
|
||||
|
@ -223,41 +144,6 @@ class VIEW3D_MT_Interactive_Mode_GPencil(Menu):
|
|||
layout.operator(VIEW3D_OT_SetObjectMode.bl_idname, text="Draw", icon="GREASEPENCIL").mode = "PAINT_GPENCIL"
|
||||
layout.operator(VIEW3D_OT_SetObjectMode.bl_idname, text="Weight Paint", icon="WPAINT_HLT").mode = "WEIGHT_GPENCIL"
|
||||
|
||||
# currently unused
|
||||
class VIEW3D_MT_Edit_Gpencil(Menu):
|
||||
bl_label = "GPencil"
|
||||
|
||||
def draw(self, context):
|
||||
toolsettings = context.tool_settings
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True
|
||||
layout.prop_menu_enum(toolsettings.gpencil_sculpt, "tool", text="Sculpt Brush")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_gpencil_transform")
|
||||
layout.operator("transform.mirror", text="Mirror")
|
||||
layout.menu("GPENCIL_MT_snap")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access...
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_gpencil_delete")
|
||||
layout.operator("gpencil.duplicate_move", text="Duplicate")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_select_gpencil")
|
||||
layout.separator()
|
||||
layout.operator("gpencil.copy", text="Copy")
|
||||
layout.operator("gpencil.paste", text="Paste")
|
||||
layout.separator()
|
||||
layout.prop_menu_enum(toolsettings, "proportional_edit")
|
||||
layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
|
||||
layout.separator()
|
||||
layout.operator("gpencil.reveal")
|
||||
layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True
|
||||
layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
|
||||
layout.separator()
|
||||
layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
|
||||
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
|
||||
|
||||
|
||||
# ********** Text Interactive Mode **********
|
||||
class VIEW3D_OT_Interactive_Mode_Text(Operator):
|
||||
|
@ -275,31 +161,6 @@ class VIEW3D_OT_Interactive_Mode_Text(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
# ********** Object Parent **********
|
||||
class VIEW3D_MT_ParentMenu(Menu):
|
||||
bl_label = "Parent"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("object.parent_set", text="Set")
|
||||
layout.operator("object.parent_clear", text="Clear")
|
||||
|
||||
|
||||
# ********** Object Group **********
|
||||
class VIEW3D_MT_GroupMenu(Menu):
|
||||
bl_label = "Group"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("collection.create")
|
||||
layout.operator("collection.objects_add_active")
|
||||
layout.separator()
|
||||
layout.operator("collection.objects_remove")
|
||||
layout.operator("collection.objects_remove_all")
|
||||
layout.operator("collection.objects_remove_active")
|
||||
|
||||
|
||||
# ********** Object Camera Options **********
|
||||
class VIEW3D_MT_Camera_Options(Menu):
|
||||
bl_label = "Camera"
|
||||
|
@ -307,22 +168,12 @@ class VIEW3D_MT_Camera_Options(Menu):
|
|||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
layout.operator("object.camera_add", text="Add Camera", icon='OUTLINER_OB_CAMERA')
|
||||
layout.operator("view3d.object_as_camera", text="Object As Camera", icon='OUTLINER_OB_CAMERA')
|
||||
|
||||
class VIEW3D_MT_Object_Data_Link(Menu):
|
||||
bl_label = "Object Data"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator_menu_enum("object.make_local", "type", text="Make Local...")
|
||||
layout.menu("VIEW3D_MT_make_single_user")
|
||||
layout.operator("object.proxy_make", text="Make Proxy...")
|
||||
layout.operator("object.make_dupli_face")
|
||||
layout.separator()
|
||||
layout.operator("object.data_transfer")
|
||||
layout.operator("object.datalayout_transfer")
|
||||
layout.operator("object.select_camera", text="Select Camera")
|
||||
layout.operator("object.camera_add", text="Add Camera")
|
||||
layout.operator("view3d.view_camera", text="View Camera")
|
||||
layout.operator("view3d.camera_to_view", text="Camera to View")
|
||||
layout.operator("view3d.camera_to_view_selected", text="Camera to Selected")
|
||||
layout.operator("view3d.object_as_camera", text="Object As Camera")
|
||||
|
||||
|
||||
class VIEW3D_MT_Duplicate(Menu):
|
||||
|
@ -371,21 +222,51 @@ class VIEW3D_OT_SetObjectMode(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
# currently unused
|
||||
class VIEW3D_MT_Edit_Gpencil(Menu):
|
||||
bl_label = "GPencil"
|
||||
|
||||
def draw(self, context):
|
||||
toolsettings = context.tool_settings
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True
|
||||
layout.prop_menu_enum(toolsettings.gpencil_sculpt, "tool", text="Sculpt Brush")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_gpencil_transform")
|
||||
layout.operator("transform.mirror", text="Mirror")
|
||||
layout.menu("GPENCIL_MT_snap")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access...
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_edit_gpencil_delete")
|
||||
layout.operator("gpencil.duplicate_move", text="Duplicate")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_select_gpencil")
|
||||
layout.separator()
|
||||
layout.operator("gpencil.copy", text="Copy")
|
||||
layout.operator("gpencil.paste", text="Paste")
|
||||
layout.separator()
|
||||
layout.prop_menu_enum(toolsettings, "proportional_edit")
|
||||
layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
|
||||
layout.separator()
|
||||
layout.operator("gpencil.reveal")
|
||||
layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True
|
||||
layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
|
||||
layout.separator()
|
||||
layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
|
||||
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_AddMenu,
|
||||
VIEW3D_MT_Object,
|
||||
VIEW3D_MT_MirrorMenu,
|
||||
VIEW3D_MT_ParentMenu,
|
||||
VIEW3D_MT_GroupMenu,
|
||||
VIEW3D_MT_UndoS,
|
||||
VIEW3D_MT_Camera_Options,
|
||||
VIEW3D_MT_InteractiveMode,
|
||||
VIEW3D_MT_InteractiveModeOther,
|
||||
VIEW3D_OT_SetObjectMode,
|
||||
VIEW3D_MT_Object_Data_Link,
|
||||
VIEW3D_MT_Duplicate,
|
||||
VIEW3D_OT_Interactive_Mode_Text,
|
||||
VIEW3D_OT_Interactive_Mode_Grease_Pencil,
|
||||
|
|
|
@ -1,339 +0,0 @@
|
|||
# ##### 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 #####
|
||||
# Contributed to by: meta-androcto, JayDez, sim88, sam, lijenstina, mkb, wisaac, CoDEmanX #
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Menu,
|
||||
)
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
StringProperty,
|
||||
)
|
||||
|
||||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
from .object_menus import *
|
||||
|
||||
# Brushes Menu's #
|
||||
# Thanks to CoDEmanX for the code
|
||||
class VIEW3D_MT_Brush_Selection(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:
|
||||
layout.label(text="No Brushes currently available", icon="INFO")
|
||||
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_Brush_Settings(Menu):
|
||||
bl_label = "Brush Settings"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = UnifiedPaintPanel.paint_settings(context)
|
||||
brush = getattr(settings, "brush", None)
|
||||
|
||||
ups = context.tool_settings.unified_paint_settings
|
||||
layout.prop(ups, "use_unified_size", text="Unified Size")
|
||||
layout.prop(ups, "use_unified_strength", text="Unified Strength")
|
||||
if context.image_paint_object or context.vertex_paint_object:
|
||||
layout.prop(ups, "use_unified_color", text="Unified Color")
|
||||
layout.separator()
|
||||
|
||||
if not brush:
|
||||
layout.label(text="No Brushes currently available", icon="INFO")
|
||||
return
|
||||
|
||||
layout.menu("VIEW3D_MT_brush_paint_modes")
|
||||
|
||||
if context.sculpt_object:
|
||||
sculpt_tool = brush.sculpt_tool
|
||||
|
||||
layout.separator()
|
||||
layout.operator_menu_enum("brush.curve_preset", "shape", text="Curve Preset")
|
||||
layout.separator()
|
||||
|
||||
if sculpt_tool != 'GRAB':
|
||||
layout.prop_menu_enum(brush, "stroke_method")
|
||||
|
||||
if sculpt_tool in {'DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'}:
|
||||
layout.prop_menu_enum(brush, "direction")
|
||||
|
||||
if sculpt_tool == 'LAYER':
|
||||
layout.prop(brush, "use_persistent")
|
||||
layout.operator("sculpt.set_persistent_base")
|
||||
|
||||
|
||||
# Sculpt Menu's #
|
||||
class VIEW3D_MT_Sculpts(Menu):
|
||||
bl_label = "Sculpt"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
toolsettings = context.tool_settings
|
||||
sculpt = toolsettings.sculpt
|
||||
|
||||
layout.prop(sculpt, "use_symmetry_x")
|
||||
layout.prop(sculpt, "use_symmetry_y")
|
||||
layout.prop(sculpt, "use_symmetry_z")
|
||||
|
||||
layout.separator()
|
||||
layout.prop(sculpt, "lock_x")
|
||||
layout.prop(sculpt, "lock_y")
|
||||
layout.prop(sculpt, "lock_z")
|
||||
|
||||
layout.separator()
|
||||
layout.prop(sculpt, "use_threaded", text="Threaded Sculpt")
|
||||
layout.prop(sculpt, "show_low_resolution")
|
||||
layout.prop(sculpt, "use_deform_only")
|
||||
|
||||
layout.separator()
|
||||
layout.prop(sculpt, "show_brush")
|
||||
|
||||
|
||||
class VIEW3D_MT_Hide_Masks(Menu):
|
||||
bl_label = "Hide/Mask"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
props = layout.operator("paint.mask_lasso_gesture", text="Lasso Mask")
|
||||
layout.separator()
|
||||
props = layout.operator("view3d.select_box", text="Box Mask")
|
||||
props = layout.operator("paint.hide_show", text="Box Hide")
|
||||
props.action = 'HIDE'
|
||||
props.area = 'INSIDE'
|
||||
|
||||
props = layout.operator("paint.hide_show", text="Box Show")
|
||||
props.action = 'SHOW'
|
||||
props.area = 'INSIDE'
|
||||
layout.separator()
|
||||
|
||||
props = layout.operator("paint.mask_flood_fill", text="Fill Mask")
|
||||
props.mode = 'VALUE'
|
||||
props.value = 1
|
||||
|
||||
props = layout.operator("paint.mask_flood_fill", text="Clear Mask")
|
||||
props.mode = 'VALUE'
|
||||
props.value = 0
|
||||
|
||||
layout.operator("paint.mask_flood_fill", text="Invert Mask").mode = 'INVERT'
|
||||
layout.separator()
|
||||
|
||||
props = layout.operator("paint.hide_show", text="Show All", icon="RESTRICT_VIEW_OFF")
|
||||
props.action = 'SHOW'
|
||||
props.area = 'ALL'
|
||||
|
||||
props = layout.operator("paint.hide_show", text="Hide Masked", icon="RESTRICT_VIEW_ON")
|
||||
props.area = 'MASKED'
|
||||
props.action = 'HIDE'
|
||||
|
||||
|
||||
# Sculpt Specials Menu (Thanks to marvin.k.breuer) #
|
||||
class VIEW3D_MT_Sculpt_Specials(Menu):
|
||||
bl_label = "Sculpt Specials"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.tool_settings
|
||||
|
||||
if context.sculpt_object.use_dynamic_topology_sculpting:
|
||||
layout.operator("sculpt.dynamic_topology_toggle",
|
||||
icon='X', text="Disable Dyntopo")
|
||||
layout.separator()
|
||||
|
||||
if (settings.sculpt.detail_type_method == 'CONSTANT'):
|
||||
layout.prop(settings.sculpt, "constant_detail", text="Const.")
|
||||
layout.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
|
||||
else:
|
||||
layout.prop(settings.sculpt, "detail_size", text="Detail")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("sculpt.symmetrize", icon='ARROW_LEFTRIGHT')
|
||||
layout.prop(settings.sculpt, "symmetrize_direction", "")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("sculpt.optimize")
|
||||
if (settings.sculpt.detail_type_method == 'CONSTANT'):
|
||||
layout.operator("sculpt.detail_flood_fill")
|
||||
layout.separator()
|
||||
|
||||
layout.prop(settings.sculpt, "detail_refine_method", text="")
|
||||
layout.prop(settings.sculpt, "detail_type_method", text="")
|
||||
layout.separator()
|
||||
layout.prop(settings.sculpt, "use_smooth_shading", "Smooth")
|
||||
else:
|
||||
layout.operator("sculpt.dynamic_topology_toggle", text="Enable Dyntopo")
|
||||
|
||||
|
||||
# Vertex Color Menu #
|
||||
class VIEW3D_MT_Vertex_Colors(Menu):
|
||||
bl_label = "Vertex Colors"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("paint.vertex_color_set")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("paint.vertex_color_smooth")
|
||||
layout.operator("paint.vertex_color_dirt")
|
||||
|
||||
|
||||
# Weight Paint Menu #
|
||||
class VIEW3D_MT_Paint_Weights(Menu):
|
||||
bl_label = "Weights"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("paint.weight_from_bones",
|
||||
text="Assign Automatic From Bones").type = 'AUTOMATIC'
|
||||
layout.operator("paint.weight_from_bones",
|
||||
text="Assign From Bone Envelopes").type = 'ENVELOPES'
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.vertex_group_normalize_all", text="Normalize All")
|
||||
layout.operator("object.vertex_group_normalize", text="Normalize")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.vertex_group_mirror", text="Mirror")
|
||||
layout.operator("object.vertex_group_invert", text="Invert")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.vertex_group_clean", text="Clean")
|
||||
layout.operator("object.vertex_group_quantize", text="Quantize")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.vertex_group_levels", text="Levels")
|
||||
layout.operator("object.vertex_group_smooth", text="Smooth")
|
||||
layout.separator()
|
||||
|
||||
props = layout.operator("object.data_transfer", text="Transfer Weights")
|
||||
props.use_reverse_transfer = True
|
||||
props.data_type = 'VGROUP_WEIGHTS'
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.vertex_group_limit_total", text="Limit Total")
|
||||
layout.operator("object.vertex_group_fix", text="Fix Deforms")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("paint.weight_set")
|
||||
|
||||
|
||||
class VIEW3D_MT_Angle_Control(Menu):
|
||||
bl_label = "Angle Control"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
settings = UnifiedPaintPanel.paint_settings(context)
|
||||
if not settings:
|
||||
return False
|
||||
|
||||
brush = settings.brush
|
||||
tex_slot = brush.texture_slot
|
||||
|
||||
return tex_slot.has_texture_angle and tex_slot.has_texture_angle_source
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
settings = UnifiedPaintPanel.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
sculpt = (context.sculpt_object is not None)
|
||||
|
||||
tex_slot = brush.texture_slot
|
||||
|
||||
layout.prop(tex_slot, "use_rake", text="Rake")
|
||||
|
||||
if brush.brush_capabilities.has_random_texture_angle and tex_slot.has_random_texture_angle:
|
||||
if sculpt:
|
||||
if brush.sculpt_capabilities.has_random_texture_angle:
|
||||
layout.prop(tex_slot, "use_random", text="Random")
|
||||
else:
|
||||
layout.prop(tex_slot, "use_random", text="Random")
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_Angle_Control,
|
||||
VIEW3D_MT_Sculpt_Specials,
|
||||
VIEW3D_MT_Brush_Settings,
|
||||
VIEW3D_MT_Brush_Selection,
|
||||
VIEW3D_MT_Sculpts,
|
||||
VIEW3D_MT_Hide_Masks,
|
||||
VIEW3D_MT_Vertex_Colors,
|
||||
VIEW3D_MT_Paint_Weights,
|
||||
)
|
||||
|
||||
|
||||
# Register Classes & Hotkeys #
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
|
||||
# Unregister Classes & Hotkeys #
|
||||
def unregister():
|
||||
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -1,440 +0,0 @@
|
|||
# ##### 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 #####
|
||||
# Contributed to by: meta-androcto, JayDez, sim88, sam, lijenstina, mkb, wisaac, CoDEmanX #
|
||||
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Menu,
|
||||
)
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
StringProperty,
|
||||
)
|
||||
|
||||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
from .object_menus import *
|
||||
|
||||
# Select Menu's #
|
||||
|
||||
# Object Select #
|
||||
class VIEW3D_MT_Select_Object(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("object.select_all", text="All").action = 'SELECT'
|
||||
layout.operator("object.select_all", text="None").action = 'DESELECT'
|
||||
layout.operator("object.select_all", text="Invert").action = 'INVERT'
|
||||
layout.separator()
|
||||
layout.operator("object.select_camera", text="Select Active Camera")
|
||||
layout.operator("object.select_mirror", text="Mirror Selection")
|
||||
layout.operator("object.select_random", text="Select Random")
|
||||
layout.separator()
|
||||
layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...")
|
||||
layout.operator_menu_enum("object.select_grouped", "type", text="Select Grouped")
|
||||
layout.operator_menu_enum("object.select_linked", "type", text="Select Linked")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_Select_Object_More_Less", text="More/Less")
|
||||
layout.operator("object.select_pattern", text="Select Pattern...")
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Object_More_Less(Menu):
|
||||
bl_label = "Select More/Less"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("object.select_more", text="More")
|
||||
layout.operator("object.select_less", text="Less")
|
||||
layout.separator()
|
||||
props = layout.operator("object.select_hierarchy", text="Parent")
|
||||
props.extend = False
|
||||
props.direction = 'PARENT'
|
||||
props = layout.operator("object.select_hierarchy", text="Child")
|
||||
props.extend = False
|
||||
props.direction = 'CHILD'
|
||||
layout.separator()
|
||||
props = layout.operator("object.select_hierarchy", text="Extend Parent")
|
||||
props.extend = True
|
||||
props.direction = 'PARENT'
|
||||
props = layout.operator("object.select_hierarchy", text="Extend Child")
|
||||
props.extend = True
|
||||
props.direction = 'CHILD'
|
||||
|
||||
|
||||
# Edit Curve Select #
|
||||
class VIEW3D_MT_Select_Edit_Curve(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("curve.select_all").action = 'TOGGLE'
|
||||
layout.operator("curve.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("curve.select_nth")
|
||||
layout.separator()
|
||||
layout.operator("curve.select_random")
|
||||
layout.operator("curve.select_linked", text="Select Linked")
|
||||
layout.operator("curve.select_similar", text="Select Similar")
|
||||
layout.operator("curve.de_select_first")
|
||||
layout.operator("curve.de_select_last")
|
||||
layout.operator("curve.select_next")
|
||||
layout.operator("curve.select_previous")
|
||||
layout.separator()
|
||||
layout.operator("curve.select_more")
|
||||
layout.operator("curve.select_less")
|
||||
|
||||
|
||||
# Armature Select #
|
||||
class VIEW3D_MT_SelectArmatureMenu(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("armature.select_all")
|
||||
layout.operator("armature.select_inverse", text="Inverse")
|
||||
layout.operator("armature.select_hierarchy",
|
||||
text="Parent").direction = 'PARENT'
|
||||
layout.operator("armature.select_hierarchy",
|
||||
text="Child").direction = 'CHILD'
|
||||
props = layout.operator("armature.select_hierarchy",
|
||||
text="Extend Parent")
|
||||
props.extend = True
|
||||
props.direction = 'PARENT'
|
||||
props = layout.operator("armature.select_hierarchy",
|
||||
text="Extend Child")
|
||||
props.extend = True
|
||||
props.direction = 'CHILD'
|
||||
layout.operator("object.select_pattern", text="Select Pattern...")
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Edit_Armature(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("armature.select_all").action = 'TOGGLE'
|
||||
layout.operator("armature.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("armature.select_mirror", text="Mirror").extend = False
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("armature.select_more", text="More")
|
||||
layout.operator("armature.select_less", text="Less")
|
||||
|
||||
layout.separator()
|
||||
|
||||
props = layout.operator("armature.select_hierarchy", text="Parent")
|
||||
props.extend = False
|
||||
props.direction = 'PARENT'
|
||||
|
||||
props = layout.operator("armature.select_hierarchy", text="Child")
|
||||
props.extend = False
|
||||
props.direction = 'CHILD'
|
||||
|
||||
layout.separator()
|
||||
|
||||
props = layout.operator("armature.select_hierarchy", text="Extend Parent")
|
||||
props.extend = True
|
||||
props.direction = 'PARENT'
|
||||
|
||||
props = layout.operator("armature.select_hierarchy", text="Extend Child")
|
||||
props.extend = True
|
||||
props.direction = 'CHILD'
|
||||
|
||||
layout.operator_menu_enum("armature.select_similar", "type", text="Similar")
|
||||
layout.operator("object.select_pattern", text="Select Pattern...")
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Pose(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("pose.select_all").action = 'TOGGLE'
|
||||
layout.operator("pose.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("pose.select_mirror", text="Flip Active")
|
||||
layout.operator("pose.select_constraint_target",
|
||||
text="Constraint Target")
|
||||
layout.separator()
|
||||
layout.operator("pose.select_linked", text="Linked")
|
||||
layout.operator("pose.select_hierarchy",
|
||||
text="Parent").direction = 'PARENT'
|
||||
layout.operator("pose.select_hierarchy",
|
||||
text="Child").direction = 'CHILD'
|
||||
props = layout.operator("pose.select_hierarchy", text="Extend Parent")
|
||||
props.extend = True
|
||||
props.direction = 'PARENT'
|
||||
props = layout.operator("pose.select_hierarchy", text="Extend Child")
|
||||
props.extend = True
|
||||
props.direction = 'CHILD'
|
||||
layout.operator_menu_enum("pose.select_grouped", "type",
|
||||
text="Grouped")
|
||||
layout.separator()
|
||||
layout.operator("object.select_pattern", text="Select Pattern...")
|
||||
layout.menu("VIEW3D_MT_select_pose_more_less")
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Pose_More_Less(Menu):
|
||||
bl_label = "Select More/Less"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = layout.operator("pose.select_hierarchy", text="Parent")
|
||||
props.extend = False
|
||||
props.direction = 'PARENT'
|
||||
|
||||
props = layout.operator("pose.select_hierarchy", text="Child")
|
||||
props.extend = False
|
||||
props.direction = 'CHILD'
|
||||
|
||||
props = layout.operator("pose.select_hierarchy", text="Extend Parent")
|
||||
props.extend = True
|
||||
props.direction = 'PARENT'
|
||||
|
||||
props = layout.operator("pose.select_hierarchy", text="Extend Child")
|
||||
props.extend = True
|
||||
props.direction = 'CHILD'
|
||||
|
||||
|
||||
|
||||
# Surface Select #
|
||||
class VIEW3D_MT_Select_Edit_Surface(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("curve.select_all").action = 'TOGGLE'
|
||||
layout.operator("curve.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("curve.select_random")
|
||||
layout.operator("curve.select_nth")
|
||||
layout.operator("curve.select_linked", text="Select Linked")
|
||||
layout.operator("curve.select_similar", text="Select Similar")
|
||||
layout.operator("curve.select_row")
|
||||
layout.separator()
|
||||
layout.operator("curve.select_more")
|
||||
layout.operator("curve.select_less")
|
||||
|
||||
|
||||
# Metaball Select #
|
||||
class VIEW3D_MT_SelectMetaball(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("mball.select_all").action = 'TOGGLE'
|
||||
layout.operator("mball.select_all").action = 'INVERT'
|
||||
layout.operator("mball.select_random_metaelems")
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Edit_Metaball(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.operator("mball.select_all").action = 'TOGGLE'
|
||||
layout.operator("mball.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("mball.select_random_metaelems")
|
||||
layout.operator_menu_enum("mball.select_similar", "type", text="Similar")
|
||||
|
||||
|
||||
# Particle Select #
|
||||
class VIEW3D_MT_Selection_Mode_Particle(Menu):
|
||||
bl_label = "Particle Select and Display Mode"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
toolsettings = context.tool_settings
|
||||
|
||||
layout.prop(toolsettings.particle_edit, "select_mode", expand=True)
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Particle(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("particle.select_all").action = 'TOGGLE'
|
||||
layout.operator("particle.select_linked")
|
||||
layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
|
||||
|
||||
layout.separator()
|
||||
layout.operator("particle.select_more")
|
||||
layout.operator("particle.select_less")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("particle.select_random")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("particle.select_roots", text="Roots")
|
||||
layout.operator("particle.select_tips", text="Tips")
|
||||
|
||||
|
||||
# Lattice Edit Select #
|
||||
class VIEW3D_MT_Select_Edit_Lattice(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.separator()
|
||||
layout.operator("lattice.select_mirror")
|
||||
layout.operator("lattice.select_random")
|
||||
layout.operator("lattice.select_all").action = 'TOGGLE'
|
||||
layout.operator("lattice.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.separator()
|
||||
layout.operator("lattice.select_ungrouped", text="Ungrouped Verts")
|
||||
|
||||
|
||||
# Grease Pencil Select #
|
||||
class VIEW3D_MT_Select_Gpencil(Menu):
|
||||
# To Do: used in 3dview header might work if mapped to mouse
|
||||
# Not in Class List yet
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("gpencil.select_box")
|
||||
layout.operator("gpencil.select_circle")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("gpencil.select_all", text="(De)select All").action = 'TOGGLE'
|
||||
layout.operator("gpencil.select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("gpencil.select_linked", text="Linked")
|
||||
# layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
|
||||
layout.operator("gpencil.select_grouped", text="Grouped")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("gpencil.select_more")
|
||||
layout.operator("gpencil.select_less")
|
||||
|
||||
|
||||
# Text Select #
|
||||
class VIEW3D_MT_Select_Edit_Text(Menu):
|
||||
# To Do: used in 3dview header might work if mapped to mouse
|
||||
# Not in Class List yet
|
||||
bl_label = "Edit"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("font.text_copy", text="Copy")
|
||||
layout.operator("font.text_cut", text="Cut")
|
||||
layout.operator("font.text_paste", text="Paste")
|
||||
layout.operator("font.text_paste_from_file")
|
||||
layout.operator("font.select_all")
|
||||
|
||||
|
||||
# Paint Mode Menus #
|
||||
class VIEW3D_MT_Select_Paint_Mask(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.operator("paint.face_select_all").action = 'TOGGLE'
|
||||
layout.operator("paint.face_select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("paint.face_select_linked", text="Linked")
|
||||
|
||||
|
||||
class VIEW3D_MT_Select_Paint_Mask_Vertex(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("view3d.select_box")
|
||||
layout.operator("view3d.select_circle")
|
||||
layout.operator("paint.vert_select_all").action = 'TOGGLE'
|
||||
layout.operator("paint.vert_select_all", text="Inverse").action = 'INVERT'
|
||||
layout.operator("paint.vert_select_ungrouped", text="Ungrouped Verts")
|
||||
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_Select_Object,
|
||||
VIEW3D_MT_Select_Object_More_Less,
|
||||
VIEW3D_MT_Select_Edit_Curve,
|
||||
VIEW3D_MT_SelectArmatureMenu,
|
||||
VIEW3D_MT_Select_Edit_Armature,
|
||||
VIEW3D_MT_Select_Pose,
|
||||
VIEW3D_MT_Select_Pose_More_Less,
|
||||
VIEW3D_MT_Select_Edit_Surface,
|
||||
VIEW3D_MT_SelectMetaball,
|
||||
VIEW3D_MT_Select_Edit_Metaball,
|
||||
VIEW3D_MT_Select_Particle,
|
||||
VIEW3D_MT_Select_Edit_Lattice,
|
||||
VIEW3D_MT_Select_Paint_Mask,
|
||||
VIEW3D_MT_Select_Paint_Mask_Vertex,
|
||||
VIEW3D_MT_Selection_Mode_Particle,
|
||||
VIEW3D_MT_Select_Gpencil,
|
||||
VIEW3D_MT_Select_Edit_Text,
|
||||
)
|
||||
|
||||
|
||||
# Register Classes & Hotkeys #
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
|
||||
# Unregister Classes & Hotkeys #
|
||||
def unregister():
|
||||
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
|
@ -20,114 +20,114 @@
|
|||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Menu,
|
||||
)
|
||||
Operator,
|
||||
Menu,
|
||||
)
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
StringProperty,
|
||||
)
|
||||
BoolProperty,
|
||||
StringProperty,
|
||||
)
|
||||
from .object_menus import *
|
||||
|
||||
# ********** Object Snap Cursor **********
|
||||
class VIEW3D_MT_Snap_Context(Menu):
|
||||
bl_label = "Snapping"
|
||||
bl_label = "Snapping"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
toolsettings = context.tool_settings
|
||||
layout.prop(toolsettings, "use_snap")
|
||||
layout.prop(toolsettings, "snap_elements", expand=True)
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
toolsettings = context.tool_settings
|
||||
layout.prop(toolsettings, "use_snap")
|
||||
layout.prop(toolsettings, "snap_elements", expand=True)
|
||||
|
||||
|
||||
class VIEW3D_MT_Snap_Origin(Menu):
|
||||
bl_label = "Snap Origin"
|
||||
bl_label = "Snap Origin"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'EXEC_AREA'
|
||||
layout.operator("object.origin_set",
|
||||
text="Geometry to Origin").type = 'GEOMETRY_ORIGIN'
|
||||
layout.separator()
|
||||
layout.operator("object.origin_set",
|
||||
text="Origin to Geometry").type = 'ORIGIN_GEOMETRY'
|
||||
layout.operator("object.origin_set",
|
||||
text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR'
|
||||
layout.operator("object.origin_set",
|
||||
text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS'
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'EXEC_AREA'
|
||||
layout.operator("object.origin_set",
|
||||
text="Geometry to Origin").type = 'GEOMETRY_ORIGIN'
|
||||
layout.separator()
|
||||
layout.operator("object.origin_set",
|
||||
text="Origin to Geometry").type = 'ORIGIN_GEOMETRY'
|
||||
layout.operator("object.origin_set",
|
||||
text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR'
|
||||
layout.operator("object.origin_set",
|
||||
text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS'
|
||||
|
||||
|
||||
class VIEW3D_MT_CursorMenu(Menu):
|
||||
bl_label = "Snap"
|
||||
bl_label = "Snap To"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.menu("VIEW3D_MT_Snap_Origin")
|
||||
layout.menu("VIEW3D_MT_Snap_Context")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_cursor_to_selected",
|
||||
text="Cursor to Selected")
|
||||
layout.operator("view3d.snap_cursor_to_center",
|
||||
text="Cursor to World Origin")
|
||||
layout.operator("view3d.snap_cursor_to_grid",
|
||||
text="Cursor to Grid")
|
||||
layout.operator("view3d.snap_cursor_to_active",
|
||||
text="Cursor to Active")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor").use_offset = False
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor (Keep Offset)").use_offset = True
|
||||
layout.operator("view3d.snap_selected_to_grid",
|
||||
text="Selection to Grid")
|
||||
layout.operator("view3d.snap_cursor_selected_to_center",
|
||||
text="Selection and Cursor to World Origin")
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.menu("VIEW3D_MT_Snap_Origin")
|
||||
layout.menu("VIEW3D_MT_Snap_Context")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_cursor_to_selected",
|
||||
text="Cursor to Selected")
|
||||
layout.operator("view3d.snap_cursor_to_center",
|
||||
text="Cursor to World Origin")
|
||||
layout.operator("view3d.snap_cursor_to_grid",
|
||||
text="Cursor to Grid")
|
||||
layout.operator("view3d.snap_cursor_to_active",
|
||||
text="Cursor to Active")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor").use_offset = False
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor (Keep Offset)").use_offset = True
|
||||
layout.operator("view3d.snap_selected_to_grid",
|
||||
text="Selection to Grid")
|
||||
layout.operator("view3d.snap_cursor_selected_to_center",
|
||||
text="Selection and Cursor to World Origin")
|
||||
|
||||
|
||||
class VIEW3D_MT_CursorMenuLite(Menu):
|
||||
bl_label = "Snap Cursor"
|
||||
bl_label = "Snap to"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.menu("VIEW3D_MT_Snap_Origin")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_cursor_to_selected",
|
||||
text="Cursor to Selected")
|
||||
layout.operator("view3d.snap_cursor_to_center",
|
||||
text="Cursor to World Origin")
|
||||
layout.operator("view3d.snap_cursor_to_grid",
|
||||
text="Cursor to Grid")
|
||||
layout.operator("view3d.snap_cursor_to_active",
|
||||
text="Cursor to Active")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor").use_offset = False
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor (Keep Offset)").use_offset = True
|
||||
layout.operator("view3d.snap_selected_to_grid",
|
||||
text="Selection to Grid")
|
||||
layout.operator("view3d.snap_cursor_selected_to_center",
|
||||
text="Selection and Cursor to World Origin")
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.menu("VIEW3D_MT_Snap_Origin")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_cursor_to_selected",
|
||||
text="Cursor to Selected")
|
||||
layout.operator("view3d.snap_cursor_to_center",
|
||||
text="Cursor to World Origin")
|
||||
layout.operator("view3d.snap_cursor_to_grid",
|
||||
text="Cursor to Grid")
|
||||
layout.operator("view3d.snap_cursor_to_active",
|
||||
text="Cursor to Active")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor").use_offset = False
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor (Keep Offset)").use_offset = True
|
||||
layout.operator("view3d.snap_selected_to_grid",
|
||||
text="Selection to Grid")
|
||||
layout.operator("view3d.snap_cursor_selected_to_center",
|
||||
text="Selection and Cursor to World Origin")
|
||||
|
||||
|
||||
# Code thanks to Isaac Weaver (wisaac) D1963
|
||||
class VIEW3D_OT_SnapCursSelToCenter(Operator):
|
||||
bl_idname = "view3d.snap_cursor_selected_to_center"
|
||||
bl_label = "Snap Cursor & Selection to World Origin"
|
||||
bl_description = ("Snap 3D cursor and selected objects to the center \n"
|
||||
"Works only in Object Mode")
|
||||
bl_idname = "view3d.snap_cursor_selected_to_center"
|
||||
bl_label = "Snap Cursor & Selection to World Origin"
|
||||
bl_description = ("Snap 3D cursor and selected objects to the center \n"
|
||||
"Works only in Object Mode")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.area.type == "VIEW_3D" and context.mode == "OBJECT")
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.area.type == "VIEW_3D" and context.mode == "OBJECT")
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.cursor.location = (0, 0, 0)
|
||||
for obj in context.selected_objects:
|
||||
obj.location = (0, 0, 0)
|
||||
return {'FINISHED'}
|
||||
def execute(self, context):
|
||||
context.scene.cursor.location = (0, 0, 0)
|
||||
for obj in context.selected_objects:
|
||||
obj.location = (0, 0, 0)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Cursor Edge Intersection Defs #
|
||||
|
@ -239,32 +239,64 @@ class VIEW3D_OT_SetOriginToSelected(Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ********** Edit Mesh Cursor **********
|
||||
class VIEW3D_MT_EditCursorMenu(Menu):
|
||||
bl_label = "Snap To"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("object.setorigintoselected",
|
||||
text="Origin to Selected V/F/E")
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_Snap_Origin")
|
||||
layout.menu("VIEW3D_MT_Snap_Context")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_cursor_to_selected",
|
||||
text="Cursor to Selected")
|
||||
layout.operator("view3d.snap_cursor_to_center",
|
||||
text="Cursor to World Origin")
|
||||
layout.operator("view3d.snap_cursor_to_grid",
|
||||
text="Cursor to Grid")
|
||||
layout.operator("view3d.snap_cursor_to_active",
|
||||
text="Cursor to Active")
|
||||
layout.operator("view3d.snap_cursor_to_edge_intersection",
|
||||
text="Cursor to Edge Intersection")
|
||||
layout.separator()
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor").use_offset = False
|
||||
layout.operator("view3d.snap_selected_to_cursor",
|
||||
text="Selection to Cursor (Keep Offset)").use_offset = True
|
||||
layout.operator("view3d.snap_selected_to_grid",
|
||||
text="Selection to Grid")
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_CursorMenu,
|
||||
VIEW3D_MT_CursorMenuLite,
|
||||
VIEW3D_MT_Snap_Context,
|
||||
VIEW3D_MT_Snap_Origin,
|
||||
VIEW3D_OT_SnapCursSelToCenter,
|
||||
VIEW3D_OT_CursorToEdgeIntersection,
|
||||
VIEW3D_OT_SetOriginToSelected,
|
||||
VIEW3D_MT_CursorMenu,
|
||||
VIEW3D_MT_CursorMenuLite,
|
||||
VIEW3D_MT_Snap_Context,
|
||||
VIEW3D_MT_Snap_Origin,
|
||||
VIEW3D_OT_SnapCursSelToCenter,
|
||||
VIEW3D_OT_CursorToEdgeIntersection,
|
||||
VIEW3D_OT_SetOriginToSelected,
|
||||
VIEW3D_MT_EditCursorMenu,
|
||||
)
|
||||
|
||||
|
||||
# Register Classes & Hotkeys #
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
|
||||
# Unregister Classes & Hotkeys #
|
||||
def unregister():
|
||||
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
register()
|
||||
|
|
|
@ -74,7 +74,11 @@ class VIEW3D_MT_TransformMenuLite(Menu):
|
|||
layout.separator()
|
||||
layout.operator("transform.transform",
|
||||
text="Align to Transform Orientation").mode = 'ALIGN'
|
||||
|
||||
layout.separator()
|
||||
layout.operator("object.align")
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
layout.operator("transform.transform",
|
||||
text="Align to Transform Orientation").mode = 'ALIGN'
|
||||
|
||||
# ********** Transform Camera **********
|
||||
class VIEW3D_MT_TransformMenuCamera(Menu):
|
||||
|
@ -118,61 +122,11 @@ class VIEW3D_MT_TransformMenuArmature(Menu):
|
|||
text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS'
|
||||
|
||||
|
||||
# ********** Transform Armature Edit **********
|
||||
class VIEW3D_MT_TransformMenuArmatureEdit(Menu):
|
||||
bl_label = "Transform"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("transform.translate", text="Move")
|
||||
layout.operator("transform.rotate", text="Rotate")
|
||||
layout.operator("transform.resize", text="Scale")
|
||||
layout.separator()
|
||||
layout.operator("transform.tosphere", text="To Sphere")
|
||||
layout.operator("transform.shear", text="Shear")
|
||||
layout.operator("transform.bend", text="Bend")
|
||||
layout.operator("transform.push_pull", text="Push/Pull")
|
||||
layout.operator("transform.vertex_warp", text="Warp")
|
||||
layout.separator()
|
||||
layout.operator("transform.vertex_random", text="Randomize")
|
||||
layout.operator("armature.align")
|
||||
layout.operator_context = 'EXEC_AREA'
|
||||
|
||||
|
||||
# ********** Transform Armature Pose **********
|
||||
class VIEW3D_MT_TransformMenuArmaturePose(Menu):
|
||||
bl_label = "Transform"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("transform.translate", text="Move")
|
||||
layout.operator("transform.rotate", text="Rotate")
|
||||
layout.operator("transform.resize", text="Scale")
|
||||
layout.separator()
|
||||
layout.operator("pose.transforms_clear", text="Clear All")
|
||||
layout.operator("pose.loc_clear", text="Location")
|
||||
layout.operator("pose.rot_clear", text="Rotation")
|
||||
layout.operator("pose.scale_clear", text="Scale")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("pose.user_transforms_clear", text="Reset unkeyed")
|
||||
obj = context.object
|
||||
if obj.type == 'ARMATURE' and obj.mode in {'EDIT', 'POSE'}:
|
||||
if obj.data.display_type == 'BBONE':
|
||||
layout.operator("transform.transform", text="Scale BBone").mode = 'BONE_SIZE'
|
||||
elif obj.data.display_type == 'ENVELOPE':
|
||||
layout.operator("transform.transform", text="Scale Envelope Distance").mode = 'BONE_SIZE'
|
||||
layout.operator("transform.transform", text="Scale Radius").mode = 'BONE_ENVELOPE'
|
||||
|
||||
|
||||
# List The Classes #
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_TransformMenu,
|
||||
VIEW3D_MT_TransformMenuArmature,
|
||||
VIEW3D_MT_TransformMenuArmatureEdit,
|
||||
VIEW3D_MT_TransformMenuArmaturePose,
|
||||
VIEW3D_MT_TransformMenuLite,
|
||||
VIEW3D_MT_TransformMenuCamera,
|
||||
)
|
||||
|
|
|
@ -28,8 +28,46 @@ from bpy.props import (
|
|||
StringProperty,
|
||||
)
|
||||
|
||||
from . edit_mesh import *
|
||||
|
||||
# View Menu's #
|
||||
class VIEW3D_MT_View_Menu(Menu):
|
||||
bl_label = "View"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
view = context.space_data
|
||||
|
||||
layout.menu("VIEW3D_MT_view_viewpoint")
|
||||
layout.menu("VIEW3D_MT_view_align")
|
||||
layout.menu("VIEW3D_MT_view_navigation")
|
||||
layout.menu("INFO_MT_area")
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.menu("VIEW3D_MT_view_regions", text="View Regions")
|
||||
layout.menu("VIEW3D_MT_Shade")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("view3d.view_selected", text="Frame Selected").use_all_regions = False
|
||||
if view.region_quadviews:
|
||||
layout.operator("view3d.view_selected", text="Frame Selected (Quad View)").use_all_regions = True
|
||||
layout.operator("view3d.view_all", text="Frame All").center = False
|
||||
layout.separator()
|
||||
|
||||
layout.operator("view3d.view_persportho", text="Perspective/Orthographic")
|
||||
layout.menu("VIEW3D_MT_view_local")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("render.opengl", text="Viewport Render Image", icon='RENDER_STILL')
|
||||
layout.operator("render.opengl", text="Viewport Render Animation", icon='RENDER_ANIMATION').animation = True
|
||||
layout.separator()
|
||||
|
||||
layout.prop(view, "show_region_toolbar")
|
||||
layout.prop(view, "show_region_ui")
|
||||
layout.prop(view, "show_region_tool_header")
|
||||
layout.prop(view, "show_region_hud")
|
||||
|
||||
|
||||
|
||||
# Display Wire (Thanks to marvin.k.breuer) #
|
||||
class VIEW3D_OT_Display_Wire_All(Operator):
|
||||
bl_label = "Wire on All Objects"
|
||||
|
@ -81,9 +119,6 @@ class VIEW3D_MT_Shade(Menu):
|
|||
layout.separator()
|
||||
layout.operator("view3d.display_wire_all", text="Wire all", icon='SHADING_WIRE')
|
||||
|
||||
layout.separator()
|
||||
layout.prop(context.space_data.fx_settings, "use_ssao",
|
||||
text="Ambient Occlusion", icon="GROUP")
|
||||
# layout.prop(context.space_data, "use_matcap", icon="MATCAP_01")
|
||||
|
||||
# if context.space_data.use_matcap:
|
||||
|
@ -100,6 +135,7 @@ def menu_func(self, context):
|
|||
classes = (
|
||||
VIEW3D_MT_Shade,
|
||||
VIEW3D_OT_Display_Wire_All,
|
||||
VIEW3D_MT_View_Menu
|
||||
)
|
||||
|
||||
|
||||
|
@ -108,14 +144,12 @@ def register():
|
|||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.VIEW3D_MT_view.append(menu_func)
|
||||
|
||||
# Unregister Classes & Hotkeys #
|
||||
def unregister():
|
||||
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.types.VIEW3D_MT_view.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
|
Loading…
Reference in New Issue