diff options
author | Xiao Xiangquan <xiaoxiangquan@gmail.com> | 2011-07-14 21:29:53 +0400 |
---|---|---|
committer | Xiao Xiangquan <xiaoxiangquan@gmail.com> | 2011-07-14 21:29:53 +0400 |
commit | fa46278e347ca173e9e6d6b734a59c268f4fc9d0 (patch) | |
tree | a14148822e60cb1f8f36dba0481b830cb9675db1 /release | |
parent | 470a5017fb80f21bac08373e4b5816c92d42990a (diff) | |
parent | 4da4943b5ce9514e9fb3d9458f3e52d6b0d310ca (diff) |
merge from trunk 38379
Diffstat (limited to 'release')
40 files changed, 436 insertions, 161 deletions
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 3877f711b7f..07f1dc618dc 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -48,8 +48,6 @@ def paths(): def modules(module_cache): import os - import sys - import time path_list = paths() @@ -173,11 +171,9 @@ def enable(module_name, default_set=True): :return: the loaded module or None on failier. :rtype: module """ - # note, this still gets added to _bpy_types.TypeMap import os import sys - import bpy_types as _bpy_types import imp def handle_error(): @@ -246,8 +242,6 @@ def disable(module_name, default_set=True): :type module_name: string """ import sys - import bpy_types as _bpy_types - mod = sys.modules.get(module_name) # possible this addon is from a previous session and didnt load a module this time. diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py index 1df8e9e5588..9c48dc89f83 100644 --- a/release/scripts/modules/bpy/__init__.py +++ b/release/scripts/modules/bpy/__init__.py @@ -22,24 +22,29 @@ Give access to blender data and utility functions. """ -# internal blender C module -import _bpy -from _bpy import types, props, app +__all__ = ( + "app", + "context", + "data", + "ops", + "path", + "props", + "types", + "utils", +) + -data = _bpy.data -context = _bpy.context +# internal blender C module +from _bpy import types, props, app, data, context # python modules -from . import utils, path -from . import ops as _ops_module +from . import utils, path, ops # fake operator module -ops = _ops_module.ops_fake_module - -import sys as _sys - +ops = ops.ops_fake_module def _main(): + import sys as _sys # Possibly temp. addons path from os.path import join, dirname, normpath @@ -59,3 +64,5 @@ def _main(): _main() + +del _main diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py index f54b0a1fefc..64c5a1a5f5f 100644 --- a/release/scripts/modules/bpy/ops.py +++ b/release/scripts/modules/bpy/ops.py @@ -29,7 +29,7 @@ op_as_string = ops_module.as_string op_get_rna = ops_module.get_rna -class bpy_ops(object): +class BPyOps(object): ''' Fake module like class. @@ -42,7 +42,7 @@ class bpy_ops(object): ''' if module.startswith('__'): raise AttributeError(module) - return bpy_ops_submodule(module) + return BPyOpsSubMod(module) def __dir__(self): @@ -67,7 +67,7 @@ class bpy_ops(object): return "<module like class 'bpy.ops'>" -class bpy_ops_submodule(object): +class BPyOpsSubMod(object): ''' Utility class to fake submodules. @@ -84,7 +84,7 @@ class bpy_ops_submodule(object): ''' if func.startswith('__'): raise AttributeError(func) - return bpy_ops_submodule_op(self.module, func) + return BPyOpsSubModOp(self.module, func) def __dir__(self): @@ -103,7 +103,7 @@ class bpy_ops_submodule(object): return "<module like class 'bpy.ops.%s'>" % self.module -class bpy_ops_submodule_op(object): +class BPyOpsSubModOp(object): ''' Utility class to fake submodule operators. @@ -151,7 +151,7 @@ class bpy_ops_submodule_op(object): self.func = func def poll(self, *args): - C_dict, C_exec = __class__._parse_args(args) + C_dict, C_exec = BPyOpsSubModOp._parse_args(args) return op_poll(self.idname_py(), C_dict, C_exec) def idname(self): @@ -170,16 +170,16 @@ class bpy_ops_submodule_op(object): wm = context.window_manager # run to account for any rna values the user changes. - __class__._scene_update(context) + BPyOpsSubModOp._scene_update(context) if args: - C_dict, C_exec = __class__._parse_args(args) + C_dict, C_exec = BPyOpsSubModOp._parse_args(args) ret = op_call(self.idname_py(), C_dict, kw, C_exec) else: ret = op_call(self.idname_py(), None, kw) if 'FINISHED' in ret and context.window_manager == wm: - __class__._scene_update(context) + BPyOpsSubModOp._scene_update(context) return ret @@ -208,4 +208,4 @@ class bpy_ops_submodule_op(object): return "<function bpy.ops.%s.%s at 0x%x'>" % \ (self.module, self.func, id(self)) -ops_fake_module = bpy_ops() +ops_fake_module = BPyOps() diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py index 551940b26e2..f91535a0ad4 100644 --- a/release/scripts/modules/bpy_extras/image_utils.py +++ b/release/scripts/modules/bpy_extras/image_utils.py @@ -99,7 +99,7 @@ def load_image(imagepath, return _image_load(nfilepath) if place_holder: - image = bpy.data.images.new(os.path.basename(filepath), 128, 128) + image = bpy.data.images.new(os.path.basename(imagepath), 128, 128) # allow the path to be resolved later image.filepath = imagepath return image diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index 12c2d809132..cfa2233f7b6 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -262,7 +262,7 @@ def path_reference(filepath, base_src, base_dst, mode='AUTO', copy_subdir="", co filepath_abs = filepath_cpy mode = 'RELATIVE' else: - Excaption("invalid mode given %r" % mode) + raise Exception("invalid mode given %r" % mode) if mode == 'ABSOLUTE': return filepath_abs diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py index 2062fe4485f..c42d3d0236a 100644 --- a/release/scripts/modules/bpy_extras/mesh_utils.py +++ b/release/scripts/modules/bpy_extras/mesh_utils.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> __all__ = ( "mesh_linked_faces", @@ -25,6 +25,7 @@ __all__ = ( "edge_loops_from_faces", "edge_loops_from_edges", "ngon_tesselate", + "face_random_points", ) @@ -67,7 +68,8 @@ def mesh_linked_faces(mesh): if mapped_index != nxt_mapped_index: ok = True - # Assign mapping to this group so they all map to this group + # Assign mapping to this group so they + # all map to this group for grp_f in face_groups[nxt_mapped_index]: face_mapping[grp_f.index] = mapped_index @@ -105,9 +107,9 @@ def edge_face_count(mesh): :return: list face users for each item in mesh.edges. :rtype: list """ - edge_face_count_dict = edge_face_count_dict(mesh) + edge_face_count = edge_face_count_dict(mesh) get = dict.get - return [get(edge_face_count_dict, ed.key, 0) for ed in mesh.edges] + return [get(edge_face_count, ed.key, 0) for ed in mesh.edges] def edge_loops_from_faces(mesh, faces=None, seams=()): @@ -212,8 +214,6 @@ def edge_loops_from_edges(mesh, edges=None): if not hasattr(edges, "pop"): edges = edges[:] - edge_dict = {ed.key: ed for ed in mesh.edges if ed.select} - while edges: current_edge = edges.pop() vert_end, vert_start = current_edge.vertices[:] @@ -287,7 +287,7 @@ def ngon_tesselate(from_data, indices, fix_loops=True): else: return v1[1], v2[1] - if not PREF_FIX_LOOPS: + if not fix_loops: ''' Normal single concave loop filling ''' @@ -300,7 +300,7 @@ def ngon_tesselate(from_data, indices, fix_loops=True): if verts[i][1] == verts[i - 1][0]: verts.pop(i - 1) - fill = fill_polygon([verts]) + fill = tesselate_polygon([verts]) else: ''' @@ -435,3 +435,70 @@ def ngon_tesselate(from_data, indices, fix_loops=True): fill[i] = tuple([ii for ii in reversed(fi)]) return fill + + +def face_random_points(num_points, faces): + """ + Generates a list of random points over mesh faces. + + :arg num_points: the number of random points to generate on each face. + :type int: + :arg faces: list of the faces to generate points on. + :type faces: :class:`MeshFaces`, sequence + :return: list of random points over all faces. + :rtype: list + """ + + from random import random + from mathutils.geometry import area_tri + + # Split all quads into 2 tris, tris remain unchanged + tri_faces = [] + for f in faces: + tris = [] + verts = f.id_data.vertices + fv = f.vertices[:] + tris.append((verts[fv[0]].co, + verts[fv[1]].co, + verts[fv[2]].co, + )) + if len(fv) == 4: + tris.append((verts[fv[0]].co, + verts[fv[3]].co, + verts[fv[2]].co, + )) + tri_faces.append(tris) + + # For each face, generate the required number of random points + sampled_points = [None] * (num_points * len(faces)) + for i, tf in enumerate(tri_faces): + for k in range(num_points): + # If this is a quad, we need to weight its 2 tris by their area + if len(tf) != 1: + area1 = area_tri(*tf[0]) + area2 = area_tri(*tf[1]) + area_tot = area1 + area2 + + area1 = area1 / area_tot + area2 = area2 / area_tot + + vecs = tf[0 if (random() < area1) else 1] + else: + vecs = tf[0] + + u1 = random() + u2 = random() + u_tot = u1 + u2 + + if u_tot > 1: + u1 = 1.0 - u1 + u2 = 1.0 - u2 + + side1 = vecs[1] - vecs[0] + side2 = vecs[2] - vecs[0] + + p = vecs[0] + u1 * side1 + u2 * side2 + + sampled_points[num_points * i + k] = p + + return sampled_points diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py index 01ac543aec7..c0c0f9186bd 100644 --- a/release/scripts/modules/bpy_extras/view3d_utils.py +++ b/release/scripts/modules/bpy_extras/view3d_utils.py @@ -22,7 +22,6 @@ __all__ = ( "region_2d_to_vector_3d", "region_2d_to_location_3d", "location_3d_to_region_2d", - "location_3d_to_region_2d", ) diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index eaa7563c757..f2cd46b20ae 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -241,7 +241,7 @@ class _GenericBone: chain.append(child) else: if len(children_basename): - print("multiple basenames found, this is probably not what you want!", bone.name, children_basename) + print("multiple basenames found, this is probably not what you want!", self.name, children_basename) break diff --git a/release/scripts/modules/bpyml_ui.py b/release/scripts/modules/bpyml_ui.py index 1e0522974d1..5df04b8bf34 100644 --- a/release/scripts/modules/bpyml_ui.py +++ b/release/scripts/modules/bpyml_ui.py @@ -22,7 +22,6 @@ import bpy as _bpy import bpyml from bpyml import TAG, ARGS, CHILDREN -from types import ModuleType _uilayout_rna = _bpy.types.UILayout.bl_rna diff --git a/release/scripts/modules/console/intellisense.py b/release/scripts/modules/console/intellisense.py index 072d467ff86..a177b305fda 100644 --- a/release/scripts/modules/console/intellisense.py +++ b/release/scripts/modules/console/intellisense.py @@ -53,7 +53,7 @@ RE_UNQUOTED_WORD = re.compile( re.UNICODE) -def complete(line, cursor, namespace, private=True): +def complete(line, cursor, namespace, private): """Returns a list of possible completions: * name completion @@ -82,6 +82,9 @@ def complete(line, cursor, namespace, private=True): if RE_MODULE.match(line): from . import complete_import matches = complete_import.complete(line) + if not private: + matches[:] = [m for m in matches if m[:1] != "_"] + matches.sort() else: from . import complete_namespace matches = complete_namespace.complete(word, namespace, private) @@ -130,11 +133,15 @@ def expand(line, cursor, namespace, private=True): else: # causes blender bug [#27495] since string keys may contain '.' # scrollback = ' '.join([m.split('.')[-1] for m in matches]) + + # add white space to align with the cursor + white_space = " " + (" " * (cursor + len(prefix))) word_prefix = word + prefix - scrollback = ' '.join( - [m[len(word_prefix):] + scrollback = '\n'.join( + [white_space + m[len(word_prefix):] if (word_prefix and m.startswith(word_prefix)) - else m.split('.')[-1] + else + white_space + m.split('.')[-1] for m in matches]) no_calltip = True diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py index b0fb3b66d0a..388ae2b0e13 100644 --- a/release/scripts/modules/rna_prop_ui.py +++ b/release/scripts/modules/rna_prop_ui.py @@ -114,7 +114,7 @@ def draw(layout, context, context_member, property_type, use_edit=True): to_dict = getattr(val, "to_dict", None) to_list = getattr(val, "to_list", None) - val_orig = val + # val_orig = val # UNUSED if to_dict: val = to_dict() val_draw = str(val) diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index 462db3a2c5e..34c5b0d922a 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -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] @@ -121,7 +121,6 @@ class ProjectEdit(bpy.types.Operator): def execute(self, context): import os - import subprocess EXT = "png" # could be made an option but for now ok diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 996b38ae571..03b0e469310 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -81,14 +81,12 @@ 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') - from mathutils import Vector - ob = context.active_object is_editmode = (ob.mode == 'EDIT') if is_editmode: @@ -120,12 +118,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] diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index c5ee2488a31..72e521be5cf 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -232,7 +232,7 @@ class ShapeTransfer(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} mode = EnumProperty(items=( - ('OFFSET', "Offset", _("Apply the relative positional offset")), + ('OFFSET', _("Offset"), _("Apply the relative positional offset")), ('RELATIVE_FACE', _("Relative Face"), _("Calculate the geometricly relative position (using faces).")), ('RELATIVE_EDGE', _("Relative Edge"), _("Calculate the geometricly relative position (using edges)."))), name=_("Transformation Mode"), diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 889972da53c..d662d292868 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -99,8 +99,6 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to): # Main Loop for obj, bb_world in objs: - - loc_world = obj.location bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box] Left_Up_Front = bb_world[1] diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index a8bb3227b3c..074f204d50e 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -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'} diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 14ca1b4705d..6624c2ad288 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -21,6 +21,7 @@ import bpy from blf import gettext as _ + class AddPresetBase(): '''Base preset class, only for subclassing subclasses must define @@ -318,7 +319,7 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): @property def preset_subdir(self): - return __class__.operator_path(self.operator) + return AddPresetOperator.operator_path(self.operator) @property def preset_values(self): diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 561738d1706..2406cc59952 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -28,6 +28,7 @@ import bpy import os from blf import gettext as _ + def guess_player_path(preset): import sys @@ -79,7 +80,7 @@ class PlayRenderedAnim(bpy.types.Operator): preset = prefs.filepaths.animation_player_preset player_path = prefs.filepaths.animation_player - file_path = bpy.path.abspath(rd.filepath) + # file_path = bpy.path.abspath(rd.filepath) # UNUSED is_movie = rd.is_movie_format # try and guess a command line if it doesn't exist diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index edd09d9c66b..43ca9af59ba 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -42,7 +42,6 @@ def extend(obj, operator, EXTEND_MODE): edge_average_lengths = {} OTHER_INDEX = 2, 3, 0, 1 - FAST_INDICIES = 0, 2, 1, 3 # order is faster def extend_uvs(face_source, face_target, edge_key): ''' diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 3893612437a..9ae0cd0ddf9 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -406,7 +406,7 @@ def lightmap_uvpack(meshes, ok = False # Tall boxes in groups of 2 - for d, boxes in odd_dict.items(): + for d, boxes in list(odd_dict.items()): if d[1] < max_int_dimension: #\boxes.sort(key = lambda a: len(a.children)) while len(boxes) >= 2: @@ -427,7 +427,7 @@ def lightmap_uvpack(meshes, odd_dict.setdefault((w, h), []).append(pf_parent) # Even boxes in groups of 4 - for d, boxes in even_dict.items(): + for d, boxes in list(even_dict.items()): if d < max_int_dimension: boxes.sort(key=lambda a: len(a.children)) @@ -444,7 +444,7 @@ def lightmap_uvpack(meshes, del even_dict del odd_dict - orig = len(pretty_faces) + # orig = len(pretty_faces) pretty_faces = [pf for pf in pretty_faces if not pf.has_parent] @@ -489,7 +489,10 @@ def lightmap_uvpack(meshes, if PREF_APPLY_IMAGE: if not PREF_PACK_IN_ONE: - image = Image.New("lightmap", PREF_IMG_PX_SIZE, PREF_IMG_PX_SIZE, 24) + image = bpy.data.images.new(name="lightmap", + width=PREF_IMG_PX_SIZE, + height=PREF_IMG_PX_SIZE, + ) for f in face_sel: # f.image = image @@ -530,7 +533,7 @@ def unwrap(operator, context, **kwargs): return {'FINISHED'} -from bpy.props import BoolProperty, FloatProperty, IntProperty, EnumProperty +from bpy.props import BoolProperty, FloatProperty, IntProperty class LightMapPack(bpy.types.Operator): diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index c70b9071985..7ea89cfa479 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -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 @@ -812,21 +818,25 @@ def main(context, island_margin, projection_limit): global RotMatStepRotation main_consts() -#XXX objects= bpy.data.scenes.active.objects - objects = context.selected_editable_objects - + # TODO, all selected meshes + ''' + # objects = context.selected_editable_objects + objects = [] # we can will tag them later. obList = [ob for ob in objects if ob.type == 'MESH'] # Face select object may not be selected. -#XXX ob = objects.active - ob= objects[0] + ob = context.active_object if ob and (not ob.select) and ob.type == 'MESH': # Add to the list obList =[ob] del objects + ''' + + # quick workaround + obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH'] if not obList: raise('error, no selected mesh objects') @@ -840,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: @@ -966,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: + if user_area_weight == 0.0: for fprop in newProjectMeshFaces: - averageVec += (fprop.no * fprop.area) + 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 + 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()) @@ -1058,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: @@ -1094,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.'),\ @@ -1121,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 @@ -1133,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): diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index f2b19923e32..00a2f546382 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -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 from blf import gettext as _ @@ -458,15 +460,76 @@ 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''' bl_idname = "wm.context_modal_mouse" bl_label = _("Context Modal Mouse") - bl_options = {'INTERNAL'} + bl_options = {'GRAB_POINTER', 'BLOCKING', 'INTERNAL'} + + data_path_iter = data_path_iter + data_path_item = data_path_item - 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)")) 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'}) diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py index eb1bbfd2fb1..3b33a7ccc61 100644 --- a/release/scripts/startup/bl_ui/properties_animviz.py +++ b/release/scripts/startup/bl_ui/properties_animviz.py @@ -94,4 +94,5 @@ class OnionSkinButtonsPanel(): col.prop(arm, "show_only_ghost_selected", text="Selected Only") if __name__ == "__main__": # only for live edit. + import bpy bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 9477dc866ab..f2a3bac2373 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -299,10 +299,7 @@ class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): # in return (context.object) and (context.armature) def draw(self, context): - layout = self.layout - ob = context.object - self.draw_settings(context, ob.pose.animation_visualisation, bones=True) diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index 00d8d08852e..3c88127c724 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -122,7 +122,6 @@ class DATA_PT_curve_texture_space(CurveButtonsPanel, bpy.types.Panel): def draw(self, context): layout = self.layout - ob = context.object curve = context.curve row = layout.row() diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 8c966825aee..618a88f0879 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -290,9 +290,8 @@ class DATA_PT_texface(MeshButtonsPanel, bpy.types.Panel): @classmethod def poll(cls, context): - ob = context.active_object - - return (context.mode == 'EDIT_MESH') and ob and ob.type == 'MESH' + obj = context.object + return (context.mode == 'EDIT_MESH') and obj and obj.type == 'MESH' def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 52d6b5f1376..45c15bd1ce6 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -729,6 +729,7 @@ class MATERIAL_PT_options(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "use_vertex_color_paint") col.prop(mat, "use_vertex_color_light") col.prop(mat, "use_object_color") + col.prop(mat, "pass_index") class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel): @@ -883,7 +884,7 @@ class MATERIAL_PT_volume_lighting(VolumeButtonsPanel, bpy.types.Panel): sub = col.column() sub.enabled = True sub.active = False - sub.prop(vol, "use_light_cache") + sub.label("Light Cache Enabled") col.prop(vol, "cache_resolution") sub = col.column(align=True) diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index ae66642e903..cdbcf2cf533 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -34,7 +34,6 @@ class OBJECT_PT_context_object(ObjectButtonsPanel, bpy.types.Panel): def draw(self, context): layout = self.layout space = context.space_data - ob = context.object if space.use_pin_id: layout.template_ID(space, "pin_id") diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 63333083cb2..4c92296dacd 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -879,6 +879,15 @@ class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel): col = row.column() col.prop(part, "billboard_offset") + row = layout.row() + col = row.column() + col.prop(part, "billboard_size", text="Scale") + if part.billboard_align == 'VEL': + col = row.column(align=True) + col.label("Velocity Scale:") + col.prop(part, "billboard_velocity_head", text="Head") + col.prop(part, "billboard_velocity_tail", text="Tail") + if psys: col = layout.column() col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_textures") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index b6904d9f98a..56520202efb 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -142,6 +142,7 @@ class RENDER_PT_layers(RenderButtonsPanel, bpy.types.Panel): col.prop(rl, "use_pass_uv") col.prop(rl, "use_pass_mist") col.prop(rl, "use_pass_object_index") + col.prop(rl, "use_pass_material_index") col.prop(rl, "use_pass_color") col = split.column() diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index a4dfe0cb7f8..8cb37a0b987 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -21,6 +21,7 @@ import bpy from rna_prop_ui import PropertyPanel from blf import gettext as _ + class TEXTURE_MT_specials(bpy.types.Menu): bl_label = "Texture Specials" COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @@ -88,15 +89,15 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, bpy.types.Panel): @classmethod def poll(cls, context): engine = context.scene.render.engine - if not hasattr(context, "texture_slot"): + if not (hasattr(context, "texture_slot") or hasattr(context, "texture_node")): return False return ((context.material or context.world or context.lamp or context.brush or context.texture or context.particle_system or isinstance(context.space_data.pin_id, bpy.types.ParticleSettings)) and (engine in cls.COMPAT_ENGINES)) def draw(self, context): layout = self.layout - slot = context.texture_slot - node = context.texture_node + slot = getattr(context, "texture_slot", None) + node = getattr(context, "texture_node", None) space = context.space_data tex = context.texture idblock = context_tex_datablock(context) @@ -208,7 +209,7 @@ class TextureSlotPanel(TextureButtonsPanel): return False engine = context.scene.render.engine - return TextureButtonsPanel.poll(self, context) and (engine in cls.COMPAT_ENGINES) + return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES) # Texture Type Panels # @@ -393,7 +394,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, bpy.types.Panel): idblock = context_tex_datablock(context) tex = context.texture - slot = context.texture_slot + slot = getattr(context, "texture_slot", None) split = layout.split() @@ -408,7 +409,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, bpy.types.Panel): col = split.column() #Only for Material based textures, not for Lamp/World... - if isinstance(idblock, bpy.types.Material): + if slot and isinstance(idblock, bpy.types.Material): col.prop(tex, "use_normal_map") row = col.row() row.active = tex.use_normal_map diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index de83e7bab1f..7e4c84d5afc 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -21,6 +21,7 @@ import bpy from bpy.props import StringProperty from blf import gettext as _ + class CONSOLE_HT_header(bpy.types.Header): bl_space_type = 'CONSOLE' diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 7f2d88a6e4e..6e0eded1d4c 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -435,7 +435,6 @@ class IMAGE_PT_game_properties(bpy.types.Panel): @classmethod def poll(cls, context): - rd = context.scene.render sima = context.space_data # display even when not in game mode because these settings effect the 3d view return (sima and sima.image) # and (rd.engine == 'BLENDER_GAME') @@ -617,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")) diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index a4e5c48cd80..90908ce6511 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -136,9 +136,10 @@ class NODE_MT_node(bpy.types.Menu): layout.operator("transform.resize") layout.separator() - + layout.operator("node.duplicate_move") layout.operator("node.delete") + layout.operator("node.delete_reconnect") layout.separator() layout.operator("node.link_make") diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 3b6b4575e8e..d6d34eb8888 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -20,6 +20,7 @@ import bpy from blf import gettext as _ + class TIME_HT_header(bpy.types.Header): bl_space_type = 'TIMELINE' diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index a78a5ceba80..5f47ca7bc87 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -127,7 +127,7 @@ class USERPREF_MT_appconfigs(bpy.types.Menu): preset_operator = "wm.appconfig_activate" def draw(self, context): - props = self.layout.operator("wm.appconfig_default", text=_("Blender (default)")) + self.layout.operator("wm.appconfig_default", text=_("Blender (default)")) # now draw the presets bpy.types.Menu.draw_preset(self, context) @@ -850,7 +850,7 @@ class USERPREF_PT_input(bpy.types.Panel, InputKeyMapPanel): class USERPREF_MT_addons_dev_guides(bpy.types.Menu): - bl_label = _("Develoment Guides") + bl_label = _("Development Guides") # menu to open webpages with addons development guides def draw(self, context): @@ -877,6 +877,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 @@ -901,6 +914,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__ @@ -970,20 +986,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 = USERPREF_PT_addons.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} @@ -1105,7 +1125,6 @@ class WM_OT_addon_install(bpy.types.Operator): del pyfile_dir # done checking for exceptional case - addon_files_old = set(os.listdir(path_addons)) addons_old = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} #check to see if the file is in compressed format (.zip) @@ -1118,7 +1137,7 @@ class WM_OT_addon_install(bpy.types.Operator): if self.overwrite: for f in file_to_extract.namelist(): - __class__._module_remove(path_addons, f) + WM_OT_addon_install._module_remove(path_addons, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_addons, os.path.basename(f)) @@ -1142,7 +1161,7 @@ class WM_OT_addon_install(bpy.types.Operator): path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if self.overwrite: - __class__._module_remove(path_addons, os.path.basename(pyfile)) + WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) elif os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} @@ -1187,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 = WM_OT_addon_remove.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 = WM_OT_addon_remove.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" diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index 749c506a78a..feb90cadd68 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -22,6 +22,7 @@ import os from blf import gettext as _ from blf import fake_gettext as N_ + KM_HIERARCHY = [ ( N_('Window'), 'EMPTY', 'WINDOW', []), # file save, window change, exit ( N_('Screen'), 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot @@ -190,9 +191,9 @@ class InputKeyMapPanel: if km.is_modal: row.label(text="", icon='LINKED') if km.is_user_defined: - op = row.operator("wm.keymap_restore", text=_("Restore")) + row.operator("wm.keymap_restore", text=_("Restore")) else: - op = row.operator("wm.keymap_edit", text=_("Edit")) + row.operator("wm.keymap_edit", text=_("Edit")) if km.show_expanded_children: if children: @@ -214,7 +215,7 @@ class InputKeyMapPanel: col = self.indented_layout(col, level + 1) subcol = col.split(percentage=0.2).column() subcol.enabled = km.is_user_defined - op = subcol.operator("wm.keyitem_add", text=_("Add New"), icon='ZOOMIN') + subcol.operator("wm.keyitem_add", text=_("Add New"), icon='ZOOMIN') col.separator() @@ -235,7 +236,7 @@ class InputKeyMapPanel: for pname, value in properties.bl_rna.properties.items(): if pname != "rna_type" and not properties.is_property_hidden(pname): if isinstance(value, bpy.types.OperatorProperties): - __class__.draw_kmi_properties(box, value, title=pname) + InputKeyMapPanel.draw_kmi_properties(box, value, title=pname) else: flow.prop(properties, pname) @@ -326,7 +327,7 @@ class InputKeyMapPanel: # Operator properties props = kmi.properties if props is not None: - __class__.draw_kmi_properties(box, props) + InputKeyMapPanel.draw_kmi_properties(box, props) # Modal key maps attached to this operator if not km.is_modal: @@ -352,9 +353,9 @@ class InputKeyMapPanel: row.label() if km.is_user_defined: - op = row.operator("wm.keymap_restore", text=_("Restore")) + row.operator("wm.keymap_restore", text=_("Restore")) else: - op = row.operator("wm.keymap_edit", text=_("Edit")) + row.operator("wm.keymap_edit", text=_("Edit")) for kmi in filtered_items: self.draw_kmi(display_keymaps, kc, km, kmi, col, 1) @@ -363,7 +364,7 @@ class InputKeyMapPanel: col = self.indented_layout(layout, 1) subcol = col.split(percentage=0.2).column() subcol.enabled = km.is_user_defined - op = subcol.operator("wm.keyitem_add", text=_("Add New"), icon='ZOOMIN') + subcol.operator("wm.keyitem_add", text=_("Add New"), icon='ZOOMIN') def draw_hierarchy(self, display_keymaps, layout): for entry in KM_HIERARCHY: @@ -731,9 +732,7 @@ class WM_OT_keyitem_add(bpy.types.Operator): __doc__ = _("Add key map item") def execute(self, context): - wm = context.window_manager km = context.keymap - kc = wm.keyconfigs.default if km.is_modal: km.keymap_items.new_modal("", 'A', 'PRESS') # kmi diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 209ef13a312..9ead8bb98df 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -775,10 +775,16 @@ class VIEW3D_MT_object_specials(bpy.types.Menu): if obj.type == 'CAMERA': layout.operator_context = 'INVOKE_REGION_WIN' - props = layout.operator("wm.context_modal_mouse", text=_("Camera Lens Angle")) - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.lens" - props.input_scale = 0.1 + if obj.data.type == 'PERSP': + props = layout.operator("wm.context_modal_mouse", text=_("Camera Lens Angle")) + props.data_path_iter = "selected_editable_objects" + props.data_path_item = "data.lens" + props.input_scale = 0.1 + else: + props = layout.operator("wm.context_modal_mouse", text=_("Camera Lens Scale")) + props.data_path_iter = "selected_editable_objects" + props.data_path_item = "data.ortho_scale" + props.input_scale = 0.01 if not obj.data.dof_object: #layout.label(text="Test Has DOF obj"); @@ -1101,17 +1107,18 @@ class VIEW3D_MT_sculpt(bpy.types.Menu): layout.operator_menu_enum("brush.curve_preset", "shape") layout.separator() - sculpt_tool = brush.sculpt_tool + if brush is not None: # unlikely but can happen + sculpt_tool = brush.sculpt_tool - if sculpt_tool != 'GRAB': - layout.prop_menu_enum(brush, "stroke_method") + 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 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") + if sculpt_tool == 'LAYER': + layout.prop(brush, "use_persistent") + layout.operator("sculpt.set_persistent_base") layout.separator() layout.prop(sculpt, "use_threaded", text=_("Threaded Sculpt")) @@ -1246,7 +1253,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): @@ -1367,6 +1374,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 ********** @@ -1960,7 +2010,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): @@ -2361,7 +2411,7 @@ class VIEW3D_PT_context_properties(bpy.types.Panel): def draw(self, context): import rna_prop_ui - member = __class__._active_context_member(context) + member = VIEW3D_PT_context_properties._active_context_member(context) if member: # Draw with no edit button diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index b02f7dd75c1..f2370ec39ac 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -61,7 +61,6 @@ def draw_gpencil_tools(context, layout): # ********** default tools for objectmode **************** - class VIEW3D_PT_tools_objectmode(View3DPanel, bpy.types.Panel): bl_context = "objectmode" bl_label = _("Object Tools") @@ -467,7 +466,7 @@ class VIEW3D_PT_tools_brush(PaintPanel, bpy.types.Panel): def draw(self, context): layout = self.layout - settings = __class__.paint_settings(context) + settings = self.paint_settings(context) brush = settings.brush if not context.particle_edit_object: @@ -688,7 +687,7 @@ class VIEW3D_PT_tools_brush_texture(PaintPanel, bpy.types.Panel): def draw(self, context): layout = self.layout - settings = __class__.paint_settings(context) + settings = self.paint_settings(context) brush = settings.brush tex_slot = brush.texture_slot @@ -787,7 +786,7 @@ class VIEW3D_PT_tools_brush_tool(PaintPanel, bpy.types.Panel): def draw(self, context): layout = self.layout - settings = __class__.paint_settings(context) + settings = self.paint_settings(context) brush = settings.brush col = layout.column(align=True) @@ -822,7 +821,7 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel, bpy.types.Panel): def draw(self, context): layout = self.layout - settings = __class__.paint_settings(context) + settings = self.paint_settings(context) brush = settings.brush image_paint = context.image_paint_object @@ -945,7 +944,6 @@ class VIEW3D_PT_sculpt_options(PaintPanel, bpy.types.Panel): tool_settings = context.tool_settings sculpt = tool_settings.sculpt - settings = __class__.paint_settings(context) layout.label(text="Lock:") row = layout.row(align=True) @@ -975,7 +973,6 @@ class VIEW3D_PT_sculpt_symmetry(PaintPanel, bpy.types.Panel): layout = self.layout sculpt = context.tool_settings.sculpt - settings = __class__.paint_settings(context) split = layout.split() @@ -998,14 +995,22 @@ class VIEW3D_PT_tools_brush_appearance(PaintPanel, bpy.types.Panel): @classmethod def poll(cls, context): - return (context.sculpt_object and context.tool_settings.sculpt) or (context.vertex_paint_object and context.tool_settings.vertex_paint) or (context.weight_paint_object and context.tool_settings.weight_paint) or (context.image_paint_object and context.tool_settings.image_paint) + ts = context.tool_settings + return ((context.sculpt_object and ts.sculpt) or + (context.vertex_paint_object and ts.vertex_paint) or + (context.weight_paint_object and ts.weight_paint) or + (context.image_paint_object and ts.image_paint)) def draw(self, context): layout = self.layout - settings = __class__.paint_settings(context) + settings = self.paint_settings(context) brush = settings.brush + if brush is None: # unlikely but can happen + layout.label(text=_("Brush Unset")) + return + col = layout.column() if context.sculpt_object and context.tool_settings.sculpt: diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py index 8cb63ea48cf..dcc1afed74b 100644 --- a/release/scripts/startup/keyingsets_builtins.py +++ b/release/scripts/startup/keyingsets_builtins.py @@ -407,7 +407,7 @@ class BUILTIN_KSI_DeltaRotation(bpy.types.KeyingSetInfo): # add the property name to the base path # rotation mode affects the property used if data.rotation_mode == 'QUATERNION': - path = path_add_property(base_path, "delta_rotation_quaternion") + path = keyingsets_utils.path_add_property(base_path, "delta_rotation_quaternion") elif data.rotation_mode == 'AXIS_ANGLE': # XXX: for now, this is not available yet #path = path_add_property(base_path, "delta_rotation_axis_angle") |