Merge with trunk r38042
This commit is contained in:
@@ -60,7 +60,7 @@ class EditExternally(bpy.types.Operator):
|
||||
filepath = bpy.path.abspath(self.filepath)
|
||||
|
||||
if not os.path.exists(filepath):
|
||||
self.report({'ERROR'}, "Image path %r not found." % filepath)
|
||||
self.report({'ERROR'}, "Image path %r not found, image may be packed or unsaved." % filepath)
|
||||
return {'CANCELLED'}
|
||||
|
||||
cmd = self._editor_guess(context) + [filepath]
|
||||
|
||||
@@ -81,8 +81,8 @@ class MeshMirrorUV(bpy.types.Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.active_object
|
||||
return (ob and ob.type == 'MESH')
|
||||
obj = context.active_object
|
||||
return (obj and obj.type == 'MESH' and obj.data.uv_textures.active)
|
||||
|
||||
def execute(self, context):
|
||||
DIR = (self.direction == 'NEGATIVE')
|
||||
@@ -120,12 +120,7 @@ class MeshMirrorUV(bpy.types.Operator):
|
||||
if j is not None:
|
||||
vmap[i] = j
|
||||
|
||||
active_uv_layer = None
|
||||
for lay in mesh.uv_textures:
|
||||
if lay.active:
|
||||
active_uv_layer = lay.data
|
||||
break
|
||||
|
||||
active_uv_layer = mesh.uv_textures.active.data
|
||||
fuvs = [(uv.uv1, uv.uv2, uv.uv3, uv.uv4) for uv in active_uv_layer]
|
||||
fuvs_cpy = [(uv[0].copy(), uv[1].copy(), uv[2].copy(), uv[3].copy()) for uv in fuvs]
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ class QuickExplode(bpy.types.Operator):
|
||||
fake_context = bpy.context.copy()
|
||||
obj_act = context.active_object
|
||||
|
||||
if obj_act.type != 'MESH':
|
||||
if obj_act is None or obj_act.type != 'MESH':
|
||||
self.report({'ERROR'}, "Active object is not a mesh")
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
@@ -746,13 +746,15 @@ def packIslands(islandList):
|
||||
uv.y= (uv.y+yoffset) * yfactor
|
||||
|
||||
|
||||
|
||||
def VectoQuat(vec):
|
||||
vec = vec.normalized()
|
||||
if abs(vec.x) > 0.5:
|
||||
return vec.to_track_quat('Z', 'X')
|
||||
else:
|
||||
return vec.to_track_quat('Z', 'Y')
|
||||
a3 = vec.normalized()
|
||||
up = Vector((0.0, 0.0, 1.0))
|
||||
if abs(a3.dot(up)) == 1.0:
|
||||
up = Vector((0.0, 1.0, 0.0))
|
||||
|
||||
a1 = a3.cross(up).normalized()
|
||||
a2 = a3.cross(a1)
|
||||
return Matrix((a1, a2, a3)).to_quaternion()
|
||||
|
||||
|
||||
class thickface(object):
|
||||
@@ -791,7 +793,11 @@ def main_consts():
|
||||
|
||||
global ob
|
||||
ob = None
|
||||
def main(context, island_margin, projection_limit):
|
||||
def main(context,
|
||||
island_margin,
|
||||
projection_limit,
|
||||
user_area_weight,
|
||||
):
|
||||
global USER_FILL_HOLES
|
||||
global USER_FILL_HOLES_QUALITY
|
||||
global USER_STRETCH_ASPECT
|
||||
@@ -844,7 +850,6 @@ def main(context, island_margin, projection_limit):
|
||||
USER_FILL_HOLES = (0)
|
||||
USER_FILL_HOLES_QUALITY = (50) # Only for hole filling.
|
||||
USER_VIEW_INIT = (0) # Only for hole filling.
|
||||
USER_AREA_WEIGHT = (1) # Only for hole filling.
|
||||
|
||||
# Reuse variable
|
||||
if len(obList) == 1:
|
||||
@@ -970,12 +975,15 @@ def main(context, island_margin, projection_limit):
|
||||
|
||||
# Add the average of all these faces normals as a projectionVec
|
||||
averageVec = Vector((0.0, 0.0, 0.0))
|
||||
if USER_AREA_WEIGHT:
|
||||
for fprop in newProjectMeshFaces:
|
||||
averageVec += (fprop.no * fprop.area)
|
||||
else:
|
||||
if user_area_weight == 0.0:
|
||||
for fprop in newProjectMeshFaces:
|
||||
averageVec += fprop.no
|
||||
elif user_area_weight == 1.0:
|
||||
for fprop in newProjectMeshFaces:
|
||||
averageVec += fprop.no * fprop.area
|
||||
else:
|
||||
for fprop in newProjectMeshFaces:
|
||||
averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight))
|
||||
|
||||
if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
|
||||
projectVecs.append(averageVec.normalized())
|
||||
@@ -1062,7 +1070,7 @@ def main(context, island_margin, projection_limit):
|
||||
f_uv = f.uv
|
||||
for j, v in enumerate(f.v):
|
||||
# XXX - note, between mathutils in 2.4 and 2.5 the order changed.
|
||||
f_uv[j][:] = (v.co * MatQuat)[:2]
|
||||
f_uv[j][:] = (v.co * MatQuat).xy
|
||||
|
||||
|
||||
if USER_SHARE_SPACE:
|
||||
@@ -1098,12 +1106,8 @@ def main(context, island_margin, projection_limit):
|
||||
"""
|
||||
pup_block = [\
|
||||
'Projection',\
|
||||
* ('Angle Limit:', USER_PROJECTION_LIMIT, 1, 89, ''),\
|
||||
('Selected Faces Only', USER_ONLY_SELECTED_FACES, 'Use only selected faces from all selected meshes.'),\
|
||||
('Init from view', USER_VIEW_INIT, 'The first projection will be from the view vector.'),\
|
||||
('Area Weight', USER_AREA_WEIGHT, 'Weight projections vector by face area.'),\
|
||||
'',\
|
||||
'',\
|
||||
'',\
|
||||
'UV Layout',\
|
||||
('Share Tex Space', USER_SHARE_SPACE, 'Objects Share texture space, map all objects into 1 uvmap.'),\
|
||||
@@ -1125,11 +1129,15 @@ class SmartProject(bpy.types.Operator):
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
angle_limit = FloatProperty(name="Angle Limit",
|
||||
description="lower for more projection groups, higher for less distortion.",
|
||||
description="lower for more projection groups, higher for less distortion",
|
||||
default=66.0, min=1.0, max=89.0)
|
||||
|
||||
island_margin = FloatProperty(name="Island Margin",
|
||||
description="Margin to reduce bleed from adjacent islands.",
|
||||
description="Margin to reduce bleed from adjacent islands",
|
||||
default=0.0, min=0.0, max=1.0)
|
||||
|
||||
user_area_weight = FloatProperty(name="Area Weight",
|
||||
description="Weight projections vector by faces with larger areas",
|
||||
default=0.0, min=0.0, max=1.0)
|
||||
|
||||
@classmethod
|
||||
@@ -1137,7 +1145,11 @@ class SmartProject(bpy.types.Operator):
|
||||
return context.active_object != None
|
||||
|
||||
def execute(self, context):
|
||||
main(context, self.island_margin, self.angle_limit)
|
||||
main(context,
|
||||
self.island_margin,
|
||||
self.angle_limit,
|
||||
self.user_area_weight,
|
||||
)
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
# <pep8 compliant>
|
||||
|
||||
import bpy
|
||||
from bpy.props import StringProperty, BoolProperty, IntProperty, FloatProperty
|
||||
from bpy.props import StringProperty, BoolProperty, IntProperty, \
|
||||
FloatProperty, EnumProperty
|
||||
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get, rna_idprop_ui_prop_clear
|
||||
|
||||
|
||||
@@ -457,6 +459,66 @@ doc_id = StringProperty(name="Doc ID",
|
||||
doc_new = StringProperty(name="Edit Description",
|
||||
description="", maxlen=1024, default="")
|
||||
|
||||
data_path_iter = StringProperty(
|
||||
description="The data path relative to the context, must point to an iterable.")
|
||||
|
||||
data_path_item = StringProperty(
|
||||
description="The data path from each iterable to the value (int or float)")
|
||||
|
||||
|
||||
class WM_OT_context_collection_boolean_set(bpy.types.Operator):
|
||||
'''Set boolean values for a collection of items'''
|
||||
bl_idname = "wm.context_collection_boolean_set"
|
||||
bl_label = "Context Collection Boolean Set"
|
||||
bl_options = {'UNDO', 'REGISTER', 'INTERNAL'}
|
||||
|
||||
data_path_iter = data_path_iter
|
||||
data_path_item = data_path_item
|
||||
|
||||
type = EnumProperty(items=(
|
||||
('TOGGLE', "Toggle", ""),
|
||||
('ENABLE', "Enable", ""),
|
||||
('DISABLE', "Disable", ""),
|
||||
),
|
||||
name="Type")
|
||||
|
||||
def execute(self, context):
|
||||
data_path_iter = self.data_path_iter
|
||||
data_path_item = self.data_path_item
|
||||
|
||||
items = list(getattr(context, data_path_iter))
|
||||
items_ok = []
|
||||
is_set = False
|
||||
for item in items:
|
||||
try:
|
||||
value_orig = eval("item." + data_path_item)
|
||||
except:
|
||||
continue
|
||||
|
||||
if value_orig == True:
|
||||
is_set = True
|
||||
elif value_orig == False:
|
||||
pass
|
||||
else:
|
||||
self.report({'WARNING'}, "Non boolean value found: %s[ ].%s" %
|
||||
(data_path_iter, data_path_item))
|
||||
return {'CANCELLED'}
|
||||
|
||||
items_ok.append(item)
|
||||
|
||||
if self.type == 'ENABLE':
|
||||
is_set = True
|
||||
elif self.type == 'DISABLE':
|
||||
is_set = False
|
||||
else:
|
||||
is_set = not is_set
|
||||
|
||||
exec_str = "item.%s = %s" % (data_path_item, is_set)
|
||||
for item in items_ok:
|
||||
exec(exec_str)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class WM_OT_context_modal_mouse(bpy.types.Operator):
|
||||
'''Adjust arbitrary values with mouse input'''
|
||||
@@ -464,8 +526,9 @@ class WM_OT_context_modal_mouse(bpy.types.Operator):
|
||||
bl_label = "Context Modal Mouse"
|
||||
bl_options = {'GRAB_POINTER', 'BLOCKING', 'INTERNAL'}
|
||||
|
||||
data_path_iter = StringProperty(description="The data path relative to the context, must point to an iterable.")
|
||||
data_path_item = StringProperty(description="The data path from each iterable to the value (int or float)")
|
||||
data_path_iter = data_path_iter
|
||||
data_path_item = data_path_item
|
||||
|
||||
input_scale = FloatProperty(default=0.01, description="Scale the mouse movement by this value before applying the delta")
|
||||
invert = BoolProperty(default=False, description="Invert the mouse input")
|
||||
initial_x = IntProperty(options={'HIDDEN'})
|
||||
|
||||
@@ -878,7 +878,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel):
|
||||
col.prop(part, "billboard_tilt_random", text="Random", slider=True)
|
||||
col = row.column()
|
||||
col.prop(part, "billboard_offset")
|
||||
|
||||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.prop(part, "billboard_size", text="Scale")
|
||||
|
||||
@@ -616,10 +616,9 @@ class IMAGE_PT_view_properties(bpy.types.Panel):
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
col.prop(uvedit, "show_faces")
|
||||
col.prop(uvedit, "show_smooth_edges", text="Smooth")
|
||||
col.prop(uvedit, "show_modified_edges", text="Modified")
|
||||
#col.prop(uvedit, "show_edges")
|
||||
#col.prop(uvedit, "show_faces")
|
||||
|
||||
col = split.column()
|
||||
col.prop(uvedit, "show_stretch", text="Stretch")
|
||||
|
||||
@@ -876,6 +876,19 @@ class USERPREF_PT_addons(bpy.types.Panel):
|
||||
def module_get(mod_name):
|
||||
return USERPREF_PT_addons._addons_fake_modules[mod_name]
|
||||
|
||||
@staticmethod
|
||||
def is_user_addon(mod, user_addon_paths):
|
||||
if not user_addon_paths:
|
||||
user_script_path = bpy.utils.user_script_path()
|
||||
if user_script_path is not None:
|
||||
user_addon_paths.append(os.path.join(user_script_path(), "addons"))
|
||||
user_addon_paths.append(os.path.join(bpy.utils.resource_path('USER'), "scripts", "addons"))
|
||||
|
||||
for path in user_addon_paths:
|
||||
if bpy.path.is_subdir(mod.__file__, path):
|
||||
return True
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@@ -900,6 +913,9 @@ class USERPREF_PT_addons(bpy.types.Panel):
|
||||
search = context.window_manager.addon_search.lower()
|
||||
support = context.window_manager.addon_support
|
||||
|
||||
# initialized on demand
|
||||
user_addon_paths = []
|
||||
|
||||
for mod, info in addons:
|
||||
module_name = mod.__name__
|
||||
|
||||
@@ -969,20 +985,24 @@ class USERPREF_PT_addons(bpy.types.Panel):
|
||||
split = colsub.row().split(percentage=0.15)
|
||||
split.label(text="Warning:")
|
||||
split.label(text=' ' + info["warning"], icon='ERROR')
|
||||
if info["wiki_url"] or info["tracker_url"]:
|
||||
|
||||
user_addon = __class__.is_user_addon(mod, user_addon_paths)
|
||||
tot_row = bool(info["wiki_url"]) + bool(info["tracker_url"]) + bool(user_addon)
|
||||
|
||||
if tot_row:
|
||||
split = colsub.row().split(percentage=0.15)
|
||||
split.label(text="Internet:")
|
||||
if info["wiki_url"]:
|
||||
split.operator("wm.url_open", text="Link to the Wiki", icon='HELP').url = info["wiki_url"]
|
||||
if info["tracker_url"]:
|
||||
split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info["tracker_url"]
|
||||
if user_addon:
|
||||
split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__
|
||||
|
||||
if info["wiki_url"] and info["tracker_url"]:
|
||||
split.separator()
|
||||
else:
|
||||
split.separator()
|
||||
for i in range(4 - tot_row):
|
||||
split.separator()
|
||||
|
||||
|
||||
# Append missing scripts
|
||||
# First collect scripts that are used but have no script file.
|
||||
module_names = {mod.__name__ for mod, info in addons}
|
||||
@@ -1186,6 +1206,54 @@ class WM_OT_addon_install(bpy.types.Operator):
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
class WM_OT_addon_remove(bpy.types.Operator):
|
||||
"Disable an addon"
|
||||
bl_idname = "wm.addon_remove"
|
||||
bl_label = "Remove Add-On"
|
||||
|
||||
module = StringProperty(name="Module", description="Module name of the addon to remove")
|
||||
|
||||
@staticmethod
|
||||
def path_from_addon(module):
|
||||
for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules):
|
||||
if mod.__name__ == module:
|
||||
filepath = mod.__file__
|
||||
if os.path.exists(filepath):
|
||||
if os.path.splitext(os.path.basename(filepath))[0] == "__init__":
|
||||
return os.path.dirname(filepath), True
|
||||
else:
|
||||
return filepath, False
|
||||
return None, False
|
||||
|
||||
def execute(self, context):
|
||||
path, isdir = __class__.path_from_addon(self.module)
|
||||
if path is None:
|
||||
self.report('WARNING', "Addon path %r could not be found" % path)
|
||||
return {'CANCELLED'}
|
||||
|
||||
# incase its enabled
|
||||
addon_utils.disable(self.module)
|
||||
|
||||
import shutil
|
||||
if isdir:
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
|
||||
context.area.tag_redraw()
|
||||
return {'FINISHED'}
|
||||
|
||||
# lame confirmation check
|
||||
def draw(self, context):
|
||||
self.layout.label(text="Remove Addon: %r?" % self.module)
|
||||
path, isdir = __class__.path_from_addon(self.module)
|
||||
self.layout.label(text="Path: %r" % path)
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self, width=600)
|
||||
|
||||
|
||||
class WM_OT_addon_expand(bpy.types.Operator):
|
||||
"Display more information on this add-on"
|
||||
bl_idname = "wm.addon_expand"
|
||||
|
||||
@@ -1252,7 +1252,7 @@ class VIEW3D_MT_pose(bpy.types.Menu):
|
||||
layout.separator()
|
||||
|
||||
layout.menu("VIEW3D_MT_pose_showhide")
|
||||
layout.operator_menu_enum("pose.flags_set", 'mode', text="Bone Settings")
|
||||
layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings")
|
||||
|
||||
|
||||
class VIEW3D_MT_pose_transform(bpy.types.Menu):
|
||||
@@ -1373,6 +1373,49 @@ class VIEW3D_MT_pose_apply(bpy.types.Menu):
|
||||
layout.operator("pose.visual_transform_apply")
|
||||
|
||||
|
||||
class BoneOptions:
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
options = [
|
||||
"show_wire",
|
||||
"use_deform",
|
||||
"use_envelope_multiply",
|
||||
"use_inherit_rotation",
|
||||
"use_inherit_scale",
|
||||
]
|
||||
|
||||
if context.mode == 'EDIT_ARMATURE':
|
||||
bone_props = bpy.types.EditBone.bl_rna.properties
|
||||
data_path_iter = "selected_bones"
|
||||
opt_suffix = ""
|
||||
options.append("lock")
|
||||
else: # posemode
|
||||
bone_props = bpy.types.Bone.bl_rna.properties
|
||||
data_path_iter = "selected_pose_bones"
|
||||
opt_suffix = "bone."
|
||||
|
||||
for opt in options:
|
||||
props = layout.operator("wm.context_collection_boolean_set", text=bone_props[opt].name)
|
||||
props.data_path_iter = data_path_iter
|
||||
props.data_path_item = opt_suffix + opt
|
||||
props.type = self.type
|
||||
|
||||
|
||||
class VIEW3D_MT_bone_options_toggle(bpy.types.Menu, BoneOptions):
|
||||
bl_label = "Toggle Bone Options"
|
||||
type = 'TOGGLE'
|
||||
|
||||
|
||||
class VIEW3D_MT_bone_options_enable(bpy.types.Menu, BoneOptions):
|
||||
bl_label = "Enable Bone Options"
|
||||
type = 'ENABLE'
|
||||
|
||||
|
||||
class VIEW3D_MT_bone_options_disable(bpy.types.Menu, BoneOptions):
|
||||
bl_label = "Disable Bone Options"
|
||||
type = 'DISABLE'
|
||||
|
||||
# ********** Edit Menus, suffix from ob.type **********
|
||||
|
||||
|
||||
@@ -1966,7 +2009,7 @@ class VIEW3D_MT_edit_armature(bpy.types.Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator_menu_enum("armature.flags_set", "mode", text="Bone Settings")
|
||||
layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings")
|
||||
|
||||
|
||||
class VIEW3D_MT_armature_specials(bpy.types.Menu):
|
||||
|
||||
Reference in New Issue
Block a user