Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2015-06-29 17:41:00 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2015-06-29 18:18:11 +0300
commitd140e70c496122915eb5c05aba83153e2e0d7998 (patch)
tree1e589247d69da64aa7b0e7802319237ec050b5d6 /release
parent147bd16ed1bb3415b30408b0eab110d0854eadd2 (diff)
parent295d0c52a26730edc6d4ed1276e4051cce006be5 (diff)
Merge branch 'master' into temp-ghash-experimentstemp-ghash-experiments
Note that 'store hash' feature was removed for now - to complex to maintain (conflicts) and relatively easy to re-add if we ever really want this one day. Conflicts: source/blender/blenlib/BLI_ghash.h source/blender/blenlib/intern/BLI_ghash.c source/blender/blenlib/intern/hash_mm2a.c source/blender/bmesh/tools/bmesh_region_match.c tests/gtests/blenlib/BLI_ghash_performance_test.cc tests/gtests/blenlib/BLI_ghash_test.cc tests/gtests/blenlib/CMakeLists.txt
Diffstat (limited to 'release')
-rwxr-xr-xrelease/bin/blender-thumbnailer.py6
-rw-r--r--release/datafiles/fonts/droidsans.ttf.gzbin2644887 -> 2466802 bytes
-rw-r--r--release/datafiles/splash.pngbin166788 -> 187546 bytes
-rw-r--r--release/datafiles/splash_2x.pngbin625100 -> 632582 bytes
-rw-r--r--release/scripts/freestyle/modules/freestyle/functions.py6
-rw-r--r--release/scripts/freestyle/modules/freestyle/predicates.py53
-rw-r--r--release/scripts/freestyle/modules/freestyle/shaders.py8
-rw-r--r--release/scripts/freestyle/modules/freestyle/utils.py110
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py15
-rw-r--r--release/scripts/modules/addon_utils.py114
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py19
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py23
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py33
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_languages_menu.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py4
-rw-r--r--release/scripts/modules/bpy/path.py67
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py (renamed from release/scripts/modules/bpy/utils.py)7
-rw-r--r--release/scripts/modules/bpy/utils/previews.py153
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py39
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py13
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py18
-rw-r--r--release/scripts/modules/bpy_types.py40
-rw-r--r--release/scripts/modules/nodeitems_utils.py10
-rw-r--r--release/scripts/modules/rna_info.py9
-rw-r--r--release/scripts/modules/rna_prop_ui.py13
-rw-r--r--release/scripts/modules/rna_xml.py2
-rw-r--r--release/scripts/presets/keyconfig/3dsmax.py3
-rw-r--r--release/scripts/presets/keyconfig/maya.py12
-rw-r--r--release/scripts/startup/bl_operators/__init__.py2
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py18
-rw-r--r--release/scripts/startup/bl_operators/anim.py13
-rw-r--r--release/scripts/startup/bl_operators/clip.py12
-rw-r--r--release/scripts/startup/bl_operators/image.py3
-rw-r--r--release/scripts/startup/bl_operators/mask.py1
-rw-r--r--release/scripts/startup/bl_operators/mesh.py1
-rw-r--r--release/scripts/startup/bl_operators/object.py8
-rw-r--r--release/scripts/startup/bl_operators/object_align.py10
-rw-r--r--release/scripts/startup/bl_operators/presets.py23
-rw-r--r--release/scripts/startup/bl_operators/screen_play_rendered_anim.py11
-rw-r--r--release/scripts/startup/bl_operators/wm.py38
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py44
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py14
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py56
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py15
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py49
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py19
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_render_layer.py65
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py35
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py5
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py21
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py44
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py15
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py24
-rw-r--r--release/scripts/startup/bl_ui/space_image.py20
-rw-r--r--release/scripts/startup/bl_ui/space_info.py4
-rw-r--r--release/scripts/startup/bl_ui/space_logic.py11
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py2
-rw-r--r--release/scripts/startup/bl_ui/space_node.py11
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py88
-rw-r--r--release/scripts/startup/bl_ui/space_time.py7
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py18
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py127
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py59
-rw-r--r--release/scripts/startup/nodeitems_builtins.py3
-rw-r--r--release/scripts/templates_py/addon_add_object.py5
-rw-r--r--release/scripts/templates_py/operator_modal_timer.py3
-rw-r--r--release/scripts/templates_py/ui_previews_custom_icon.py76
-rw-r--r--release/scripts/templates_py/ui_previews_dynamic_enum.py137
-rw-r--r--release/windows/installer/00.sconsblender.nsi7
81 files changed, 1518 insertions, 456 deletions
diff --git a/release/bin/blender-thumbnailer.py b/release/bin/blender-thumbnailer.py
index 779c6156e70..d3b31d63fad 100755
--- a/release/bin/blender-thumbnailer.py
+++ b/release/bin/blender-thumbnailer.py
@@ -170,7 +170,7 @@ def write_png(buf, width, height):
png_pack(b'IEND', b'')])
-if __name__ == '__main__':
+def main():
import sys
if len(sys.argv) < 3:
@@ -186,3 +186,7 @@ if __name__ == '__main__':
f = open(file_out, "wb")
f.write(write_png(buf, width, height))
f.close()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/release/datafiles/fonts/droidsans.ttf.gz b/release/datafiles/fonts/droidsans.ttf.gz
index c76cf67992c..a685c590795 100644
--- a/release/datafiles/fonts/droidsans.ttf.gz
+++ b/release/datafiles/fonts/droidsans.ttf.gz
Binary files differ
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index a3e9afe6403..cfadec07b09 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png
index d45b9952633..79a6f2781ff 100644
--- a/release/datafiles/splash_2x.png
+++ b/release/datafiles/splash_2x.png
Binary files differ
diff --git a/release/scripts/freestyle/modules/freestyle/functions.py b/release/scripts/freestyle/modules/freestyle/functions.py
index 48d9b2e2b39..426d344e8ab 100644
--- a/release/scripts/freestyle/modules/freestyle/functions.py
+++ b/release/scripts/freestyle/modules/freestyle/functions.py
@@ -189,11 +189,13 @@ class CurveMaterialF0D(UnaryFunction0DMaterial):
priority is used to pick one of the two materials at material
boundaries.
- Note: expects instances of CurvePoint to be iterated over
+ Notes: expects instances of CurvePoint to be iterated over
+ can return None if no fedge can be found
"""
def __call__(self, inter):
fe = inter.object.fedge
- assert(fe is not None), "CurveMaterialF0D: fe is None"
+ if fe is None:
+ return None
if fe.is_smooth:
return fe.material
else:
diff --git a/release/scripts/freestyle/modules/freestyle/predicates.py b/release/scripts/freestyle/modules/freestyle/predicates.py
index 54656e450d9..5cbe577b956 100644
--- a/release/scripts/freestyle/modules/freestyle/predicates.py
+++ b/release/scripts/freestyle/modules/freestyle/predicates.py
@@ -43,6 +43,7 @@ __all__ = (
"FalseUP0D",
"FalseUP1D",
"Length2DBP1D",
+ "MaterialBP1D",
"NotBP1D",
"NotUP1D",
"ObjectNamesUP1D",
@@ -150,12 +151,13 @@ from freestyle.functions import (
pyViewMapGradientNormF1D,
)
+from freestyle.utils import material_from_fedge
+
import random
# -- Unary predicates for 0D elements (vertices) -- #
-
class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D):
def __init__(self, a):
UnaryPredicate0D.__init__(self)
@@ -234,9 +236,10 @@ class AndUP1D(UnaryPredicate1D):
def __init__(self, *predicates):
UnaryPredicate1D.__init__(self)
self.predicates = predicates
- # there are cases in which only one predicate is supplied (in the parameter editor)
- if len(self.predicates) < 1:
- raise ValueError("Expected one or more UnaryPredicate1D, got ", len(predicates))
+ correct_types = all(isinstance(p, UnaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more UnaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, inter):
return all(pred(inter) for pred in self.predicates)
@@ -246,9 +249,10 @@ class OrUP1D(UnaryPredicate1D):
def __init__(self, *predicates):
UnaryPredicate1D.__init__(self)
self.predicates = predicates
- # there are cases in which only one predicate is supplied (in the parameter editor)
- if len(self.predicates) < 1:
- raise ValueError("Expected one or more UnaryPredicate1D, got ", len(predicates))
+ correct_types = all(isinstance(p, UnaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more UnaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, inter):
return any(pred(inter) for pred in self.predicates)
@@ -257,10 +261,10 @@ class OrUP1D(UnaryPredicate1D):
class NotUP1D(UnaryPredicate1D):
def __init__(self, pred):
UnaryPredicate1D.__init__(self)
- self.__pred = pred
+ self.predicate = pred
def __call__(self, inter):
- return not self.__pred(inter)
+ return not self.predicate(inter)
class ObjectNamesUP1D(UnaryPredicate1D):
@@ -563,32 +567,36 @@ class pyClosedCurveUP1D(UnaryPredicate1D):
class AndBP1D(BinaryPredicate1D):
def __init__(self, *predicates):
BinaryPredicate1D.__init__(self)
- self._predicates = predicates
- if len(self.predicates) < 2:
- raise ValueError("Expected two or more BinaryPredicate1D, got ", len(predictates))
+ self.predicates = tuple(predicates)
+ correct_types = all(isinstance(p, BinaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more BinaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, i1, i2):
- return all(pred(i1, i2) for pred in self._predicates)
+ return all(pred(i1, i2) for pred in self.predicates)
class OrBP1D(BinaryPredicate1D):
def __init__(self, *predicates):
BinaryPredicate1D.__init__(self)
- self._predicates = predicates
- if len(self.predicates) < 2:
- raise ValueError("Expected two or more BinaryPredicate1D, got ", len(predictates))
+ self.predicates = tuple(predicates)
+ correct_types = all(isinstance(p, BinaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more BinaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, i1, i2):
- return any(pred(i1, i2) for pred in self._predicates)
+ return any(pred(i1, i2) for pred in self.predicates)
class NotBP1D(BinaryPredicate1D):
def __init__(self, predicate):
BinaryPredicate1D.__init__(self)
- self._predicate = predicate
+ self.predicate = predicate
def __call__(self, i1, i2):
- return (not self._predicate(i1, i2))
+ return (not self.predicate(i1, i2))
class pyZBP1D(BinaryPredicate1D):
@@ -663,3 +671,10 @@ class pyShuffleBP1D(BinaryPredicate1D):
def __call__(self, inter1, inter2):
return (random.uniform(0, 1) < random.uniform(0, 1))
+
+class MaterialBP1D(BinaryPredicate1D):
+ """Checks whether the two supplied ViewEdges have the same material."""
+ def __call__(self, i1, i2):
+ fedges = (fe for ve in (i1, i2) for fe in (ve.first_fedge, ve.last_fedge))
+ materials = {material_from_fedge(fe) for fe in fedges}
+ return len(materials) < 2
diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py
index 61365e8dd87..127db3fcd4b 100644
--- a/release/scripts/freestyle/modules/freestyle/shaders.py
+++ b/release/scripts/freestyle/modules/freestyle/shaders.py
@@ -138,7 +138,7 @@ from freestyle.predicates import (
from freestyle.utils import (
bound,
- bounding_box,
+ BoundingBox,
phase_to_direction,
)
@@ -865,7 +865,7 @@ class pyBluePrintCirclesShader(StrokeShader):
def shade(self, stroke):
# get minimum and maximum coordinates
- p_min, p_max = bounding_box(stroke)
+ p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners
stroke.resample(32 * self.__turns)
sv_nb = len(stroke) // self.__turns
@@ -917,7 +917,7 @@ class pyBluePrintEllipsesShader(StrokeShader):
self.__random_radius = random_radius
def shade(self, stroke):
- p_min, p_max = bounding_box(stroke)
+ p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners
stroke.resample(32 * self.__turns)
sv_nb = len(stroke) // self.__turns
@@ -964,7 +964,7 @@ class pyBluePrintSquaresShader(StrokeShader):
return
# get minimum and maximum coordinates
- p_min, p_max = bounding_box(stroke)
+ p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners
stroke.resample(32 * self.__turns)
num_segments = len(stroke) // self.__turns
diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py
index 224734d5bfb..41d2297f723 100644
--- a/release/scripts/freestyle/modules/freestyle/utils.py
+++ b/release/scripts/freestyle/modules/freestyle/utils.py
@@ -22,24 +22,29 @@ writing.
"""
__all__ = (
- "ContextFunctions",
"bound",
- "bounding_box",
+ "BoundingBox",
+ "ContextFunctions",
"find_matching_vertex",
- "getCurrentScene",
"get_chain_length",
+ "get_object_name",
+ "get_strokes",
"get_test_stroke",
+ "getCurrentScene",
"integrate",
+ "is_poly_clockwise",
"iter_distance_along_stroke",
"iter_distance_from_camera",
"iter_distance_from_object",
"iter_material_value",
"iter_t2d_along_stroke",
+ "material_from_fedge",
"pairwise",
"phase_to_direction",
"rgb_to_bw",
"stroke_curvature",
"stroke_normal",
+ "StrokeCollector",
"tripplewise",
)
@@ -55,6 +60,7 @@ from _freestyle import (
from freestyle.types import (
Interface0DIterator,
Stroke,
+ StrokeShader,
StrokeVertexIterator,
)
@@ -79,12 +85,38 @@ def bound(lower, x, higher):
return (lower if x <= lower else higher if x >= higher else x)
-def bounding_box(stroke):
- """
- Returns the maximum and minimum coordinates (the bounding box) of the stroke's vertices
- """
- x, y = zip(*(svert.point for svert in stroke))
- return (Vector((min(x), min(y))), Vector((max(x), max(y))))
+def get_strokes():
+ """Get all strokes that are currently available"""
+ return tuple(map(Operators().get_stroke_from_index, range(Operators().get_strokes_size())))
+
+
+def is_poly_clockwise(stroke):
+ """True if the stroke is orientated in a clockwise way, False otherwise"""
+ v = sum((v2.point.x - v1.point.x) * (v1.point.y + v2.point.y) for v1, v2 in pairwise(stroke))
+ v1, v2 = stroke[0], stroke[-1]
+ if (v1.point - v2.point).length > 1e-3:
+ v += (v2.point.x - v1.point.x) * (v1.point.y + v2.point.y)
+ return v > 0
+
+
+def get_object_name(stroke):
+ """Returns the name of the object that this stroke is drawn on."""
+ fedge = stroke[0].fedge
+ if fedge is None:
+ return None
+ return fedge.viewedge.viewshape.name
+
+
+def material_from_fedge(fe):
+ "get the diffuse rgba color from an FEdge"
+ if fe is None:
+ return None
+ if fe.is_smooth:
+ material = fe.material
+ else:
+ right, left = fe.material_right, fe.material_left
+ material = right if (right.priority > left.priority) else left
+ return material
# -- General helper functions -- #
@@ -106,6 +138,54 @@ def phase_to_direction(length):
# lower bound (e.g., thickness, range and certain values)
BoundedProperty = namedtuple("BoundedProperty", ["min", "max", "delta"])
+
+class BoundingBox:
+ """Object representing a bounding box consisting out of 2 2D vectors"""
+
+ __slots__ = (
+ "minimum",
+ "maximum",
+ "size",
+ "corners",
+ )
+
+ def __init__(self, minimum: Vector, maximum: Vector):
+ self.minimum = minimum
+ self.maximum = maximum
+ if len(minimum) != len(maximum):
+ raise TypeError("Expected two vectors of size 2, got", minimum, maximum)
+ self.size = len(minimum)
+ self.corners = (minimum, maximum)
+
+ def __repr__(self):
+ return "BoundingBox(%r, %r)" % (self.minimum, self.maximum)
+
+ @classmethod
+ def from_sequence(cls, sequence):
+ """BoundingBox from sequence of 2D or 3D Vector objects"""
+ x, y = zip(*sequence)
+ mini = Vector((min(x), min(y)))
+ maxi = Vector((max(x), max(y)))
+ return cls(mini, maxi)
+
+ def inside(self, other):
+ """True if self inside other, False otherwise"""
+ if self.size != other.size:
+ raise TypeError("Expected two BoundingBox of the same size, got", self, other)
+ return (self.minimum.x >= other.minimum.x and self.minimum.y >= other.minimum.y and
+ self.maximum.x <= other.maximum.x and self.maximum.y <= other.maximum.y)
+
+
+class StrokeCollector(StrokeShader):
+ "Collects and Stores stroke objects"
+ def __init__(self):
+ StrokeShader.__init__(self)
+ self.strokes = []
+
+ def shade(self, stroke):
+ self.strokes.append(stroke)
+
+
# -- helper functions for chaining -- #
def get_chain_length(ve, orientation):
@@ -147,6 +227,7 @@ def find_matching_vertex(id, it):
"""Finds the matching vertex, or returns None."""
return next((ve for ve in it if ve.id == id), None)
+
# -- helper functions for iterating -- #
def pairwise(iterable, types={Stroke, StrokeVertexIterator}):
@@ -210,7 +291,7 @@ def iter_distance_from_object(stroke, location, range_min, range_max, normfac):
def iter_material_value(stroke, func, attribute):
- "Yields a specific material attribute from the vertex' underlying material."
+ """Yields a specific material attribute from the vertex' underlying material."""
it = Interface0DIterator(stroke)
for svert in it:
material = func(it)
@@ -252,8 +333,9 @@ def iter_material_value(stroke, func, attribute):
raise ValueError("unexpected material attribute: " + attribute)
yield (svert, value)
+
def iter_distance_along_stroke(stroke):
- "Yields the absolute distance along the stroke up to the current vertex."
+ """Yields the absolute distance along the stroke up to the current vertex."""
distance = 0.0
# the positions need to be copied, because they are changed in the calling function
points = tuple(svert.point.copy() for svert in stroke)
@@ -295,6 +377,7 @@ def stroke_curvature(it):
yield abs(K)
+
def stroke_normal(stroke):
"""
Compute the 2D normal at the stroke vertex pointed by the iterator
@@ -304,7 +387,7 @@ def stroke_normal(stroke):
The returned normals are dynamic: they update when the
vertex position (and therefore the vertex normal) changes.
- for use in geometry modifiers it is advised to
+ for use in geometry modifiers it is advised to
cast this generator function to a tuple or list
"""
n = len(stroke) - 1
@@ -323,12 +406,13 @@ def stroke_normal(stroke):
n2 = Vector((e2[1], -e2[0])).normalized()
yield (n1 + n2).normalized()
+
def get_test_stroke():
"""Returns a static stroke object for testing """
from freestyle.types import Stroke, Interface0DIterator, StrokeVertexIterator, SVertex, Id, StrokeVertex
# points for our fake stroke
points = (Vector((1.0, 5.0, 3.0)), Vector((1.0, 2.0, 9.0)),
- Vector((6.0, 2.0, 3.0)), Vector((7.0, 2.0, 3.0)),
+ Vector((6.0, 2.0, 3.0)), Vector((7.0, 2.0, 3.0)),
Vector((2.0, 6.0, 3.0)), Vector((2.0, 8.0, 3.0)))
ids = (Id(0, 0), Id(1, 1), Id(2, 2), Id(3, 3), Id(4, 4), Id(5, 5))
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index d4765847450..3c11c33a39d 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -960,11 +960,11 @@ def process(layer_name, lineset_name):
if lineset.select_external_contour:
upred = ExternalContourUP1D()
edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_external_contour else upred)
- if lineset.edge_type_combination == 'OR':
- upred = OrUP1D(*edge_type_criteria)
- else:
- upred = AndUP1D(*edge_type_criteria)
- if upred is not None:
+ if edge_type_criteria:
+ if lineset.edge_type_combination == 'OR':
+ upred = OrUP1D(*edge_type_criteria)
+ else:
+ upred = AndUP1D(*edge_type_criteria)
if lineset.edge_type_negation == 'EXCLUSIVE':
upred = NotUP1D(upred)
selection_criteria.append(upred)
@@ -989,8 +989,9 @@ def process(layer_name, lineset_name):
upred = WithinImageBoundaryUP1D(*ContextFunctions.get_border())
selection_criteria.append(upred)
# select feature edges
- upred = AndUP1D(*selection_criteria)
- if upred is None:
+ if selection_criteria:
+ upred = AndUP1D(*selection_criteria)
+ else:
upred = TrueUP1D()
Operators.select(upred)
# join feature edges to form chains
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 8c86f31022c..123b3cb953c 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -74,40 +74,43 @@ def modules_refresh(module_cache=addons_fake_modules):
print("fake_module", mod_path, mod_name)
import ast
ModuleType = type(ast)
- file_mod = open(mod_path, "r", encoding='UTF-8')
- if speedy:
- lines = []
- line_iter = iter(file_mod)
- l = ""
- while not l.startswith("bl_info"):
- try:
- l = line_iter.readline()
- except UnicodeDecodeError as e:
- if not error_encoding:
- error_encoding = True
- print("Error reading file as UTF-8:", mod_path, e)
- file_mod.close()
- return None
-
- if len(l) == 0:
- break
- while l.rstrip():
- lines.append(l)
- try:
- l = line_iter.readline()
- except UnicodeDecodeError as e:
- if not error_encoding:
- error_encoding = True
- print("Error reading file as UTF-8:", mod_path, e)
- file_mod.close()
- return None
-
- data = "".join(lines)
+ try:
+ file_mod = open(mod_path, "r", encoding='UTF-8')
+ except OSError as e:
+ print("Error opening file %r: %s" % (mod_path, e))
+ return None
- else:
- data = file_mod.read()
+ with file_mod:
+ if speedy:
+ lines = []
+ line_iter = iter(file_mod)
+ l = ""
+ while not l.startswith("bl_info"):
+ try:
+ l = line_iter.readline()
+ except UnicodeDecodeError as e:
+ if not error_encoding:
+ error_encoding = True
+ print("Error reading file as UTF-8:", mod_path, e)
+ return None
+
+ if len(l) == 0:
+ break
+ while l.rstrip():
+ lines.append(l)
+ try:
+ l = line_iter.readline()
+ except UnicodeDecodeError as e:
+ if not error_encoding:
+ error_encoding = True
+ print("Error reading file as UTF-8:", mod_path, e)
+ return None
+
+ data = "".join(lines)
- file_mod.close()
+ else:
+ data = file_mod.read()
+ del file_mod
try:
ast_data = ast.parse(data, filename=mod_path)
@@ -216,7 +219,8 @@ def check(module_name):
loaded_default = module_name in _user_preferences.addons
mod = sys.modules.get(module_name)
- loaded_state = mod and getattr(mod, "__addon_enabled__", Ellipsis)
+ loaded_state = ((mod is not None) and
+ getattr(mod, "__addon_enabled__", Ellipsis))
if loaded_state is Ellipsis:
print("Warning: addon-module %r found module "
@@ -274,6 +278,20 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
mod = sys.modules.get(module_name)
# chances of the file _not_ existing are low, but it could be removed
if mod and os.path.exists(mod.__file__):
+
+ if getattr(mod, "__addon_enabled__", False):
+ # This is an unlikely situation,
+ # re-register if the module is enabled.
+ # Note: the UI doesn't allow this to happen,
+ # in most cases the caller should 'check()' first.
+ try:
+ mod.unregister()
+ except:
+ print("Exception in module unregister(): %r" %
+ getattr(mod, "__file__", module_name))
+ handle_error()
+ return None
+
mod.__addon_enabled__ = False
mtime_orig = getattr(mod, "__time__", 0)
mtime_new = os.path.getmtime(mod.__file__)
@@ -342,7 +360,7 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
return mod
-def disable(module_name, default_set=True, handle_error=None):
+def disable(module_name, default_set=False, handle_error=None):
"""
Disables an addon by name.
@@ -416,19 +434,21 @@ def reset_all(reload_scripts=False):
disable(mod_name)
-def module_bl_info(mod, info_basis={"name": "",
- "author": "",
- "version": (),
- "blender": (),
- "location": "",
- "description": "",
- "wiki_url": "",
- "support": 'COMMUNITY',
- "category": "",
- "warning": "",
- "show_expanded": False,
- }
- ):
+def module_bl_info(mod, info_basis=None):
+ if info_basis is None:
+ info_basis = {
+ "name": "",
+ "author": "",
+ "version": (),
+ "blender": (),
+ "location": "",
+ "description": "",
+ "wiki_url": "",
+ "support": 'COMMUNITY',
+ "category": "",
+ "warning": "",
+ "show_expanded": False,
+ }
addon_info = getattr(mod, "bl_info", {})
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index c3b2ae9908b..43a09a1acbd 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -64,7 +64,7 @@ def _gen_check_ctxt(settings):
def _diff_check_ctxt(check_ctxt, minus_check_ctxt):
- """Returns check_ctxt - minus_check_ctxt"""
+ """Removes minus_check_ctxt from check_ctxt"""
for key in check_ctxt:
if isinstance(check_ctxt[key], set):
for warning in minus_check_ctxt[key]:
@@ -576,8 +576,9 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
#print(func_translate_args)
# Break recursive nodes look up on some kind of nodes.
- # E.g. we don’t want to get strings inside subscripts (blah["foo"])!
- stopper_nodes = {ast.Subscript}
+ # E.g. we don't want to get strings inside subscripts (blah["foo"])!
+ # we don't want to get strings from comparisons (foo.type == 'BAR').
+ stopper_nodes = {ast.Subscript, ast.Compare}
# Consider strings separate: ("a" if test else "b")
separate_nodes = {ast.IfExp}
@@ -897,7 +898,7 @@ def dump_addon_messages(module_name, do_checks, settings):
del msgs[key]
if check_ctxt:
- check_ctxt = _diff_check_ctxt(check_ctxt, minus_check_ctxt)
+ _diff_check_ctxt(check_ctxt, minus_check_ctxt)
# and we are done with those!
del minus_pot
@@ -924,18 +925,18 @@ def main():
return
import sys
- back_argv = sys.argv
+ import argparse
+
# Get rid of Blender args!
- sys.argv = sys.argv[sys.argv.index("--") + 1:]
+ argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
- import argparse
parser = argparse.ArgumentParser(description="Process UI messages from inside Blender.")
parser.add_argument('-c', '--no_checks', default=True, action="store_false", help="No checks over UI messages.")
parser.add_argument('-m', '--no_messages', default=True, action="store_false", help="No export of UI messages.")
parser.add_argument('-o', '--output', default=None, help="Output POT file path.")
parser.add_argument('-s', '--settings', default=None,
help="Override (some) default settings. Either a JSon file name, or a JSon string.")
- args = parser.parse_args()
+ args = parser.parse_args(argv)
settings = settings_i18n.I18nSettings()
settings.from_json(args.settings)
@@ -945,8 +946,6 @@ def main():
dump_messages(do_messages=args.no_messages, do_checks=args.no_checks, settings=settings)
- sys.argv = back_argv
-
if __name__ == "__main__":
print("\n\n *** Running {} *** \n".format(__file__))
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 920a56a628b..1c960a217de 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -88,6 +88,7 @@ LANGUAGES = (
(38, "Uzbek (Oʻzbek)", "uz_UZ"),
(39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"),
(40, "Hindi (मानक हिन्दी)", "hi_IN"),
+ (41, "Vietnamese (tiếng Việt)", "vi_VN"),
)
# Default context, in py!
@@ -324,6 +325,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"y",
# Sub-strings.
"available with",
+ "brown fox",
"can't save image while rendering",
"expected a timeline/animation area to be active",
"expected a view3d region",
@@ -332,6 +334,8 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"image file not found",
"image path can't be written to",
"in memory to enable editing!",
+ "jumps over",
+ "the lazy dog",
"unable to load movie clip",
"unable to load text",
"unable to open the file",
@@ -412,6 +416,15 @@ REL_TRUNK_PO_DIR = os.path.join(REL_TRUNK_DIR, "po")
# The /trunk/mo path (relative to I18N_DIR).
REL_TRUNK_MO_DIR = os.path.join(REL_TRUNK_DIR, "locale")
+
+# The path to the *git* translation repository (relative to SOURCE_DIR).
+REL_GIT_I18N_DIR = os.path.join("release/datafiles/locale")
+
+
+# The /po path of the *git* translation repository (relative to REL_GIT_I18N_DIR).
+REL_GIT_I18N_PO_DIR = os.path.join("po")
+
+
# The Blender source path to check for i18n macros (relative to SOURCE_DIR).
REL_POTFILES_SOURCE_DIR = os.path.join("source")
@@ -493,14 +506,6 @@ def _gen_get_set_path(ref, name):
return _get, _set
-def _gen_get_set_paths(ref, name):
- def _get(self):
- return [_do_get(getattr(self, ref), p) for p in getattr(self, name)]
- def _set(self, value):
- setattr(self, name, [_do_set(getattr(self, ref), p) for p in value])
- return _get, _set
-
-
class I18nSettings:
"""
Class allowing persistence of our settings!
@@ -552,6 +557,8 @@ class I18nSettings:
TRUNK_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_DIR")))
TRUNK_PO_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_PO_DIR")))
TRUNK_MO_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_MO_DIR")))
+ GIT_I18N_ROOT = property(*(_gen_get_set_path("SOURCE_DIR", "REL_GIT_I18N_DIR")))
+ GIT_I18N_PO_DIR = property(*(_gen_get_set_path("GIT_I18N_ROOT", "REL_GIT_I18N_PO_DIR")))
POTFILES_SOURCE_DIR = property(*(_gen_get_set_path("SOURCE_DIR", "REL_POTFILES_SOURCE_DIR")))
FILE_NAME_POT = property(*(_gen_get_set_path("I18N_DIR", "REL_FILE_NAME_POT")))
MO_PATH_ROOT = property(*(_gen_get_set_path("I18N_DIR", "REL_MO_PATH_ROOT")))
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index 524fef909e8..5fdb6b88cbf 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -162,7 +162,7 @@ def get_po_files_from_dir(root_dir, langs=set()):
yield uid, po_file
-def enable_addons(addons={}, support={}, disable=False, check_only=False):
+def enable_addons(addons=None, support=None, disable=False, check_only=False):
"""
Enable (or disable) addons based either on a set of names, or a set of 'support' types.
Returns the list of all affected addons (as fake modules)!
@@ -170,6 +170,11 @@ def enable_addons(addons={}, support={}, disable=False, check_only=False):
"""
import addon_utils
+ if addons is None:
+ addons = {}
+ if support is None:
+ support = {}
+
userpref = bpy.context.user_preferences
used_ext = {ext.module for ext in userpref.addons}
@@ -212,13 +217,13 @@ class I18nMessage:
__slots__ = ("msgctxt_lines", "msgid_lines", "msgstr_lines", "comment_lines", "is_fuzzy", "is_commented",
"settings")
- def __init__(self, msgctxt_lines=[], msgid_lines=[], msgstr_lines=[], comment_lines=[],
+ def __init__(self, msgctxt_lines=None, msgid_lines=None, msgstr_lines=None, comment_lines=None,
is_commented=False, is_fuzzy=False, settings=settings):
self.settings = settings
- self.msgctxt_lines = msgctxt_lines
- self.msgid_lines = msgid_lines
- self.msgstr_lines = msgstr_lines
- self.comment_lines = comment_lines
+ self.msgctxt_lines = msgctxt_lines or []
+ self.msgid_lines = msgid_lines or []
+ self.msgstr_lines = msgstr_lines or []
+ self.comment_lines = comment_lines or []
self.is_fuzzy = is_fuzzy
self.is_commented = is_commented
@@ -976,13 +981,13 @@ class I18nMessages:
def write(self, kind, dest):
self.writers[kind](self, dest)
- def write_messages_to_po(self, fname):
+ def write_messages_to_po(self, fname, compact=False):
"""
Write messages in fname po file.
"""
default_context = self.settings.DEFAULT_CONTEXT
- def _write(self, f):
+ def _write(self, f, compact):
_msgctxt = self.settings.PO_MSGCTXT
_msgid = self.settings.PO_MSGID
_msgstr = self.settings.PO_MSGSTR
@@ -991,9 +996,12 @@ class I18nMessages:
self.escape()
for num, msg in enumerate(self.msgs.values()):
- f.write("\n".join(msg.comment_lines))
+ if compact and (msg.is_commented or msg.is_fuzzy or not msg.msgstr_lines):
+ continue
+ if not compact:
+ f.write("\n".join(msg.comment_lines))
# Only mark as fuzzy if msgstr is not empty!
- if msg.is_fuzzy and msg.msgstr:
+ if msg.is_fuzzy and msg.msgstr_lines:
f.write("\n" + self.settings.PO_COMMENT_FUZZY)
_p = _comm if msg.is_commented else ""
chunks = []
@@ -1030,10 +1038,10 @@ class I18nMessages:
self.normalize(max_len=0) # No wrapping for now...
if isinstance(fname, str):
with open(fname, 'w', encoding="utf-8") as f:
- _write(self, f)
+ _write(self, f, compact)
# Else assume fname is already a file(like) object!
else:
- _write(self, fname)
+ _write(self, fname, compact)
def write_messages_to_mo(self, fname):
"""
@@ -1112,6 +1120,7 @@ class I18nMessages:
writers = {
"PO": write_messages_to_po,
+ "PO_COMPACT": lambda s, fn: s.write_messages_to_po(fn, True),
"MO": write_messages_to_mo,
}
diff --git a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
index 24255d9be61..4f499476ad9 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
@@ -95,3 +95,5 @@ def gen_menu_file(stats, settings):
data_lines.append("# {} #{}:{}:{}".format(FLAG_MESSAGES[flag], uid_num, label, uid))
with open(os.path.join(settings.TRUNK_MO_DIR, settings.LANGUAGES_FILE), 'w') as f:
f.write("\n".join(data_lines))
+ with open(os.path.join(settings.GIT_I18N_ROOT, settings.LANGUAGES_FILE), 'w') as f:
+ f.write("\n".join(data_lines))
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index 4126dde1225..42a23c8c041 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -125,6 +125,7 @@ class SpellChecker:
"multisampling",
"multitexture",
"multiuser",
+ "multiview",
"namespace",
"keyconfig",
"online",
@@ -186,6 +187,7 @@ class SpellChecker:
"unhide",
"unindent",
"unkeyed",
+ "unmute",
"unpremultiply",
"unprojected",
"unreacted",
@@ -576,6 +578,8 @@ class SpellChecker:
"btx",
"cineon",
"dpx",
+ "dwaa",
+ "dwab",
"dxf",
"eps",
"exr",
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 25a6c7242e0..d5b64933165 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -116,7 +116,11 @@ def is_subdir(path, directory):
from os.path import normpath, normcase
path = normpath(normcase(path))
directory = normpath(normcase(directory))
- return path.startswith(directory)
+ if len(path) > len(directory):
+ if path.startswith(directory):
+ sep = ord(_os.sep) if isinstance(directory, bytes) else _os.sep
+ return (path[len(directory)] == sep)
+ return False
def clean_name(name, replace="_"):
@@ -128,23 +132,47 @@ def clean_name(name, replace="_"):
or the replace argument if defined.
"""
- bad_chars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
- "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d"
- "\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c"
- "\x2e\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x40\x5b\x5c\x5d\x5e\x60\x7b"
- "\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a"
- "\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99"
- "\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
- "\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
- "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6"
- "\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5"
- "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
- "\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3"
- "\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe")
-
- for ch in bad_chars:
- name = name.replace(ch, replace)
- return name
+ if replace != "_":
+ if len(replace) != 1 or ord(replace) > 255:
+ raise ValueError("Value must be a single ascii character")
+
+ def maketrans_init():
+ trans_cache = clean_name._trans_cache
+ trans = trans_cache.get(replace)
+ if trans is None:
+ bad_chars = (
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2e, 0x2f, 0x3a,
+ 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x5b, 0x5c,
+ 0x5d, 0x5e, 0x60, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
+ )
+ trans = str.maketrans({char: replace for char in bad_chars})
+ trans_cache[replace] = trans
+ return trans
+
+ trans = maketrans_init()
+ return name.translate(trans)
+clean_name._trans_cache = {}
def _clean_utf8(name):
@@ -222,7 +250,8 @@ def resolve_ncase(path):
if _os.path.isdir(dirpath):
try:
files = _os.listdir(dirpath)
- except PermissionError: # We might not have the permission to list dirpath...
+ except PermissionError:
+ # We might not have the permission to list dirpath...
return path, False
else:
return path, False
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils/__init__.py
index 5f235ae3958..7a1224db226 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -38,6 +38,7 @@ __all__ = (
"unregister_manual_map",
"make_rna_paths",
"manual_map",
+ "previews",
"resource_path",
"script_path_user",
"script_path_pref",
@@ -160,7 +161,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
# modification time changes. This `won't` work for packages so...
# its not perfect.
for module_name in [ext.module for ext in _user_preferences.addons]:
- _addon_utils.disable(module_name, default_set=False)
+ _addon_utils.disable(module_name)
def register_module_call(mod):
register = getattr(mod, "register", None)
@@ -640,10 +641,10 @@ def unregister_module(module, verbose=False):
# we start with the built-in default mapping
def _blender_default_map():
import sys
- import rna_wiki_reference as ref_mod
+ import rna_manual_reference as ref_mod
ret = (ref_mod.url_manual_prefix, ref_mod.url_manual_mapping)
# avoid storing in memory
- del sys.modules["rna_wiki_reference"]
+ del sys.modules["rna_manual_reference"]
return ret
# hooks for doc lookups
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
new file mode 100644
index 00000000000..965971139e4
--- /dev/null
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -0,0 +1,153 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+"""
+This module contains utility functions to handle custom previews.
+
+It behaves as a high-level 'cached' previews manager.
+
+This allows scripts to generate their own previews, and use them as icons in UI widgets
+('icon_value' for UILayout functions).
+
+
+Custom Icon Example
+-------------------
+
+.. literalinclude:: ../../../release/scripts/templates_py/ui_previews_custom_icon.py
+"""
+
+__all__ = (
+ "new",
+ "remove",
+ "ImagePreviewCollection",
+ )
+
+import _bpy
+_utils_previews = _bpy._utils_previews
+del _bpy
+
+
+_uuid_open = set()
+
+
+# High-level previews manager.
+# not accessed directly
+class ImagePreviewCollection(dict):
+ """
+ Dictionary-like class of previews.
+
+ This is a subclass of Python's built-in dict type,
+ used to store multiple image previews.
+
+ .. note::
+
+ - instance with :mod:`bpy.utils.previews.new`
+ - keys must be ``str`` type.
+ - values will be :class:`bpy.types.ImagePreview`
+ """
+
+ # Internal notes:
+ # - Blender's internal 'PreviewImage' struct uses 'self._uuid' prefix.
+
+ def __init__(self):
+ super().__init__()
+ self._uuid = hex(id(self))
+ _uuid_open.add(self._uuid)
+
+ def __del__(self):
+ if self._uuid not in _uuid_open:
+ return
+
+ raise ResourceWarning(
+ "<%s id=%s[%d]>: left open, remove with "
+ "'bpy.utils.previews.remove()'" %
+ (self.__class__.__name__, self._uuid, len(self)))
+ self.close()
+
+ def _gen_key(self, name):
+ return ":".join((self._uuid, name))
+
+ def new(self, name):
+ if name in self:
+ raise KeyException("key %r already exists")
+ p = self[name] = _utils_previews.new(
+ self._gen_key(name))
+ return p
+ new.__doc__ = _utils_previews.new.__doc__
+
+ def load(self, name, path, path_type, force_reload=False):
+ if name in self:
+ raise KeyException("key %r already exists")
+ p = self[name] = _utils_previews.load(
+ self._gen_key(name), path, path_type, force_reload)
+ return p
+ load.__doc__ = _utils_previews.load.__doc__
+
+ def clear(self):
+ """Clear all previews."""
+ for name in self.keys():
+ _utils_previews.release(self._gen_key(name))
+ super().clear()
+
+ def close(self):
+ """Close the collection and clear all previews."""
+ self.clear()
+ _uuid_open.remove(self._uuid)
+
+ def __delitem__(self, key):
+ _utils_previews.release(self._gen_key(key))
+ super().__delitem__(key)
+
+ def __repr__(self):
+ return "<%s id=%s[%d], %s>" % (
+ self.__class__.__name__,
+ self._uuid,
+ len(self),
+ super().__repr__())
+
+
+def new():
+ """
+ :return: a new preview collection.
+ :rtype: :class:`ImagePreviewCollection`
+ """
+
+ return ImagePreviewCollection()
+
+
+def remove(pcoll):
+ """
+ Remove the specified previews collection.
+
+ :arg pcoll: Preview collection to close.
+ :type pcoll: :class:`ImagePreviewCollection`
+ """
+ pcoll.close()
+
+
+# don't complain about resources on exit (only unregister)
+import atexit
+
+
+def exit_clear_warning():
+ del ImagePreviewCollection.__del__
+
+atexit.register(exit_clear_warning)
+del atexit, exit_clear_warning
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 81de0d7c6f0..65ccc3f8dc3 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -21,7 +21,7 @@
__all__ = (
"ExportHelper",
"ImportHelper",
- "OrientationHelper",
+ "orientation_helper_factory",
"axis_conversion",
"axis_conversion_ensure",
"create_derived_objects",
@@ -35,7 +35,11 @@ __all__ = (
)
import bpy
-from bpy.props import StringProperty, BoolProperty, EnumProperty
+from bpy.props import (
+ StringProperty,
+ BoolProperty,
+ EnumProperty,
+ )
def _check_axis_conversion(op):
@@ -61,6 +65,12 @@ class ExportHelper:
options={'HIDDEN'},
)
+ # needed for mix-ins
+ order = [
+ "filepath",
+ "check_existing",
+ ]
+
# subclasses can override with decorator
# True == use ext, False == no ext, None == do nothing.
check_extension = True
@@ -109,6 +119,11 @@ class ImportHelper:
subtype='FILE_PATH',
)
+ # needed for mix-ins
+ order = [
+ "filepath",
+ ]
+
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
@@ -117,13 +132,14 @@ class ImportHelper:
return _check_axis_conversion(self)
-class OrientationHelper:
+def orientation_helper_factory(name, axis_forward='Y', axis_up='Z'):
+ members = {}
def _update_axis_forward(self, context):
if self.axis_forward[-1] == self.axis_up[-1]:
self.axis_up = self.axis_up[0:-1] + 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3]
- axis_forward = EnumProperty(
+ members['axis_forward'] = EnumProperty(
name="Forward",
items=(('X', "X Forward", ""),
('Y', "Y Forward", ""),
@@ -132,7 +148,7 @@ class OrientationHelper:
('-Y', "-Y Forward", ""),
('-Z', "-Z Forward", ""),
),
- default='-Z',
+ default=axis_forward,
update=_update_axis_forward,
)
@@ -140,7 +156,7 @@ class OrientationHelper:
if self.axis_up[-1] == self.axis_forward[-1]:
self.axis_forward = self.axis_forward[0:-1] + 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3]
- axis_up = EnumProperty(
+ members['axis_up'] = EnumProperty(
name="Up",
items=(('X', "X Up", ""),
('Y', "Y Up", ""),
@@ -149,10 +165,17 @@ class OrientationHelper:
('-Y', "-Y Up", ""),
('-Z', "-Z Up", ""),
),
- default='Y',
+ default=axis_up,
update=_update_axis_up,
)
+ members["order"] = [
+ "axis_forward",
+ "axis_up",
+ ]
+
+ return type(name, (object,), members)
+
# Axis conversion function, not pretty LUT
# use lookup table to convert between any axis
@@ -349,7 +372,7 @@ def unpack_list(list_of_tuples):
# same as above except that it adds 0 for triangle faces
def unpack_face_list(list_of_tuples):
- #allocate the entire list
+ # allocate the entire list
flat_ls = [0] * (len(list_of_tuples) * 4)
i = 0
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 13ef86b23c0..78fb6aa8fa2 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -31,7 +31,10 @@ __all__ = (
import bpy
-from bpy.props import BoolProperty, FloatVectorProperty
+from bpy.props import (
+ BoolProperty,
+ FloatVectorProperty,
+ )
def add_object_align_init(context, operator):
@@ -171,7 +174,7 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name=
obj_act.select = True
scene.update() # apply location
- #scene.objects.active = obj_new
+ # scene.objects.active = obj_new
bpy.ops.object.join() # join into the active.
if obdata:
@@ -287,7 +290,8 @@ def world_to_camera_view(scene, obj, coord):
Returns the camera space coords for a 3d point.
(also known as: normalized device coordinates - NDC).
- Where (0, 0) is the bottom left and (1, 1) is the top right of the camera frame.
+ Where (0, 0) is the bottom left and (1, 1)
+ is the top right of the camera frame.
values outside 0-1 are also supported.
A negative 'z' value means the point is behind the camera.
@@ -300,7 +304,8 @@ def world_to_camera_view(scene, obj, coord):
:type obj: :class:`bpy.types.Object`
:arg coord: World space location.
:type coord: :class:`mathutils.Vector`
- :return: a vector where X and Y map to the view plane and Z is the depth on the view axis.
+ :return: a vector where X and Y map to the view plane and
+ Z is the depth on the view axis.
:rtype: :class:`mathutils.Vector`
"""
from mathutils import Vector
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index ec4a395f1e1..4aa06262970 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -69,11 +69,13 @@ def region_2d_to_origin_3d(region, rv3d, coord, clamp=None):
.. note::
- Orthographic views have a less obvious origin, the far clip is used to define the viewport near/far extents.
- Since far clip can be a very large value, the result may give with numeric precision issues.
+ Orthographic views have a less obvious origin,
+ the far clip is used to define the viewport near/far extents.
+ Since far clip can be a very large value,
+ the result may give with numeric precision issues.
- To avoid this problem, you can optionally clamp the far clip to a smaller value
- based on the data you're operating on.
+ To avoid this problem, you can optionally clamp the far clip to a
+ smaller value based on the data you're operating on.
:arg region: region of the 3D viewport, typically bpy.context.region.
:type region: :class:`bpy.types.Region`
@@ -160,7 +162,7 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location):
)[0]
-def location_3d_to_region_2d(region, rv3d, coord):
+def location_3d_to_region_2d(region, rv3d, coord, default=None):
"""
Return the *region* relative 2d location of a 3d position.
@@ -170,8 +172,10 @@ def location_3d_to_region_2d(region, rv3d, coord):
:type rv3d: :class:`bpy.types.RegionView3D`
:arg coord: 3d worldspace location.
:type coord: 3d vector
+ :arg default: Return this value if ``coord``
+ is behind the origin of a perspective view.
:return: 2d location
- :rtype: :class:`mathutils.Vector`
+ :rtype: :class:`mathutils.Vector` or ``default`` argument.
"""
from mathutils import Vector
@@ -184,4 +188,4 @@ def location_3d_to_region_2d(region, rv3d, coord):
height_half + height_half * (prj.y / prj.w),
))
else:
- return None
+ return default
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index c7ec7e1e54a..92dbd2dbd0e 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -715,7 +715,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
__slots__ = ()
def path_menu(self, searchpaths, operator,
- props_default={}, filter_ext=None):
+ props_default=None, filter_ext=None):
layout = self.layout
# hard coded to set the operators 'filepath' to the filename.
@@ -745,8 +745,9 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
text=bpy.path.display_name(f),
translate=False)
- for attr, value in props_default.items():
- setattr(props, attr, value)
+ if props_default is not None:
+ for attr, value in props_default.items():
+ setattr(props, attr, value)
props.filepath = filepath
if operator == "script.execute_preset":
@@ -754,14 +755,21 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
def draw_preset(self, context):
"""
- Define these on the subclass
- - preset_operator
- - preset_subdir
+ Define these on the subclass:
+ - preset_operator (string)
+ - preset_subdir (string)
+
+ Optionally:
+ - preset_extensions (set of strings)
+ - preset_operator_defaults (dict of keyword args)
"""
import bpy
+ ext_valid = getattr(self, "preset_extensions", {".py", ".xml"})
+ props_default = getattr(self, "preset_operator_defaults", None)
self.path_menu(bpy.utils.preset_paths(self.preset_subdir),
self.preset_operator,
- filter_ext=lambda ext: ext.lower() in {".py", ".xml"})
+ props_default=props_default,
+ filter_ext=lambda ext: ext.lower() in ext_valid)
@classmethod
def draw_collapsible(cls, context, layout):
@@ -773,24 +781,6 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
layout.menu(cls.__name__, icon='COLLAPSEMENU')
-class Region(StructRNA):
- __slots__ = ()
-
- def callback_add(self, cb, args, draw_mode):
- """
- Append a draw function to this region,
- deprecated, instead use bpy.types.SpaceView3D.draw_handler_add
- """
- for area in self.id_data.areas:
- for region in area.regions:
- if region == self:
- spacetype = type(area.spaces[0])
- return spacetype.draw_handler_add(cb, args, self.type,
- draw_mode)
-
- return None
-
-
class NodeTree(bpy_types.ID, metaclass=RNAMetaPropGroup):
__slots__ = ()
diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py
index 2882a08fbd4..2f69ea84386 100644
--- a/release/scripts/modules/nodeitems_utils.py
+++ b/release/scripts/modules/nodeitems_utils.py
@@ -37,13 +37,17 @@ class NodeCategory:
else:
def items_gen(context):
for item in items:
- if item.poll is None or item.poll(context):
+ if item.poll is None or context is None or item.poll(context):
yield item
self.items = items_gen
class NodeItem:
- def __init__(self, nodetype, label=None, settings={}, poll=None):
+ def __init__(self, nodetype, label=None, settings=None, poll=None):
+
+ if settings is None:
+ settings = {}
+
self.nodetype = nodetype
self._label = label
self.settings = settings
@@ -136,7 +140,7 @@ def register_node_categories(identifier, cat_list):
def node_categories_iter(context):
for cat_type in _node_categories.values():
for cat in cat_type[0]:
- if cat.poll and cat.poll(context):
+ if cat.poll and ((context is None) or cat.poll(context)):
yield cat
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 353362ed168..dae262e93d7 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -268,7 +268,8 @@ class InfoPropertyRNA:
self.default_str = "\"%s\"" % self.default
elif self.type == "enum":
if self.is_enum_flag:
- self.default_str = "%r" % self.default # repr or set()
+ # self.default_str = "%r" % self.default # repr or set()
+ self.default_str = "{%s}" % repr(list(sorted(self.default)))[1:-1]
else:
self.default_str = "'%s'" % self.default
elif self.array_length:
@@ -695,7 +696,7 @@ def BuildRNAInfo():
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup
-if __name__ == "__main__":
+def main():
import rna_info
struct = rna_info.BuildRNAInfo()[0]
data = []
@@ -723,3 +724,7 @@ if __name__ == "__main__":
else:
text = bpy.data.texts.new(name="api.py")
text.from_string(data)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index f4649453b46..44722fa7162 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -32,6 +32,13 @@ def rna_idprop_ui_get(item, create=True):
return None
+def rna_idprop_ui_del(item):
+ try:
+ del item['_RNA_UI']
+ except KeyError:
+ pass
+
+
def rna_idprop_ui_prop_get(item, prop, create=True):
rna_ui = rna_idprop_ui_get(item, create)
@@ -46,7 +53,7 @@ def rna_idprop_ui_prop_get(item, prop, create=True):
return rna_ui[prop]
-def rna_idprop_ui_prop_clear(item, prop):
+def rna_idprop_ui_prop_clear(item, prop, remove=True):
rna_ui = rna_idprop_ui_get(item, False)
if rna_ui is None:
@@ -54,8 +61,10 @@ def rna_idprop_ui_prop_clear(item, prop):
try:
del rna_ui[prop]
- except:
+ except KeyError:
pass
+ if remove and len(item.keys()) == 1:
+ rna_idprop_ui_del(item)
def rna_idprop_context_value(context, context_member, property_type):
diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py
index 729d6238ac3..ad4809efbe1 100644
--- a/release/scripts/modules/rna_xml.py
+++ b/release/scripts/modules/rna_xml.py
@@ -32,7 +32,7 @@ def build_property_typemap(skip_classes, skip_typemap):
if issubclass(cls, skip_classes):
continue
- ## to support skip-save we cant get all props
+ # # to support skip-save we cant get all props
# properties = cls.bl_rna.properties.keys()
properties = []
for prop_id, prop in cls.bl_rna.properties.items():
diff --git a/release/scripts/presets/keyconfig/3dsmax.py b/release/scripts/presets/keyconfig/3dsmax.py
index f85d3b43041..7694e338d68 100644
--- a/release/scripts/presets/keyconfig/3dsmax.py
+++ b/release/scripts/presets/keyconfig/3dsmax.py
@@ -754,8 +754,6 @@ kmi = km.keymap_items.new('anim.channels_move', 'PAGE_DOWN', 'PRESS', shift=True
kmi.properties.direction = 'BOTTOM'
kmi = km.keymap_items.new('anim.channels_group', 'G', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('anim.channels_ungroup', 'G', 'PRESS', alt=True)
-kmi = km.keymap_items.new('anim.channels_visibility_set', 'V', 'PRESS')
-kmi = km.keymap_items.new('anim.channels_visibility_toggle', 'V', 'PRESS', shift=True)
# Map UV Editor
km = kc.keymaps.new('UV Editor', space_type='EMPTY', region_type='WINDOW', modal=False)
@@ -1055,7 +1053,6 @@ kmi.properties.name = 'NODE_MT_add'
kmi = km.keymap_items.new('node.duplicate_move', 'D', 'PRESS', shift=True)
kmi = km.keymap_items.new('node.duplicate_move_keep_inputs', 'D', 'PRESS', shift=True, ctrl=True)
kmi = km.keymap_items.new('node.parent_set', 'P', 'PRESS', ctrl=True)
-kmi = km.keymap_items.new('node.parent_clear', 'P', 'PRESS', alt=True)
kmi = km.keymap_items.new('node.join', 'J', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('node.hide_toggle', 'H', 'PRESS')
kmi = km.keymap_items.new('node.mute_toggle', 'M', 'PRESS')
diff --git a/release/scripts/presets/keyconfig/maya.py b/release/scripts/presets/keyconfig/maya.py
index 47a7a7c5f5d..cdd16f26877 100644
--- a/release/scripts/presets/keyconfig/maya.py
+++ b/release/scripts/presets/keyconfig/maya.py
@@ -698,10 +698,10 @@ kmi.properties.level = 5
km = kc.keymaps.new('Knife Tool Modal Map', space_type='EMPTY', region_type='WINDOW', modal=True)
kmi = km.keymap_items.new_modal('CANCEL', 'ESC', 'ANY', any=True)
+kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY')
kmi = km.keymap_items.new_modal('PANNING', 'LEFTMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'MIDDLEMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'RIGHTMOUSE', 'ANY', alt=True)
-kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'PRESS', any=True)
kmi = km.keymap_items.new_modal('CANCEL', 'RIGHTMOUSE', 'ANY')
kmi = km.keymap_items.new_modal('CONFIRM', 'RET', 'PRESS', any=True)
kmi = km.keymap_items.new_modal('CONFIRM', 'NUMPAD_ENTER', 'PRESS', any=True)
@@ -1137,8 +1137,6 @@ kmi = km.keymap_items.new('anim.channels_move', 'PAGE_UP', 'PRESS', shift=True)
kmi.properties.direction = 'TOP'
kmi = km.keymap_items.new('anim.channels_move', 'PAGE_DOWN', 'PRESS', shift=True)
kmi.properties.direction = 'BOTTOM'
-kmi = km.keymap_items.new('anim.channels_visibility_set', 'V', 'PRESS')
-kmi = km.keymap_items.new('anim.channels_visibility_toggle', 'V', 'PRESS', shift=True)
# Map UV Editor
km = kc.keymaps.new('UV Editor', space_type='EMPTY', region_type='WINDOW', modal=False)
@@ -1499,11 +1497,9 @@ kmi = km.keymap_items.new('node.group_edit', 'TAB', 'PRESS')
kmi = km.keymap_items.new('node.read_renderlayers', 'R', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('node.read_fullsamplelayers', 'R', 'PRESS', shift=True)
kmi = km.keymap_items.new('node.render_changed', 'Z', 'PRESS')
-kmi = km.keymap_items.new('transform.translate', 'W', 'PRESS')
-kmi = km.keymap_items.new('transform.translate', 'EVT_TWEAK_A', 'ANY')
-kmi.properties.release_confirm = True
-kmi = km.keymap_items.new('transform.translate', 'EVT_TWEAK_S', 'ANY')
-kmi.properties.release_confirm = True
+kmi = km.keymap_items.new('node.translate_attach', 'W', 'PRESS')
+kmi = km.keymap_items.new('node.translate_attach', 'EVT_TWEAK_A', 'ANY')
+kmi = km.keymap_items.new('node.translate_attach', 'EVT_TWEAK_S', 'ANY')
kmi = km.keymap_items.new('transform.rotate', 'E', 'PRESS')
kmi = km.keymap_items.new('transform.resize', 'R', 'PRESS')
kmi = km.keymap_items.new('node.move_detach_links', 'D', 'PRESS', alt=True)
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 65f7bde1809..4047505652f 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -54,7 +54,7 @@ if bpy.app.build_options.freestyle:
_modules.append("freestyle")
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules if name != 'bpy'}
+_modules_loaded = {name: _namespace[name] for name in _modules if name != "bpy"}
del _namespace
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index dfb734e9b5b..82014c87be9 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -153,40 +153,40 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
col = layout.column(align=True)
col.label(text="Location")
- col.prop(self, 'location', text="")
+ col.prop(self, "location", text="")
col = layout.column(align=True)
col.label(text="Rotation")
- col.prop(self, 'rotation', text="")
+ col.prop(self, "rotation", text="")
col = layout.column(align=True)
col.label(text="Major Segments")
- col.prop(self, 'major_segments', text="")
+ col.prop(self, "major_segments", text="")
col = layout.column(align=True)
col.label(text="Minor Segments")
- col.prop(self, 'minor_segments', text="")
+ col.prop(self, "minor_segments", text="")
col = layout.column(align=True)
col.label(text="Torus Dimensions")
- col.row().prop(self, 'mode', expand=True)
+ col.row().prop(self, "mode", expand=True)
if self.mode == 'MAJOR_MINOR':
col = layout.column(align=True)
col.label(text="Major Radius")
- col.prop(self, 'major_radius', text="")
+ col.prop(self, "major_radius", text="")
col = layout.column(align=True)
col.label(text="Minor Radius")
- col.prop(self, 'minor_radius', text="")
+ col.prop(self, "minor_radius", text="")
else:
col = layout.column(align=True)
col.label(text="Exterior Radius")
- col.prop(self, 'abso_major_rad', text="")
+ col.prop(self, "abso_major_rad", text="")
col = layout.column(align=True)
col.label(text="Interior Radius")
- col.prop(self, 'abso_minor_rad', text="")
+ col.prop(self, "abso_minor_rad", text="")
def invoke(self, context, event):
object_utils.object_add_grid_scale_apply_operator(self, context)
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index 1b3e719b2bd..f3575f26890 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -210,6 +210,12 @@ class BakeAction(Operator):
description="Bake animation onto the object then clear parents (objects only)",
default=False,
)
+ use_current_action = BoolProperty(
+ name="Overwrite Current Action",
+ description="Bake animation into current action, instead of creating a new one "
+ "(useful for baking only part of bones in an armature)",
+ default=False,
+ )
bake_types = EnumProperty(
name="Bake Data",
description="Which data's transformations to bake",
@@ -224,6 +230,12 @@ class BakeAction(Operator):
from bpy_extras import anim_utils
+ action = None
+ if self.use_current_action:
+ obj = context.object
+ if obj.animation_data:
+ action = obj.animation_data.action
+
action = anim_utils.bake_action(self.frame_start,
self.frame_end,
frame_step=self.step,
@@ -234,6 +246,7 @@ class BakeAction(Operator):
do_constraint_clear=self.clear_constraints,
do_parents_clear=self.clear_parents,
do_clean=True,
+ action=action,
)
if action is None:
diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py
index 7e4e0ea9246..0c77ea2ab7e 100644
--- a/release/scripts/startup/bl_operators/clip.py
+++ b/release/scripts/startup/bl_operators/clip.py
@@ -225,7 +225,8 @@ class CLIP_OT_track_to_empty(Operator):
bl_label = "Link Empty to Track"
bl_options = {'UNDO', 'REGISTER'}
- def _link_track(self, context, clip, tracking_object, track):
+ @staticmethod
+ def _link_track(context, clip, tracking_object, track):
sc = context.space_data
constraint = None
ob = None
@@ -331,7 +332,8 @@ class CLIP_OT_delete_proxy(Operator):
return wm.invoke_confirm(self, event)
- def _rmproxy(self, abspath):
+ @staticmethod
+ def _rmproxy(abspath):
import shutil
if not os.path.exists(abspath):
@@ -552,8 +554,8 @@ class CLIP_OT_setup_tracking_scene(Operator):
world.light_settings.sample_method = 'ADAPTIVE_QMC'
world.light_settings.samples = 7
world.light_settings.threshold = 0.005
- if hasattr(scene, 'cycles'):
- world.light_settings.ao_factor = 0.05
+ if hasattr(scene, "cycles"):
+ world.light_settings.ao_factor = 0.05
@staticmethod
def _findOrCreateCamera(context):
@@ -841,7 +843,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
self._offsetNodes(tree)
scene.render.alpha_mode = 'TRANSPARENT'
- if hasattr(scene, 'cycles'):
+ if hasattr(scene, "cycles"):
scene.cycles.film_transparent = True
@staticmethod
diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py
index 1653459bd71..f00f5d97c5e 100644
--- a/release/scripts/startup/bl_operators/image.py
+++ b/release/scripts/startup/bl_operators/image.py
@@ -33,7 +33,8 @@ class EditExternally(Operator):
subtype='FILE_PATH',
)
- def _editor_guess(self, context):
+ @staticmethod
+ def _editor_guess(context):
import sys
image_editor = context.user_preferences.filepaths.image_editor
diff --git a/release/scripts/startup/bl_operators/mask.py b/release/scripts/startup/bl_operators/mask.py
index 60208d27338..aa984659430 100644
--- a/release/scripts/startup/bl_operators/mask.py
+++ b/release/scripts/startup/bl_operators/mask.py
@@ -18,7 +18,6 @@
# <pep8-80 compliant>
-import bpy
from bpy.types import Menu
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index f86c31cd9cc..ea504d48448 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -75,7 +75,6 @@ class MeshMirrorUV(Operator):
double_warn += co in mirror_lt
mirror_lt[co] = i
- #for i, v in enumerate(mesh.vertices):
vmap = {}
for mirror_a, mirror_b in ((mirror_gt, mirror_lt),
(mirror_lt, mirror_gt)):
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index e3ceeca8abe..b89890a223c 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -579,7 +579,8 @@ class MakeDupliFace(Operator):
bl_label = "Make Dupli-Face"
bl_options = {'REGISTER', 'UNDO'}
- def _main(self, context):
+ @staticmethod
+ def _main(context):
from mathutils import Vector
SCALE_FAC = 0.01
@@ -643,6 +644,9 @@ class MakeDupliFace(Operator):
ob_new.use_dupli_faces_scale = True
ob_new.dupli_faces_scale = 1.0 / SCALE_FAC
+ ob_inst.select = True
+ ob_new.select = True
+
def execute(self, context):
self._main(context)
return {'FINISHED'}
@@ -924,7 +928,7 @@ class LodGenerate(Operator):
lod.location.y = ob.location.y + 3.0 * i
if i == 1:
- modifier = lod.modifiers.new("lod_decimate", "DECIMATE")
+ modifier = lod.modifiers.new("lod_decimate", 'DECIMATE')
else:
modifier = lod.modifiers[-1]
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index e843209da3c..3c84e5dc553 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -70,7 +70,8 @@ def GlobalBB_HQ(obj):
# Initialize the variables with the last vertex
- verts = obj.data.vertices
+ me = obj.to_mesh(scene=bpy.context.scene, apply_modifiers=True, settings='PREVIEW')
+ verts = me.vertices
val = matrix_world * verts[-1].co
@@ -111,6 +112,8 @@ def GlobalBB_HQ(obj):
if val > up:
up = val
+ bpy.data.meshes.remove(me)
+
return Vector((left, front, up)), Vector((right, back, down))
@@ -338,7 +341,10 @@ def align_objects(context,
return True
-from bpy.props import EnumProperty, BoolProperty
+from bpy.props import (
+ EnumProperty,
+ BoolProperty
+ )
class AlignObjects(Operator):
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 7195b7819d1..63c1945d2d2 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -45,11 +45,28 @@ class AddPresetBase:
options={'HIDDEN', 'SKIP_SAVE'},
)
+ # needed for mix-ins
+ order = [
+ "name",
+ "remove_active",
+ ]
+
@staticmethod
def as_filename(name): # could reuse for other presets
- for char in " !@#$%^&*(){}:\";'[]<>,.\\/?":
- name = name.replace(char, '_')
- return name.lower().strip()
+
+ # lazy init maketrans
+ def maketrans_init():
+ cls = AddPresetBase
+ attr = "_as_filename_trans"
+
+ trans = getattr(cls, attr, None)
+ if trans is None:
+ trans = str.maketrans({char: "_" for char in " !@#$%^&*(){}:\";'[]<>,.\\/?"})
+ setattr(cls, attr, trans)
+ return trans
+
+ trans = maketrans_init()
+ return name.lower().strip().translate(trans)
def execute(self, context):
import os
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 3a7a9b99cde..a5565699364 100644
--- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
+++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
@@ -107,11 +107,20 @@ class PlayRenderedAnim(Operator):
del file_a, file_b, frame_tmp
file = bpy.path.abspath(file) # expand '//'
else:
+ path_valid = True
# works for movies and images
- file = rd.frame_path(frame=scene.frame_start)
+ file = rd.frame_path(frame=scene.frame_start, preview=scene.use_preview_range)
file = bpy.path.abspath(file) # expand '//'
if not os.path.exists(file):
self.report({'WARNING'}, "File %r not found" % file)
+ path_valid = False
+
+ #one last try for full range if we used preview range
+ if scene.use_preview_range and not path_valid:
+ file = rd.frame_path(frame=scene.frame_start, preview=False)
+ file = bpy.path.abspath(file) # expand '//'
+ if not os.path.exists(file):
+ self.report({'WARNING'}, "File %r not found" % file)
cmd = [player_path]
# extra options, fps controls etc.
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index a48415caa9b..edf60aa40e7 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -719,7 +719,7 @@ class WM_OT_context_modal_mouse(Operator):
"""Adjust arbitrary values with mouse input"""
bl_idname = "wm.context_modal_mouse"
bl_label = "Context Modal Mouse"
- bl_options = {'GRAB_POINTER', 'BLOCKING', 'UNDO', 'INTERNAL'}
+ bl_options = {'GRAB_CURSOR', 'BLOCKING', 'UNDO', 'INTERNAL'}
data_path_iter = data_path_iter
data_path_item = data_path_item
@@ -974,10 +974,12 @@ class WM_OT_doc_view_manual(Operator):
url = self._lookup_rna_url(rna_id)
if url is None:
- self.report({'WARNING'}, "No reference available %r, "
- "Update info in 'rna_wiki_reference.py' "
- " or callback to bpy.utils.manual_map()" %
- self.doc_id)
+ self.report(
+ {'WARNING'},
+ "No reference available %r, "
+ "Update info in 'rna_manual_reference.py' "
+ "or callback to bpy.utils.manual_map()" %
+ self.doc_id)
return {'CANCELLED'}
else:
import webbrowser
@@ -1296,9 +1298,13 @@ class WM_OT_properties_remove(Operator):
property = rna_property
def execute(self, context):
+ from rna_prop_ui import rna_idprop_ui_prop_clear
data_path = self.data_path
item = eval("context.%s" % data_path)
- del item[self.property]
+ prop = self.property
+ del item[prop]
+ rna_idprop_ui_prop_clear(item, prop)
+
return {'FINISHED'}
@@ -1782,7 +1788,7 @@ class WM_OT_addon_disable(Operator):
err_str = traceback.format_exc()
print(err_str)
- addon_utils.disable(self.module, handle_error=err_cb)
+ addon_utils.disable(self.module, default_set=True, handle_error=err_cb)
if err_str:
self.report({'ERROR'}, err_str)
@@ -1998,7 +2004,7 @@ class WM_OT_addon_install(Operator):
# disable any addons we may have enabled previously and removed.
# this is unlikely but do just in case. bug [#23978]
for new_addon in addons_new:
- addon_utils.disable(new_addon)
+ addon_utils.disable(new_addon, default_set=True)
# possible the zip contains multiple addons, we could disallow this
# but for now just use the first
@@ -2062,7 +2068,7 @@ class WM_OT_addon_remove(Operator):
return {'CANCELLED'}
# in case its enabled
- addon_utils.disable(self.module)
+ addon_utils.disable(self.module, default_set=True)
import shutil
if isdir:
@@ -2102,15 +2108,9 @@ class WM_OT_addon_expand(Operator):
module_name = self.module
- # unlikely to fail, module should have already been imported
- try:
- # mod = __import__(module_name)
- mod = addon_utils.addons_fake_modules.get(module_name)
- except:
- import traceback
- traceback.print_exc()
- return {'CANCELLED'}
+ mod = addon_utils.addons_fake_modules.get(module_name)
+ if mod is not None:
+ info = addon_utils.module_bl_info(mod)
+ info["show_expanded"] = not info["show_expanded"]
- info = addon_utils.module_bl_info(mod)
- info["show_expanded"] = not info["show_expanded"]
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 51117f68558..c110b429aad 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -86,7 +86,7 @@ if bpy.app.build_options.freestyle:
_modules.append("properties_freestyle")
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules if name != 'bpy'}
+_modules_loaded = {name: _namespace[name] for name in _modules if name != "bpy"}
del _namespace
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 9aa67223fc4..b37feb82461 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -38,7 +38,8 @@ class ConstraintButtonsPanel:
if con.type not in {'RIGID_BODY_JOINT', 'NULL'}:
box.prop(con, "influence")
- def space_template(self, layout, con, target=True, owner=True):
+ @staticmethod
+ def space_template(layout, con, target=True, owner=True):
if target or owner:
split = layout.split(percentage=0.2)
@@ -55,7 +56,8 @@ class ConstraintButtonsPanel:
if owner:
row.prop(con, "owner_space", text="")
- def target_template(self, layout, con, subtargets=True):
+ @staticmethod
+ def target_template(layout, con, subtargets=True):
layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
if con.target and subtargets:
@@ -69,6 +71,7 @@ class ConstraintButtonsPanel:
elif con.target.type in {'MESH', 'LATTICE'}:
layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
+ @staticmethod
def ik_template(self, layout, con):
# only used for iTaSC
layout.prop(con, "pole_target")
@@ -894,7 +897,7 @@ class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
obj = context.object
- if obj.type == 'ARMATURE' and obj.mode in {'POSE'}:
+ if obj.type == 'ARMATURE' and obj.mode == 'POSE':
box = layout.box()
box.alert = True # XXX: this should apply to the box background
box.label(icon='INFO', text="Constraints for active bone do not live here")
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 106e31ea89a..24a67a22c1f 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -135,6 +135,35 @@ class DATA_PT_lens(CameraButtonsPanel, Panel):
col.prop(cam, "clip_end", text="End")
+class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
+ bl_label = "Stereoscopy"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ render = context.scene.render
+ return (super().poll(context) and render.use_multiview and
+ render.views_format == 'STEREO_3D')
+
+ def draw(self, context):
+ layout = self.layout
+ # render = context.scene.render
+ st = context.camera.stereo
+
+ col = layout.column()
+ col.row().prop(st, "convergence_mode", expand=True)
+
+ if st.convergence_mode == 'PARALLEL':
+ col.prop(st, "viewport_convergence")
+ else:
+ col.prop(st, "convergence_distance")
+
+ col.prop(st, "interocular_distance")
+
+ col.label(text="Pivot:")
+ col.row().prop(st, "pivot", expand=True)
+
+
class DATA_PT_camera(CameraButtonsPanel, Panel):
bl_label = "Camera"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
@@ -184,13 +213,20 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
col = split.column()
col.label(text="Focus:")
col.prop(cam, "dof_object", text="")
-
- col = split.column()
- col.prop(dof_options, "fstop")
sub = col.column()
- sub.active = cam.dof_object is None
+ sub.active = (cam.dof_object is None)
sub.prop(cam, "dof_distance", text="Distance")
+ hq_support = dof_options.is_hq_supported
+ col = split.column(align=True)
+ col.label("Viewport:")
+ sub = col.column()
+ sub.active = hq_support
+ sub.prop(dof_options, "use_high_quality")
+ col.prop(dof_options, "fstop")
+ if dof_options.use_high_quality and hq_support:
+ col.prop(dof_options, "blades")
+
class DATA_PT_camera_display(CameraButtonsPanel, Panel):
bl_label = "Display"
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 9277bbe20f9..eb8ffa1fb60 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -321,7 +321,7 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
row.label(text="Bold & Italic")
row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink")
- #layout.prop(text, "font")
+ # layout.prop(text, "font")
split = layout.split()
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
index 6fef30fa3e6..0121ad46c86 100644
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ b/release/scripts/startup/bl_ui/properties_data_lamp.py
@@ -355,6 +355,7 @@ class DATA_PT_spot(DataButtonsPanel, Panel):
col = split.column()
+ col.active = (lamp.shadow_method != 'BUFFER_SHADOW' or lamp.shadow_buffer_type != 'DEEP')
col.prop(lamp, "use_halo")
sub = col.column(align=True)
sub.active = lamp.use_halo
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 8efd14afb47..5416735494b 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -29,8 +29,8 @@ class MESH_MT_vertex_group_specials(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("object.vertex_group_sort", icon='SORTALPHA', text="Sort by Name").sort_type = "NAME"
- layout.operator("object.vertex_group_sort", icon='ARMATURE_DATA', text="Sort by Bone Hierarchy").sort_type = "BONE_HIERARCHY"
+ layout.operator("object.vertex_group_sort", icon='SORTALPHA', text="Sort by Name").sort_type = 'NAME'
+ layout.operator("object.vertex_group_sort", icon='ARMATURE_DATA', text="Sort by Bone Hierarchy").sort_type = 'BONE_HIERARCHY'
layout.operator("object.vertex_group_copy", icon='COPY_ID')
layout.operator("object.vertex_group_copy_to_linked", icon='LINK_AREA')
layout.operator("object.vertex_group_copy_to_selected", icon='LINK_AREA')
@@ -70,7 +70,7 @@ class MESH_UL_vgroups(UIList):
layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -94,7 +94,7 @@ class MESH_UL_shape_keys(UIList):
else:
row.label(text="")
row.prop(key_block, "mute", text="", emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -106,7 +106,7 @@ class MESH_UL_uvmaps_vcols(UIList):
layout.prop(item, "name", text="", emboss=False, icon_value=icon)
icon = 'RESTRICT_RENDER_OFF' if item.active_render else 'RESTRICT_RENDER_ON'
layout.prop(item, "active_render", text="", icon=icon, emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -369,8 +369,8 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
me = context.mesh
col = layout.column()
- col.operator("mesh.customdata_clear_mask", icon='X')
- col.operator("mesh.customdata_clear_skin", icon='X')
+ col.operator("mesh.customdata_mask_clear", icon='X')
+ col.operator("mesh.customdata_skin_clear", icon='X')
if me.has_custom_normals:
col.operator("mesh.customdata_custom_splitnormals_clear", icon='X')
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index ec60f1caec8..381c9add34f 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -262,24 +262,37 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.prop(md, "decimate_type", expand=True)
if decimate_type == 'COLLAPSE':
+ has_vgroup = bool(md.vertex_group)
layout.prop(md, "ratio")
split = layout.split()
- row = split.row(align=True)
+
+ col = split.column()
+ row = col.row(align=True)
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
- split.prop(md, "use_collapse_triangulate")
+ layout_info = col
+
+ col = split.column()
+ row = col.row()
+ row.active = has_vgroup
+ row.prop(md, "vertex_group_factor")
+
+ col.prop(md, "use_collapse_triangulate")
+
elif decimate_type == 'UNSUBDIV':
layout.prop(md, "iterations")
+ layout_info = layout
else: # decimate_type == 'DISSOLVE':
layout.prop(md, "angle_limit")
layout.prop(md, "use_dissolve_boundaries")
layout.label("Delimit:")
row = layout.row()
row.prop(md, "delimit")
+ layout_info = layout
- layout.label(text=iface_("Face Count: %d") % md.face_count, translate=False)
+ layout_info.label(text=iface_("Faces: %d") % md.face_count, translate=False)
def DISPLACE(self, layout, ob, md):
has_texture = (md.texture is not None)
@@ -1131,13 +1144,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
self.vertex_weight_mask(layout, ob, md)
def SKIN(self, layout, ob, md):
- layout.operator("object.skin_armature_create", text="Create Armature")
+ row = layout.row()
+ row.operator("object.skin_armature_create", text="Create Armature")
+ row.operator("mesh.customdata_skin_add")
layout.separator()
- col = layout.column(align=True)
- col.prop(md, "branch_smoothing")
- col.prop(md, "use_smooth_shade")
+ row = layout.row(align=True)
+ row.prop(md, "branch_smoothing")
+ row.prop(md, "use_smooth_shade")
split = layout.split()
@@ -1384,7 +1399,32 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
sub = row.row(align=True)
sub.active = has_vgroup
- sub.prop(md, "use_invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+ sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+
+ def CORRECTIVE_SMOOTH(self, layout, ob, md):
+ is_bind = md.is_bind
+
+ layout.prop(md, "factor", text="Factor")
+ layout.prop(md, "iterations")
+
+ row = layout.row()
+ row.prop(md, "smooth_type")
+
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+
+ col = split.column()
+ col.prop(md, "use_only_smooth")
+ col.prop(md, "use_pin_boundary")
+
+ layout.prop(md, "rest_source")
+ if md.rest_source == 'BIND':
+ layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index 2d91c998007..995136b0d97 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -74,8 +74,8 @@ class RenderLayerFreestyleButtonsPanel:
rd = context.scene.render
with_freestyle = bpy.app.build_options.freestyle
- return (scene and with_freestyle and rd.use_freestyle
- and rd.layers.active and(scene.render.engine in cls.COMPAT_ENGINES))
+ return (scene and with_freestyle and rd.use_freestyle and
+ rd.layers.active and(scene.render.engine in cls.COMPAT_ENGINES))
class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel):
@@ -95,7 +95,7 @@ class RENDERLAYER_UL_linesets(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(lineset, "name", text="", emboss=False, icon_value=icon)
layout.prop(lineset, "show_render", text="", index=index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label("", icon_value=icon)
@@ -690,10 +690,11 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
row.prop(linestyle, "texture_spacing", text="Spacing Along Stroke")
row = layout.row()
- op = row.operator("wm.properties_context_change",
- text="Go to Linestyle Textures Properties",
- icon='TEXTURE')
- op.context = 'TEXTURE'
+ props = row.operator(
+ "wm.properties_context_change",
+ text="Go to Linestyle Textures Properties",
+ icon='TEXTURE')
+ props.context = 'TEXTURE'
elif linestyle.panel == 'MISC':
pass
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
index 32a8e734ab6..fa57bf2115f 100644
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ b/release/scripts/startup/bl_ui/properties_game.py
@@ -89,10 +89,14 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
split = layout.split()
col = split.column()
- col.label(text="Velocity:")
+ col.label(text="Linear velocity:")
sub = col.column(align=True)
sub.prop(game, "velocity_min", text="Minimum")
sub.prop(game, "velocity_max", text="Maximum")
+ col.label(text="Angular velocity:")
+ sub = col.column(align=True)
+ sub.prop(game, "angular_velocity_min", text="Minimum")
+ sub.prop(game, "angular_velocity_max", text="Maximum")
col = split.column()
col.label(text="Damping:")
@@ -100,7 +104,6 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
sub.prop(game, "damping", text="Translation", slider=True)
sub.prop(game, "rotation_damping", text="Rotation", slider=True)
- if physics_type == 'RIGID_BODY':
layout.separator()
split = layout.split()
@@ -111,6 +114,7 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
col.prop(game, "lock_location_y", text="Y")
col.prop(game, "lock_location_z", text="Z")
+ if physics_type == 'RIGID_BODY':
col = split.column()
col.label(text="Lock Rotation:")
col.prop(game, "lock_rotation_x", text="X")
@@ -213,15 +217,17 @@ class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel):
layout = self.layout
game = context.active_object.game
- layout.active = game.use_collision_bounds
+ split = layout.split()
+ split.active = game.use_collision_bounds
- layout.prop(game, "collision_bounds_type", text="Bounds")
+ col = split.column()
+ col.prop(game, "collision_bounds_type", text="Bounds")
- row = layout.row()
+ row = col.row()
row.prop(game, "collision_margin", text="Margin", slider=True)
sub = row.row()
- sub.active = game.physics_type not in {'SOFT_BODY', 'CHARACTER'}
+ sub.active = game.physics_type not in {'SOFT_BODY', 'CHARACTER'}
sub.prop(game, "use_collision_compound", text="Compound")
layout.separator()
@@ -397,7 +403,6 @@ class RENDER_PT_game_shading(RenderButtonsPanel, Panel):
col.prop(gs, "use_glsl_lights", text="Lights")
col.prop(gs, "use_glsl_shaders", text="Shaders")
col.prop(gs, "use_glsl_shadows", text="Shadows")
- col.prop(gs, "use_glsl_color_management", text="Color Management")
col = split.column()
col.prop(gs, "use_glsl_ramps", text="Ramps")
@@ -523,6 +528,26 @@ class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel):
row.prop(rd, "sample_max_error")
+class SCENE_PT_game_hysteresis(SceneButtonsPanel, Panel):
+ bl_label = "Level of Detail"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return (scene and scene.render.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ gs = context.scene.game_settings
+
+ row = layout.row()
+ row.prop(gs, "use_scene_hysteresis", text="Hysteresis")
+ row = layout.row()
+ row.active = gs.use_scene_hysteresis
+ row.prop(gs, "scene_hysteresis_percentage", text="")
+
+
class WorldButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@@ -712,6 +737,8 @@ class DATA_PT_shadow_game(DataButtonsPanel, Panel):
col = split.column()
col.prop(lamp, "shadow_color", text="")
+ if lamp.type == 'SUN':
+ col.prop(lamp, "show_shadow_box")
col = split.column()
col.prop(lamp, "use_shadow_layer", text="This Layer Only")
@@ -765,6 +792,7 @@ class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
ob = context.object
+ gs = context.scene.game_settings
col = layout.column()
@@ -782,6 +810,13 @@ class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel):
row.prop(level, "use_mesh", text="")
row.prop(level, "use_material", text="")
+ row = box.row()
+ row.active = gs.use_scene_hysteresis
+ row.prop(level, "use_object_hysteresis", text="Hysteresis Override")
+ row = box.row()
+ row.active = gs.use_scene_hysteresis and level.use_object_hysteresis
+ row.prop(level, "object_hysteresis_percentage", text="")
+
row = col.row(align=True)
row.operator("object.lod_add", text="Add", icon='ZOOMIN')
row.menu("OBJECT_MT_lod_tools", text="", icon='TRIA_DOWN')
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 5b5a7648d83..e86fc79e343 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -321,7 +321,7 @@ class GPENCIL_UL_layer(UIList):
row = layout.row(align=True)
row.prop(gpl, "lock", text="", emboss=False)
row.prop(gpl, "hide", text="", emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -414,9 +414,7 @@ class GreasePencilDataPanel:
col = split.column(align=True)
col.prop(gpl, "show_x_ray")
-
- # if debug:
- # layout.prop(gpl, "show_points")
+ col.prop(gpl, "show_points", text="Points")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index cb4a0f5bb85..f4836da50bc 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -36,7 +36,7 @@ class MASK_UL_layers(UIList):
row.prop(mask, "hide", text="", emboss=False)
row.prop(mask, "hide_select", text="", emboss=False)
row.prop(mask, "hide_render", text="", emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -190,7 +190,7 @@ class MASK_PT_point:
col.prop_search(parent, "parent", tracking,
"objects", icon='OBJECT_DATA', text="Object:")
- tracks_list = "tracks" if parent.type == 'POINT_TRACK' else 'plane_tracks'
+ tracks_list = "tracks" if parent.type == 'POINT_TRACK' else "plane_tracks"
if parent.parent in tracking.objects:
object = tracking.objects[parent.parent]
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 20143b81d14..d916007ea41 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -87,7 +87,7 @@ class MATERIAL_UL_matslots(UIList):
layout.label(text=iface_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode))
elif ma.use_nodes:
layout.label(text="Node <none>")
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -123,11 +123,16 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
ob = context.object
slot = context.material_slot
space = context.space_data
+ is_sortable = (len(ob.material_slots) > 1)
if ob:
+ rows = 1
+ if is_sortable:
+ rows = 4
+
row = layout.row()
- row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1)
+ row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
@@ -135,6 +140,12 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
+ if is_sortable:
+ col.separator()
+
+ col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
if ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign")
@@ -867,12 +878,14 @@ class MATERIAL_PT_transp_game(MaterialButtonsPanel, Panel):
base_mat = context.material
mat = active_node_mat(base_mat)
+ layout.active = mat.use_transparency
+
if simple_material(base_mat):
row = layout.row()
- row.active = mat.use_transparency
row.prop(mat, "transparency_method", expand=True)
layout.prop(mat, "alpha")
+ layout.prop(mat, "specular_alpha", text="Specular")
class VolumeButtonsPanel:
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index b0da65063d1..cca142b645c 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -133,7 +133,7 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
else:
row = col.row(align=True)
panel.prop_unified_color(row, context, brush, "color", text="")
- if brush.image_tool == 'FILL':
+ if brush.image_tool == 'FILL' and not projpaint:
col.prop(brush, "fill_threshold")
else:
panel.prop_unified_color(row, context, brush, "secondary_color", text="")
@@ -216,7 +216,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
col = layout.column(align=True)
col.prop(brush, "use_accumulate")
- col.prop(brush, "use_alpha")
+ if projpaint:
+ col.prop(brush, "use_alpha")
+
col.prop(brush, "use_gradient")
col.separator()
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 29be9ac2158..e294f5487a6 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -118,7 +118,7 @@ class PARTICLE_UL_particle_systems(bpy.types.UIList):
layout.prop(md, "show_render", emboss=False, icon_only=True, icon='RESTRICT_RENDER_OFF' if md.show_render else 'RESTRICT_RENDER_ON')
layout.prop(md, "show_viewport", emboss=False, icon_only=True, icon='RESTRICT_VIEW_OFF' if md.show_viewport else 'RESTRICT_VIEW_ON')
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -1243,7 +1243,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
split = layout.split()
split.active = part.kink != 'NO'
- if part.kink in {'SPIRAL'}:
+ if part.kink == 'SPIRAL':
col = split.column()
sub = col.column(align=True)
sub.prop(part, "kink_amplitude", text="Radius")
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index bb0f0cfc796..82eecf0fb5a 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -191,7 +191,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
col.operator("ptcache.bake", text="Bake").bake = True
sub = col.row()
- sub.enabled = (cache.frames_skipped or cache.is_outdated) and enabled
+ sub.enabled = (cache.is_frame_skip or cache.is_outdated) and enabled
sub.operator("ptcache.bake", text="Calculate To Frame").bake = False
sub = col.column()
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index 01dcf837546..269ffa6d371 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -40,7 +40,7 @@ class PHYSICS_UL_dynapaint_surfaces(UIList):
row.prop(surf, "show_preview", text="", emboss=False,
icon='RESTRICT_VIEW_OFF' if surf.show_preview else 'RESTRICT_VIEW_ON')
row.prop(surf, "is_active", text="")
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
row = layout.row(align=True)
row.label(text="", icon_value=icon)
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index 63268bc6672..85d3c1d7dc4 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -81,12 +81,12 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
layout.prop(flow, "smoke_flow_type", expand=False)
- if flow.smoke_flow_type != "OUTFLOW":
+ if flow.smoke_flow_type != 'OUTFLOW':
split = layout.split()
col = split.column()
col.label(text="Flow Source:")
col.prop(flow, "smoke_flow_source", expand=False, text="")
- if flow.smoke_flow_source == "PARTICLES":
+ if flow.smoke_flow_source == 'PARTICLES':
col.label(text="Particle System:")
col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
col.prop(flow, "use_particle_size", text="Set Size")
@@ -103,7 +103,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
sub = sub.column()
sub.active = flow.use_initial_velocity
sub.prop(flow, "velocity_factor")
- if flow.smoke_flow_source == "MESH":
+ if flow.smoke_flow_source == 'MESH':
sub.prop(flow, "velocity_normal")
#sub.prop(flow, "velocity_random")
@@ -135,7 +135,7 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
@classmethod
def poll(cls, context):
md = context.smoke
- return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == "MESH")
+ return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == 'MESH')
def draw(self, context):
layout = self.layout
@@ -151,9 +151,9 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
sub.prop(flow, "noise_texture", text="")
sub.label(text="Mapping:")
sub.prop(flow, "texture_map_type", expand=False, text="")
- if flow.texture_map_type == "UV":
+ if flow.texture_map_type == 'UV':
sub.prop_search(flow, "uv_layer", ob.data, "uv_textures", text="")
- if flow.texture_map_type == "AUTO":
+ if flow.texture_map_type == 'AUTO':
sub.prop(flow, "texture_size")
sub.prop(flow, "texture_offset")
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index b596fe48b49..0c68d98a8e1 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -274,7 +274,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel):
col.prop(rd, "tile_y", text="Y")
col.separator()
- col.prop(rd, 'preview_start_resolution')
+ col.prop(rd, "preview_start_resolution")
col = split.column()
col.label(text="Memory:")
@@ -334,28 +334,25 @@ class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
class RENDER_PT_stamp(RenderButtonsPanel, Panel):
- bl_label = "Stamp"
+ bl_label = "Metadata"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
- def draw_header(self, context):
- rd = context.scene.render
-
- self.layout.prop(rd, "use_stamp", text="")
-
def draw(self, context):
layout = self.layout
rd = context.scene.render
- layout.active = rd.use_stamp
+ layout.prop(rd, "use_stamp", text="Stamp Output")
+ col = layout.column()
+ col.active = rd.use_stamp
+ col.prop(rd, "stamp_font_size", text="Font Size")
- layout.prop(rd, "stamp_font_size", text="Font Size")
-
- row = layout.row()
+ row = col.row()
row.column().prop(rd, "stamp_foreground", slider=True)
row.column().prop(rd, "stamp_background", slider=True)
+ layout.label("Enabled Metadata")
split = layout.split()
col = split.column()
@@ -404,6 +401,8 @@ class RENDER_PT_output(RenderButtonsPanel, Panel):
col.prop(rd, "use_render_cache")
layout.template_image_settings(image_settings, color_management=False)
+ if rd.use_multiview:
+ layout.template_image_views(image_settings)
if file_format == 'QUICKTIME':
quicktime = rd.quicktime
diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py
index 35032d38933..8a3e33f1936 100644
--- a/release/scripts/startup/bl_ui/properties_render_layer.py
+++ b/release/scripts/startup/bl_ui/properties_render_layer.py
@@ -40,7 +40,7 @@ class RENDERLAYER_UL_renderlayers(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(layer, "name", text="", icon_value=icon, emboss=False)
layout.prop(layer, "use", text="", index=index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label("", icon_value=icon)
@@ -87,7 +87,7 @@ class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel):
col = split.column()
col.prop(scene, "layers", text="Scene")
col.label(text="")
- col.prop(rl, "light_override", text="Light")
+ col.prop(rl, "light_override", text="Lights")
col.prop(rl, "material_override", text="Material")
col = split.column()
@@ -126,7 +126,8 @@ class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
- def draw_pass_type_buttons(self, box, rl, pass_type):
+ @staticmethod
+ def draw_pass_type_buttons(box, rl, pass_type):
# property names
use_pass_type = "use_pass_" + pass_type
exclude_pass_type = "exclude_" + pass_type
@@ -167,5 +168,63 @@ class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
self.draw_pass_type_buttons(col, rl, "refraction")
+class RENDERLAYER_UL_renderviews(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.SceneRenderView)
+ view = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if view.name in {'left', 'right'}:
+ layout.label(view.name, icon_value=icon + (not view.use))
+ else:
+ layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False)
+ layout.prop(view, "use", text="", index=index)
+
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label("", icon_value=icon + (not view.use))
+
+
+class RENDERLAYER_PT_views(RenderLayerButtonsPanel, Panel):
+ bl_label = "Views"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "use_multiview", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rv = rd.views.active
+
+ layout.active = rd.use_multiview
+ basic_stereo = rd.views_format == 'STEREO_3D'
+
+ row = layout.row()
+ row.prop(rd, "views_format", expand=True)
+
+ if basic_stereo:
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
+
+ row = layout.row()
+ row.label(text="File Suffix:")
+ row.prop(rv, "file_suffix", text="")
+
+ else:
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("scene.render_view_add", icon='ZOOMIN', text="")
+ col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
+
+ row = layout.row()
+ row.label(text="Camera Suffix:")
+ row.prop(rv, "camera_suffix", text="")
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index facf54d358a..bbf11abe6d9 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -35,7 +35,7 @@ class SCENE_UL_keying_set_paths(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
# Do not make this one editable in uiList for now...
layout.label(text=kspath.data_path, translate=False, icon_value=icon)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -86,19 +86,25 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
class SceneKeyingSetsPanel:
- def draw_keyframing_settings(self, context, layout, ks, ksp):
- self.draw_keyframing_setting(context, layout, ks, ksp, "Needed",
- "use_insertkey_override_needed", "use_insertkey_needed",
- userpref_fallback="use_keyframe_insert_needed")
- self.draw_keyframing_setting(context, layout, ks, ksp, "Visual",
- "use_insertkey_override_visual", "use_insertkey_visual",
- userpref_fallback="use_visual_keying")
+ @staticmethod
+ def draw_keyframing_settings(context, layout, ks, ksp):
+ SceneKeyingSetsPanel._draw_keyframing_setting(
+ context, layout, ks, ksp, "Needed",
+ "use_insertkey_override_needed", "use_insertkey_needed",
+ userpref_fallback="use_keyframe_insert_needed")
- self.draw_keyframing_setting(context, layout, ks, ksp, "XYZ to RGB",
- "use_insertkey_override_xyz_to_rgb", "use_insertkey_xyz_to_rgb")
+ SceneKeyingSetsPanel._draw_keyframing_setting(
+ context, layout, ks, ksp, "Visual",
+ "use_insertkey_override_visual", "use_insertkey_visual",
+ userpref_fallback="use_visual_keying")
- def draw_keyframing_setting(self, context, layout, ks, ksp, label, toggle_prop, prop, userpref_fallback=None):
+ SceneKeyingSetsPanel._draw_keyframing_setting(
+ context, layout, ks, ksp, "XYZ to RGB",
+ "use_insertkey_override_xyz_to_rgb", "use_insertkey_xyz_to_rgb")
+
+ @staticmethod
+ def _draw_keyframing_setting(context, layout, ks, ksp, label, toggle_prop, prop, userpref_fallback=None):
if ksp:
item = ksp
@@ -392,14 +398,17 @@ class SCENE_PT_simplify(SceneButtonsPanel, Panel):
split = layout.split()
col = split.column()
+ col.label(text="Viewport:")
col.prop(rd, "simplify_subdivision", text="Subdivision")
col.prop(rd, "simplify_child_particles", text="Child Particles")
- col.prop(rd, "use_simplify_triangulate")
-
col = split.column()
+ col.label(text="Render:")
+ col.prop(rd, "simplify_subdivision_render", text="Subdivision")
+ col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col.prop(rd, "simplify_shadow_samples", text="Shadow Samples")
col.prop(rd, "simplify_ao_sss", text="AO and SSS")
+ col.prop(rd, "use_simplify_triangulate")
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index a48e06249fb..78ea4fa6c3f 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -72,7 +72,7 @@ class TEXTURE_UL_texslots(UIList):
layout.label(text="", icon_value=icon)
if tex and isinstance(item, bpy.types.MaterialTextureSlot):
layout.prop(ma, "use_textures", text="", index=index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -676,8 +676,7 @@ class TEXTURE_PT_musgrave(TextureTypePanel, Panel):
col = split.column()
if musgrave_type in {'HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
col.prop(tex, "offset")
- if musgrave_type in {'MULTIFRACTAL', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
- col.prop(tex, "noise_intensity", text="Intensity")
+ col.prop(tex, "noise_intensity", text="Intensity")
if musgrave_type in {'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
col.prop(tex, "gain")
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index a9fcdea35c7..ed4a78420d8 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -37,7 +37,7 @@ class CLIP_UL_tracking_objects(UIList):
layout.prop(tobj, "name", text="", emboss=False,
icon='CAMERA_DATA' if tobj.is_camera
else 'OBJECT_DATA')
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="",
icon='CAMERA_DATA' if tobj.is_camera
@@ -147,7 +147,7 @@ class CLIP_HT_header(Header):
sc = context.space_data
- if sc.mode in {'TRACKING'}:
+ if sc.mode == 'TRACKING':
self._draw_tracking(context)
else:
self._draw_masking(context)
@@ -716,7 +716,7 @@ class CLIP_PT_tracking_camera(Panel):
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
- return sc.mode in {'TRACKING'} and sc.clip
+ return sc.mode == 'TRACKING' and sc.clip
return False
@@ -756,7 +756,7 @@ class CLIP_PT_tracking_lens(Panel):
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
- return sc.mode in {'TRACKING'} and sc.clip
+ return sc.mode == 'TRACKING' and sc.clip
return False
@@ -893,7 +893,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
- return sc.mode in {'TRACKING'} and sc.clip
+ return sc.mode == 'TRACKING' and sc.clip
return False
@@ -987,7 +987,9 @@ class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
if clip.use_proxy_custom_directory:
col.prop(clip.proxy, "directory")
- col.operator("clip.rebuild_proxy", text="Build Proxy")
+ col.operator("clip.rebuild_proxy",
+ text="Build Proxy / Timecode" if clip.source == 'MOVIE'
+ else "Build Proxy")
if clip.source == 'MOVIE':
col2 = col.column()
@@ -1147,12 +1149,15 @@ class CLIP_MT_view(Menu):
layout.operator("clip.view_selected")
layout.operator("clip.view_all")
+ layout.operator("clip.view_all", text="View Fit").fit_view = True
layout.separator()
layout.operator("clip.view_zoom_in")
layout.operator("clip.view_zoom_out")
layout.separator()
+ layout.prop(sc, "show_metadata")
+ layout.separator()
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
@@ -1277,8 +1282,8 @@ class CLIP_MT_reconstruction(Menu):
layout.operator("clip.set_plane", text="Set Floor").plane = 'FLOOR'
layout.operator("clip.set_plane", text="Set Wall").plane = 'WALL'
- layout.operator("clip.set_axis", text="Set X Axis").axis = "X"
- layout.operator("clip.set_axis", text="Set Y Axis").axis = "Y"
+ layout.operator("clip.set_axis", text="Set X Axis").axis = 'X'
+ layout.operator("clip.set_axis", text="Set Y Axis").axis = 'Y'
layout.operator("clip.set_scale")
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 5358670c2f2..0b7502b585b 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -51,6 +51,11 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
row.prop(dopesheet, "show_only_matching_fcurves", text="")
if dopesheet.show_only_matching_fcurves:
row.prop(dopesheet, "filter_fcurve_name", text="")
+ else:
+ row = layout.row(align=True)
+ row.prop(dopesheet, "use_filter_text", text="")
+ if dopesheet.use_filter_text:
+ row.prop(dopesheet, "filter_text", text="")
if not genericFiltersOnly:
row = layout.row(align=True)
@@ -105,6 +110,7 @@ class DOPESHEET_HT_header(Header):
layout = self.layout
st = context.space_data
+ toolsettings = context.tool_settings
row = layout.row(align=True)
row.template_header()
@@ -112,6 +118,18 @@ class DOPESHEET_HT_header(Header):
DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
layout.prop(st, "mode", text="")
+
+ if st.mode in {'ACTION', 'SHAPEKEY'}:
+ row = layout.row(align=True)
+ row.operator("action.layer_prev", text="", icon='TRIA_DOWN')
+ row.operator("action.layer_next", text="", icon='TRIA_UP')
+
+ layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
+
+ row = layout.row(align=True)
+ row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
+ row.operator("action.stash", text="Stash", icon='FREEZE')
+
layout.prop(st.dopesheet, "show_summary", text="Summary")
if st.mode == 'DOPESHEET':
@@ -121,12 +139,12 @@ class DOPESHEET_HT_header(Header):
# filters which will work here and are useful (especially for character animation)
dopesheet_filter(layout, context, genericFiltersOnly=True)
- if st.mode in {'ACTION', 'SHAPEKEY'}:
- layout.template_ID(st, "action", new="action.new")
-
- row = layout.row(align=True)
- row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
- row.operator("action.stash", text="Stash", icon='FREEZE')
+ row = layout.row(align=True)
+ row.prop(toolsettings, "use_proportional_action",
+ text="", icon_only=True)
+ if toolsettings.use_proportional_action:
+ row.prop(toolsettings, "proportional_edit_falloff",
+ text="", icon_only=True)
# Grease Pencil mode doesn't need snapping, as it's frame-aligned only
if st.mode != 'GPENCIL':
@@ -190,6 +208,7 @@ class DOPESHEET_MT_view(Menu):
layout.separator()
layout.operator("action.view_all")
layout.operator("action.view_selected")
+ layout.operator("action.view_frame")
layout.separator()
layout.operator("screen.area_dupli")
@@ -390,5 +409,18 @@ class DOPESHEET_MT_gpencil_frame(Menu):
#layout.operator("action.copy")
#layout.operator("action.paste")
+
+class DOPESHEET_MT_delete(Menu):
+ bl_label = "Delete"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("action.delete")
+
+ layout.separator()
+
+ layout.operator("action.clean")
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 841e169b080..0d900a41f25 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -44,15 +44,19 @@ class FILEBROWSER_HT_header(Header):
row.separator()
row = layout.row(align=True)
- layout.operator_context = "EXEC_DEFAULT"
+ layout.operator_context = 'EXEC_DEFAULT'
row.operator("file.directory_new", icon='NEWFOLDER')
- layout.operator_context = "INVOKE_DEFAULT"
+ layout.operator_context = 'INVOKE_DEFAULT'
params = st.params
# can be None when save/reload with a file selector open
if params:
layout.prop(params, "display_type", expand=True, text="")
+
+ if params.display_type == 'FILE_IMGDISPLAY':
+ layout.prop(params, "thumbnail_size", text="")
+
layout.prop(params, "sort_method", expand=True, text="")
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
@@ -84,7 +88,7 @@ class FILEBROWSER_HT_header(Header):
class FILEBROWSER_UL_dir(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
direntry = item
- space = context.space_data
+ # space = context.space_data
icon = 'NONE'
if active_propname == "system_folders_active":
icon = 'DISK_DRIVE'
@@ -99,12 +103,12 @@ class FILEBROWSER_UL_dir(bpy.types.UIList):
row = layout.row(align=True)
row.enabled = direntry.is_valid
# Non-editable entries would show grayed-out, which is bad in this specific case, so switch to mere label.
- if direntry.is_property_readonly('name'):
+ if direntry.is_property_readonly("name"):
row.label(text=direntry.name, icon=icon)
else:
row.prop(direntry, "name", text="", emboss=False, icon=icon)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.prop(direntry, "path", text="")
@@ -124,6 +128,7 @@ class FILEBROWSER_PT_system_folders(Panel):
row.template_list("FILEBROWSER_UL_dir", "system_folders", space, "system_folders",
space, "system_folders_active", item_dyntip_propname="path", rows=1, maxrows=10)
+
class FILEBROWSER_PT_system_bookmarks(Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOLS'
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index d3e1a866e43..2f5381e58c8 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -29,6 +29,7 @@ class GRAPH_HT_header(Header):
from bl_ui.space_dopesheet import dopesheet_filter
layout = self.layout
+ toolsettings = context.tool_settings
st = context.space_data
@@ -46,6 +47,14 @@ class GRAPH_HT_header(Header):
row.active = st.use_normalization
row.prop(st, "use_auto_normalization", text="Auto")
+ row = layout.row(align=True)
+
+ row.prop(toolsettings, "use_proportional_fcurve",
+ text="", icon_only=True)
+ if toolsettings.use_proportional_fcurve:
+ row.prop(toolsettings, "proportional_edit_falloff",
+ text="", icon_only=True)
+
layout.prop(st, "auto_snap", text="")
layout.prop(st, "pivot_point", icon_only=True)
@@ -116,6 +125,7 @@ class GRAPH_MT_view(Menu):
layout.separator()
layout.operator("graph.view_all")
layout.operator("graph.view_selected")
+ layout.operator("graph.view_frame")
layout.separator()
layout.operator("screen.area_dupli")
@@ -271,5 +281,19 @@ class GRAPH_MT_key_transform(Menu):
layout.operator("transform.rotate", text="Rotate")
layout.operator("transform.resize", text="Scale")
+
+class GRAPH_MT_delete(Menu):
+ bl_label = "Delete"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("graph.delete")
+
+ layout.separator()
+
+ layout.operator("graph.clean")
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index a75e0916c09..1345a2c51fb 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -84,6 +84,7 @@ class IMAGE_MT_view(Menu):
layout.prop(toolsettings, "show_uv_local_view")
layout.prop(uv, "show_other_objects")
+ layout.prop(uv, "show_metadata")
if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
layout.prop(uv, "show_texpaint")
layout.prop(toolsettings, "show_uv_local_view", text="Show same material")
@@ -106,6 +107,7 @@ class IMAGE_MT_view(Menu):
layout.operator("image.view_selected")
layout.operator("image.view_all")
+ layout.operator("image.view_all", text="View Fit").fit_view = True
layout.separator()
@@ -127,6 +129,7 @@ class IMAGE_MT_select(Menu):
layout.operator("uv.select_border").pinned = False
layout.operator("uv.select_border", text="Border Select Pinned").pinned = True
+ layout.operator("uv.circle_select")
layout.separator()
@@ -335,7 +338,8 @@ class IMAGE_MT_uvs(Menu):
layout.operator("uv.average_islands_scale")
layout.operator("uv.minimize_stretch")
layout.operator("uv.stitch")
- layout.operator("uv.mark_seam")
+ layout.operator("uv.mark_seam").clear = False
+ layout.operator("uv.mark_seam", text="Clear Seam").clear = True
layout.operator("uv.seams_from_islands")
layout.operator("mesh.faces_mirror_uv")
@@ -458,6 +462,10 @@ class IMAGE_HT_header(Header):
layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")
if ima:
+ if ima.is_stereo_3d:
+ row = layout.row()
+ row.prop(sima, "show_stereo_3d", text="")
+
# layers
layout.template_image_layers(ima, iuser)
@@ -566,7 +574,7 @@ class IMAGE_PT_image_properties(Panel):
sima = context.space_data
iuser = sima.image_user
- layout.template_image(sima, "image", iuser)
+ layout.template_image(sima, "image", iuser, multiview=True)
class IMAGE_PT_game_properties(Panel):
@@ -625,6 +633,8 @@ class IMAGE_PT_view_properties(Panel):
sima = context.space_data
ima = sima.image
+
+ show_render = sima.show_render
show_uvedit = sima.show_uvedit
show_maskedit = sima.show_maskedit
uvedit = sima.uv_editor
@@ -669,7 +679,7 @@ class IMAGE_PT_view_properties(Panel):
sub.active = uvedit.show_stretch
sub.row().prop(uvedit, "draw_stretch_type", expand=True)
- if ima:
+ if show_render and ima:
layout.separator()
render_slot = ima.render_slots.active
layout.prop(render_slot, "name", text="Slot Name")
@@ -1051,10 +1061,10 @@ class ImageScopesPanel:
if not (sima and sima.image):
return False
# scopes are not updated in paint modes, hide
- if sima.mode in {'PAINT'}:
+ if sima.mode == 'PAINT':
return False
ob = context.active_object
- if ob and ob.mode in {'TEXTURE_PAINT'}:
+ if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}:
return False
return True
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 927967c8bc6..48a1b28289e 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -282,6 +282,10 @@ class INFO_MT_window(Menu):
layout.separator()
layout.operator("wm.console_toggle", icon='CONSOLE')
+ if context.scene.render.use_multiview:
+ layout.separator()
+ layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO')
+
class INFO_MT_help(Menu):
bl_label = "Help"
diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py
index 16182da1018..48b54feba17 100644
--- a/release/scripts/startup/bl_ui/space_logic.py
+++ b/release/scripts/startup/bl_ui/space_logic.py
@@ -54,11 +54,11 @@ class LOGIC_PT_properties(Panel):
row.label("See Text Object")
else:
props = layout.operator("object.game_property_new", text="Add Text Game Property", icon='ZOOMIN')
- props.name = 'Text'
+ props.name = "Text"
props.type = 'STRING'
props = layout.operator("object.game_property_new", text="Add Game Property", icon='ZOOMIN')
- props.name = ''
+ props.name = ""
for i, prop in enumerate(game.properties):
@@ -71,6 +71,13 @@ class LOGIC_PT_properties(Panel):
row.prop(prop, "type", text="")
row.prop(prop, "value", text="")
row.prop(prop, "show_debug", text="", toggle=True, icon='INFO')
+ sub = row.row(align=True)
+ props = sub.operator("object.game_property_move", text="", icon='TRIA_UP')
+ props.index = i
+ props.direction = 'UP'
+ props = sub.operator("object.game_property_move", text="", icon='TRIA_DOWN')
+ props.index = i
+ props.direction = 'DOWN'
row.operator("object.game_property_remove", text="", icon='X', emboss=False).index = i
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index ae432c44bf6..c083907f017 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -168,8 +168,10 @@ class NLA_MT_edit(Menu):
layout.separator()
# TODO: names of these tools for 'tweak-mode' need changing?
if scene.is_nla_tweakmode:
+ layout.operator("nla.tweakmode_exit", text="Stop Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_exit", text="Stop Tweaking Strip Actions")
else:
+ layout.operator("nla.tweakmode_enter", text="Start Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions")
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index a5ab6898b13..d0d1376fe05 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
+from bpy.app.translations import pgettext_iface as iface_
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
@@ -66,7 +67,7 @@ class NODE_HT_header(Header):
if snode_id and not (scene.render.use_shading_nodes == 0 and ob.type == 'LAMP'):
layout.prop(snode_id, "use_nodes")
- if snode.shader_type == 'WORLD':
+ if scene.render.use_shading_nodes and snode.shader_type == 'WORLD':
row = layout.row()
row.enabled = not snode.pin
row.template_ID(scene, "world", new="world.new")
@@ -208,8 +209,8 @@ class NODE_MT_select(Menu):
layout.separator()
layout.operator("node.select_grouped").extend = False
- layout.operator("node.select_same_type_step").prev = True
- layout.operator("node.select_same_type_step").prev = False
+ layout.operator("node.select_same_type_step", text="Activate Same Type Previous").prev = True
+ layout.operator("node.select_same_type_step", text="Activate Same Type Next").prev = False
layout.separator()
@@ -358,7 +359,7 @@ class NODE_PT_active_node_properties(Panel):
layout.label("Inputs:")
for socket in value_inputs:
row = layout.row()
- socket.draw(context, row, node, socket.name)
+ socket.draw(context, row, node, iface_(socket.name, socket.bl_rna.translation_context))
# Node Backdrop options
@@ -440,7 +441,7 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
if socket.is_output:
row.template_node_socket(color)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.template_node_socket(color)
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 0be1bf0b90a..43224412009 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
+from rna_prop_ui import PropertyPanel
from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel, GreasePencilToolsPanel
from bpy.app.translations import pgettext_iface as iface_
@@ -206,6 +207,7 @@ class SEQUENCER_MT_view(Menu):
if is_preview:
if st.display_mode == 'IMAGE':
layout.prop(st, "show_safe_areas")
+ layout.prop(st, "show_metadata")
elif st.display_mode == 'WAVEFORM':
layout.prop(st, "show_separate_color")
@@ -228,12 +230,12 @@ class SEQUENCER_MT_select(Menu):
layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT'
layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT'
- op = layout.operator("sequencer.select", text="All strips to the Left")
- op.left_right = 'LEFT'
- op.linked_time = True
- op = layout.operator("sequencer.select", text="All strips to the Right")
- op.left_right = 'RIGHT'
- op.linked_time = True
+ props = layout.operator("sequencer.select", text="All strips to the Left")
+ props.left_right = 'LEFT'
+ props.linked_time = True
+ props = layout.operator("sequencer.select", text="All strips to the Right")
+ props.left_right = 'RIGHT'
+ props.linked_time = True
layout.separator()
layout.operator("sequencer.select_handles", text="Surrounding Handles").side = 'BOTH'
@@ -472,7 +474,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
split.label(text="Type:")
split.prop(strip, "type", text="")
- if strip.type not in {'SOUND'}:
+ if strip.type != 'SOUND':
split = layout.split(percentage=0.3)
split.label(text="Blend:")
split.prop(strip, "blend_type", text="")
@@ -658,6 +660,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ scene = context.scene
strip = act_strip(context)
@@ -671,7 +674,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
# Current element for the filename
- elem = strip.strip_elem_from_frame(context.scene.frame_current)
+ elem = strip.strip_elem_from_frame(scene.frame_current)
if elem:
split = layout.split(percentage=0.2)
split.label(text="File:")
@@ -717,6 +720,19 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
col.prop(strip, "frame_offset_start", text="Start")
col.prop(strip, "frame_offset_end", text="End")
+ if scene.render.use_multiview and seq_type in {'IMAGE', 'MOVIE'}:
+ layout.prop(strip, "use_multiview")
+
+ col = layout.column()
+ col.active = strip.use_multiview
+
+ col.label(text="Views Format:")
+ col.row().prop(strip, "views_format", expand=True)
+
+ box = col.box()
+ box.active = strip.views_format == 'STEREO_3D'
+ box.template_image_stereo_3d(strip.stereo_3d_format)
+
class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
bl_label = "Sound"
@@ -913,44 +929,43 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ sequencer = context.scene.sequence_editor
+
strip = act_strip(context)
- flow = layout.column_flow()
- flow.prop(strip, "use_proxy_custom_directory")
- flow.prop(strip, "use_proxy_custom_file")
if strip.proxy:
- if strip.use_proxy_custom_directory and not strip.use_proxy_custom_file:
- flow.prop(strip.proxy, "directory")
- if strip.use_proxy_custom_file:
- flow.prop(strip.proxy, "filepath")
+ proxy = strip.proxy
- layout.label("Enabled Proxies:")
- enabled = ""
- row = layout.row()
- if (strip.proxy.build_25):
- enabled += "25% "
- if (strip.proxy.build_50):
- enabled += "50% "
- if (strip.proxy.build_75):
- enabled += "75% "
- if (strip.proxy.build_100):
- enabled += "100% "
-
- row.label(enabled)
- if (strip.proxy.use_overwrite):
- layout.label("Overwrite On")
+ flow = layout.column_flow()
+ flow.prop(sequencer, "proxy_storage")
+ if sequencer.proxy_storage == 'PROJECT':
+ flow.prop(sequencer, "proxy_dir")
else:
- layout.label("Overwrite Off")
+ flow.prop(proxy, "use_proxy_custom_directory")
+ flow.prop(proxy, "use_proxy_custom_file")
+
+ if proxy.use_proxy_custom_directory and not proxy.use_proxy_custom_file:
+ flow.prop(proxy, "directory")
+ if proxy.use_proxy_custom_file:
+ flow.prop(proxy, "filepath")
+
+ row = layout.row()
+ row.prop(strip.proxy, "build_25")
+ row.prop(strip.proxy, "build_50")
+ row.prop(strip.proxy, "build_75")
+ row.prop(strip.proxy, "build_100")
+
+ layout.prop(proxy, "use_overwrite")
col = layout.column()
col.label(text="Build JPEG quality")
- col.prop(strip.proxy, "quality")
+ col.prop(proxy, "quality")
if strip.type == 'MOVIE':
col = layout.column()
col.label(text="Use timecode index:")
- col.prop(strip.proxy, "timecode")
+ col.prop(proxy, "timecode")
col = layout.column()
col.operator("sequencer.enable_proxies")
@@ -1036,6 +1051,7 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
layout.prop(strip, "use_linear_modifiers")
layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
+ layout.operator("sequencer.strip_modifier_copy")
for mod in strip.modifiers:
box = layout.box()
@@ -1098,5 +1114,11 @@ class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsP
# toolbar, which doesn't exist here...
+class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ _context_path = "scene.sequence_editor.active_strip"
+ _property_type = (bpy.types.Sequence,)
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 27fcf94666a..c4c4097315c 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -30,6 +30,7 @@ class TIME_HT_header(Header):
scene = context.scene
toolsettings = context.tool_settings
screen = context.screen
+ userprefs = context.user_preferences
row = layout.row(align=True)
row.template_header()
@@ -82,7 +83,7 @@ class TIME_HT_header(Header):
if toolsettings.use_keyframe_insert_auto:
row.prop(toolsettings, "use_keyframe_insert_keyingset", text="", toggle=True)
- if screen.is_animation_playing:
+ if screen.is_animation_playing and not userprefs.edit.use_keyframe_insert_available:
subsub = row.row(align=True)
subsub.prop(toolsettings, "use_record_with_nla", toggle=True)
@@ -253,6 +254,10 @@ def marker_menu_generic(layout):
layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
+ layout.separator()
+ ts = bpy.context.tool_settings
+ layout.prop(ts, "lock_markers")
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 3b17e40c294..0272f752bab 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -113,11 +113,11 @@ class USERPREF_MT_splash(Menu):
row.label("")
row = split.row()
row.label("Interaction:")
- # XXX, no redraws
- # text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
- # if not text:
- # text = "Blender (default)"
- row.menu("USERPREF_MT_appconfigs", text="Preset")
+
+ text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
+ if not text:
+ text = "Blender (default)"
+ row.menu("USERPREF_MT_appconfigs", text=text)
# only for addons
@@ -200,6 +200,11 @@ class USERPREF_PT_interface(Panel):
col.label(text="2D Viewports:")
col.prop(view, "view2d_grid_spacing_min", text="Minimum Grid Spacing")
col.prop(view, "timecode_style")
+ col.prop(view, "view_frame_type")
+ if (view.view_frame_type == 'SECONDS'):
+ col.prop(view, "view_frame_seconds")
+ elif (view.view_frame_type == 'KEYFRAMES'):
+ col.prop(view, "view_frame_keyframes")
row.separator()
row.separator()
@@ -1041,7 +1046,8 @@ class USERPREF_PT_input(Panel):
userpref = context.user_preferences
return (userpref.active_section == 'INPUT')
- def draw_input_prefs(self, inputs, layout):
+ @staticmethod
+ def draw_input_prefs(inputs, layout):
import sys
# General settings
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index c65cebfde10..1047d12fa5b 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -86,7 +86,7 @@ class VIEW3D_HT_header(Header):
row = layout.row(align=True)
row.prop(toolsettings, "use_snap", text="")
row.prop(toolsettings, "snap_element", icon_only=True)
- if snap_element != 'INCREMENT':
+ if snap_element not in {'INCREMENT', 'GRID'}:
row.prop(toolsettings, "snap_target", text="")
if obj:
if mode in {'OBJECT', 'POSE'} and snap_element != 'VOLUME':
@@ -158,7 +158,7 @@ class VIEW3D_MT_editor_menus(Menu):
if edit_object:
layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
elif obj:
- if mode_string not in {'PAINT_TEXTURE'}:
+ if mode_string != 'PAINT_TEXTURE':
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
if mode_string in {'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'PAINT_TEXTURE'}:
layout.menu("VIEW3D_MT_brush")
@@ -208,8 +208,10 @@ class VIEW3D_MT_transform_base(Menu):
layout.operator("transform.shear", text="Shear")
layout.operator("transform.bend", text="Bend")
layout.operator("transform.push_pull", text="Push/Pull")
- layout.operator("object.vertex_warp", text="Warp")
- layout.operator("object.vertex_random", text="Randomize")
+
+ if context.mode != 'OBJECT':
+ layout.operator("transform.vertex_warp", text="Warp")
+ layout.operator("transform.vertex_random", text="Randomize")
# Generic transform menu - geometry types
@@ -935,7 +937,7 @@ class VIEW3D_MT_angle_control(Menu):
settings = UnifiedPaintPanel.paint_settings(context)
brush = settings.brush
- sculpt = (context.sculpt_object != None)
+ sculpt = (context.sculpt_object is not None)
tex_slot = brush.texture_slot
@@ -1043,6 +1045,17 @@ class INFO_MT_armature_add(Menu):
layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA')
+class INFO_MT_lamp_add(Menu):
+ bl_idname = "INFO_MT_lamp_add"
+ bl_label = "Lamp"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator_enum("object.lamp_add", "type")
+
+
class INFO_MT_add(Menu):
bl_label = "Add"
@@ -1075,7 +1088,7 @@ class INFO_MT_add(Menu):
layout.separator()
layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
- layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP')
+ layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP')
layout.separator()
layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_EMPTY')
@@ -1654,10 +1667,10 @@ class VIEW3D_MT_paint_weight(Menu):
layout.operator("object.vertex_group_clean", text="Clean")
layout.operator("object.vertex_group_quantize", text="Quantize")
layout.operator("object.vertex_group_levels", text="Levels")
- layout.operator("object.vertex_group_blend", text="Blend")
- prop = layout.operator("object.data_transfer", text="Transfer Weights")
- prop.use_reverse_transfer = True
- prop.data_type = 'VGROUP_WEIGHTS'
+ layout.operator("object.vertex_group_smooth", text="Smooth")
+ props = layout.operator("object.data_transfer", text="Transfer Weights")
+ props.use_reverse_transfer = True
+ props.data_type = 'VGROUP_WEIGHTS'
layout.operator("object.vertex_group_limit_total", text="Limit Total")
layout.operator("object.vertex_group_fix", text="Fix Deforms")
@@ -1933,6 +1946,10 @@ class VIEW3D_MT_pose_propagate(Menu):
layout.separator()
+ layout.operator("pose.propagate", text="On Selected Keyframes").mode = 'SELECTED_KEYS'
+
+ layout.separator()
+
layout.operator("pose.propagate", text="On Selected Markers").mode = 'SELECTED_MARKERS'
@@ -2262,10 +2279,10 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.separator()
- op = layout.operator("mesh.mark_sharp", text="Shade Smooth")
- op.use_verts = True
- op.clear = True
- layout.operator("mesh.mark_sharp", text="Shade Sharp").use_verts = True
+ layout.operator("mesh.mark_sharp", text="Mark Sharp Edges").use_verts = True
+ props = layout.operator("mesh.mark_sharp", text="Clear Sharp Edges")
+ props.use_verts = True
+ props.clear = True
layout.separator()
@@ -2276,7 +2293,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.operator("mesh.blend_from_shape")
- layout.operator("object.vertex_group_blend")
+ layout.operator("object.vertex_group_smooth")
layout.operator("mesh.shape_propagate_to_all")
layout.separator()
@@ -2419,6 +2436,7 @@ class VIEW3D_MT_edit_mesh_clean(Menu):
layout.operator("mesh.dissolve_degenerate")
layout.operator("mesh.dissolve_limited")
+ layout.operator("mesh.face_make_planar")
layout.operator("mesh.vert_connect_nonplanar")
layout.operator("mesh.vert_connect_concave")
layout.operator("mesh.fill_holes")
@@ -2467,6 +2485,7 @@ def draw_curve(self, context):
layout.separator()
layout.operator("curve.extrude_move")
+ layout.operator("curve.spin")
layout.operator("curve.duplicate_move")
layout.operator("curve.split")
layout.operator("curve.separate")
@@ -2568,10 +2587,6 @@ class VIEW3D_MT_edit_font(Menu):
layout.operator("font.style_toggle", text="Toggle Underline").style = 'UNDERLINE'
layout.operator("font.style_toggle", text="Toggle Small Caps").style = 'SMALL_CAPS'
- layout.separator()
-
- layout.operator("font.insert_lorem")
-
class VIEW3D_MT_edit_text_chars(Menu):
bl_label = "Special Characters"
@@ -2710,6 +2725,7 @@ class VIEW3D_MT_edit_armature(Menu):
layout.separator()
layout.operator_context = 'EXEC_AREA'
+ layout.operator("armature.symmetrize")
layout.operator("armature.autoside_names", text="AutoName Left/Right").type = 'XAXIS'
layout.operator("armature.autoside_names", text="AutoName Front/Back").type = 'YAXIS'
layout.operator("armature.autoside_names", text="AutoName Top/Bottom").type = 'ZAXIS'
@@ -2748,6 +2764,7 @@ class VIEW3D_MT_armature_specials(Menu):
layout.operator("armature.autoside_names", text="AutoName Front/Back").type = 'YAXIS'
layout.operator("armature.autoside_names", text="AutoName Top/Bottom").type = 'ZAXIS'
layout.operator("armature.flip_names", text="Flip Names")
+ layout.operator("armature.symmetrize")
class VIEW3D_MT_edit_armature_parent(Menu):
@@ -2772,6 +2789,20 @@ class VIEW3D_MT_edit_armature_roll(Menu):
layout.operator("transform.transform", text="Set Roll").mode = 'BONE_ROLL'
+
+class VIEW3D_MT_edit_armature_delete(Menu):
+ bl_label = "Delete"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("armature.delete", text="Delete Bones")
+
+ layout.separator()
+
+ layout.operator("armature.dissolve", text="Dissolve")
+
+
# ********** Panel **********
@@ -2934,16 +2965,50 @@ class VIEW3D_PT_view3d_display(Panel):
row.prop(region, "use_box_clip")
-class VIEW3D_PT_view3d_shading(Panel):
+class VIEW3D_PT_view3d_stereo(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
- bl_label = "Shading"
+ bl_label = "Stereoscopy"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
+ scene = context.scene
+
+ multiview = scene.render.use_multiview
+ return context.space_data and multiview
+
+ def draw(self, context):
+ layout = self.layout
view = context.space_data
- return (view)
+
+ basic_stereo = context.scene.render.views_format == 'STEREO_3D'
+
+ col = layout.column()
+ col.row().prop(view, "stereo_3d_camera", expand=True)
+
+ col.label(text="Display:")
+ row = col.row()
+ row.active = basic_stereo
+ row.prop(view, "show_stereo_3d_cameras")
+ row = col.row()
+ row.active = basic_stereo
+ split = row.split()
+ split.prop(view, "show_stereo_3d_convergence_plane")
+ split = row.split()
+ split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha")
+ split.active = view.show_stereo_3d_convergence_plane
+ row = col.row()
+ split = row.split()
+ split.prop(view, "show_stereo_3d_volume")
+ split = row.split()
+ split.prop(view, "stereo_3d_volume_alpha", text="Alpha")
+
+
+class VIEW3D_PT_view3d_shading(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+ bl_label = "Shading"
def draw(self, context):
layout = self.layout
@@ -2973,12 +3038,12 @@ class VIEW3D_PT_view3d_shading(Panel):
if obj and obj.mode == 'EDIT':
col.prop(view, "show_occlude_wire")
- fx_settings = view.fx_settings
+ fx_settings = view.fx_settings
+ if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}:
sub = col.column()
sub.active = view.region_3d.view_perspective == 'CAMERA'
sub.prop(fx_settings, "use_dof")
-
col.prop(fx_settings, "use_ssao", text="Ambient Occlusion")
if fx_settings.use_ssao:
ssao_settings = fx_settings.ssao
@@ -3171,6 +3236,7 @@ class VIEW3D_PT_background_image(Panel):
layout = self.layout
view = context.space_data
+ use_multiview = context.scene.render.use_multiview
col = layout.column()
col.operator("view3d.background_image_add", text="Add Image")
@@ -3208,6 +3274,19 @@ class VIEW3D_PT_background_image(Panel):
box.template_image(bg, "image", bg.image_user, compact=True)
has_bg = True
+ if use_multiview and bg.view_axis in {'CAMERA','ALL'}:
+ box.prop(bg.image, "use_multiview")
+
+ column = box.column()
+ column.active = bg.image.use_multiview
+
+ column.label(text="Views Format:")
+ column.row().prop(bg.image, "views_format", expand=True)
+
+ sub = column.box()
+ sub.active = bg.image.views_format == 'STEREO_3D'
+ sub.template_image_stereo_3d(bg.image.stereo_3d_format)
+
elif bg.source == 'MOVIE_CLIP':
box.prop(bg, "use_camera_clip")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 70874460d4d..e381800ae02 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -100,7 +100,7 @@ class VIEW3D_PT_tools_object(View3DPanel, Panel):
row.operator("object.shade_smooth", text="Smooth")
row.operator("object.shade_flat", text="Flat")
- if obj_type in {'MESH'}:
+ if obj_type == 'MESH':
col = layout.column(align=True)
col.label(text="Data Transfer:")
row = col.row(align=True)
@@ -315,7 +315,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, Panel):
row.operator("transform.vert_slide", text="Vertex")
col.operator("mesh.noise")
col.operator("mesh.vertices_smooth")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
col = layout.column(align=True)
col.label(text="Add:")
@@ -327,6 +327,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, Panel):
col.operator("mesh.edge_face_add")
col.operator("mesh.subdivide")
col.operator("mesh.loopcut_slide")
+ col.operator("mesh.offset_edge_loops_slide")
col.operator("mesh.duplicate_move", text="Duplicate")
row = col.row(align=True)
row.operator("mesh.spin")
@@ -366,7 +367,7 @@ class VIEW3D_PT_tools_meshweight(View3DPanel, Panel):
col.operator("object.vertex_group_clean", text="Clean")
col.operator("object.vertex_group_quantize", text="Quantize")
col.operator("object.vertex_group_levels", text="Levels")
- col.operator("object.vertex_group_blend", text="Blend")
+ col.operator("object.vertex_group_smooth", text="Smooth")
col.operator("object.vertex_group_limit_total", text="Limit Total")
col.operator("object.vertex_group_fix", text="Fix Deforms")
@@ -407,9 +408,9 @@ class VIEW3D_PT_tools_shading(View3DPanel, Panel):
row.operator("mesh.mark_sharp", text="Sharp")
col.label(text="Vertices:")
row = col.row(align=True)
- op = row.operator("mesh.mark_sharp", text="Smooth")
- op.use_verts = True
- op.clear = True
+ props = row.operator("mesh.mark_sharp", text="Smooth")
+ props.use_verts = True
+ props.clear = True
row.operator("mesh.mark_sharp", text="Sharp").use_verts = True
col = layout.column(align=True)
@@ -523,7 +524,7 @@ class VIEW3D_PT_tools_curveedit(View3DPanel, Panel):
col.operator("curve.extrude_move", text="Extrude")
col.operator("curve.subdivide")
col.operator("curve.smooth")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_add_curve_edit(View3DPanel, Panel):
@@ -573,11 +574,12 @@ class VIEW3D_PT_tools_surfaceedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Modeling:")
col.operator("curve.extrude", text="Extrude")
+ col.operator("curve.spin")
col.operator("curve.subdivide")
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_add_surface_edit(View3DPanel, Panel):
@@ -654,7 +656,7 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
@@ -687,7 +689,7 @@ class VIEW3D_PT_tools_mballedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_add_mball_edit(View3DPanel, Panel):
@@ -725,7 +727,7 @@ class VIEW3D_PT_tools_latticeedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
# ********** default tools for pose-mode ****************
@@ -758,6 +760,10 @@ class VIEW3D_PT_tools_posemode(View3DPanel, Panel):
row.operator("pose.copy", text="Copy")
row.operator("pose.paste", text="Paste")
+ row = layout.row(align=True)
+ row.operator("pose.propagate", text="Propagate")
+ row.menu("VIEW3D_MT_pose_propagate", icon='TRIA_RIGHT', text="")
+
col = layout.column(align=True)
col.operator("poselib.pose_add", text="Add To Library")
@@ -1071,7 +1077,7 @@ class TEXTURE_UL_texpaintslots(UIList):
if (not mat.use_nodes) and context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}:
mtex_index = mat.texture_paint_slots[index].index
layout.prop(mat, "use_textures", text="", index=mtex_index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="")
@@ -1467,6 +1473,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
row = sub.row(align=True)
row.prop(sculpt, "constant_detail")
row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
+ elif (sculpt.detail_type_method == 'BRUSH'):
+ sub.prop(sculpt, "detail_percent")
else:
sub.prop(sculpt, "detail_size")
sub.prop(sculpt, "detail_refine_method", text="")
@@ -1601,9 +1609,9 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel):
col = layout.column()
col.operator("paint.weight_gradient")
- prop = col.operator("object.data_transfer", text="Transfer Weights")
- prop.use_reverse_transfer = True
- prop.data_type = 'VGROUP_WEIGHTS'
+ props = col.operator("object.data_transfer", text="Transfer Weights")
+ props.use_reverse_transfer = True
+ props.data_type = 'VGROUP_WEIGHTS'
class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
@@ -1694,6 +1702,25 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
col.operator("paint.project_image", text="Apply Camera Image")
+class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
+ bl_category = "Tools"
+ bl_context = "imagepaint"
+ bl_label = "Symmetry"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ toolsettings = context.tool_settings
+ ipaint = toolsettings.image_paint
+
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
+ row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
+ row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
+
+
class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
bl_category = "Options"
bl_context = "imagepaint"
@@ -1854,7 +1881,7 @@ class VIEW3D_PT_tools_history(View3DPanel, Panel):
row = col.row(align=True)
row.operator("ed.undo")
row.operator("ed.redo")
- if obj is None or obj.mode not in {'SCULPT'}:
+ if obj is None or obj.mode != 'SCULPT':
# Sculpt mode does not generate an undo menu it seems...
col.operator("ed.undo_history")
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 1590bd49763..bee48de42f5 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -66,6 +66,8 @@ node_tree_group_type = {
# generic node group items generator for shader, compositor and texture node groups
def node_group_items(context):
+ if context is None:
+ return
space = context.space_data
if not space:
return
@@ -328,6 +330,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeCombYUVA"),
NodeItem("CompositorNodeSepYCCA"),
NodeItem("CompositorNodeCombYCCA"),
+ NodeItem("CompositorNodeSwitchView"),
]),
CompositorNodeCategory("CMP_OP_FILTER", "Filter", items=[
NodeItem("CompositorNodeBlur"),
diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py
index f0d8bede6d5..8e57d7ef8f8 100644
--- a/release/scripts/templates_py/addon_add_object.py
+++ b/release/scripts/templates_py/addon_add_object.py
@@ -2,12 +2,13 @@ bl_info = {
"name": "New Object",
"author": "Your Name Here",
"version": (1, 0),
- "blender": (2, 65, 0),
+ "blender": (2, 75, 0),
"location": "View3D > Add > Mesh > New Object",
"description": "Adds a new Mesh Object",
"warning": "",
"wiki_url": "",
- "category": "Add Mesh"}
+ "category": "Add Mesh",
+ }
import bpy
diff --git a/release/scripts/templates_py/operator_modal_timer.py b/release/scripts/templates_py/operator_modal_timer.py
index 4d36860b9e3..df4d10e656b 100644
--- a/release/scripts/templates_py/operator_modal_timer.py
+++ b/release/scripts/templates_py/operator_modal_timer.py
@@ -10,7 +10,8 @@ class ModalTimerOperator(bpy.types.Operator):
def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
- return self.cancel(context)
+ self.cancel(context)
+ return {'CANCELLED'}
if event.type == 'TIMER':
# change theme color, silly!
diff --git a/release/scripts/templates_py/ui_previews_custom_icon.py b/release/scripts/templates_py/ui_previews_custom_icon.py
new file mode 100644
index 00000000000..53f84b2982f
--- /dev/null
+++ b/release/scripts/templates_py/ui_previews_custom_icon.py
@@ -0,0 +1,76 @@
+# This sample script demonstrates how to place a custom icon on a button or
+# menu entry.
+#
+# IMPORTANT NOTE: if you run this sample, there will be no icon in the button
+# You need to replace the image path with a real existing one.
+# For distributable scripts, it is recommended to place the icons inside the
+# addon folder and access it relative to the py script file for portability
+#
+#
+# Other use cases for UI-previews:
+# - provide a fixed list of previews to select from
+# - provide a dynamic list of preview (eg. calculated from reading a directory)
+#
+# For the above use cases, see the template 'ui_previews_dynamic_enum.py"
+
+
+import os
+import bpy
+
+
+class PreviewsExamplePanel(bpy.types.Panel):
+ """Creates a Panel in the Object properties window"""
+ bl_label = "Previews Example Panel"
+ bl_idname = "OBJECT_PT_previews"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "object"
+
+ def draw(self, context):
+ layout = self.layout
+ pcoll = preview_collections["main"]
+
+ row = layout.row()
+ my_icon = pcoll["my_icon"]
+ row.operator("render.render", icon_value=my_icon.icon_id)
+
+ # my_icon.icon_id can be used in any UI function that accepts
+ # icon_value # try also setting text=""
+ # to get an icon only operator button
+
+
+# We can store multiple preview collections here,
+# however in this example we only store "main"
+preview_collections = {}
+
+
+def register():
+
+ # Note that preview collections returned by bpy.utils.previews
+ # are regular py objects - you can use them to store custom data.
+ import bpy.utils.previews
+ pcoll = bpy.utils.previews.new()
+
+ # path to the folder where the icon is
+ # the path is calculated relative to this py file inside the addon folder
+ my_icons_dir = os.path.join(os.path.dirname(__file__), "icons")
+
+ # load a preview thumbnail of a file and store in the previews collection
+ pcoll.load("my_icon", os.path.join(my_icons_dir, "icon-image.png"), 'IMAGE')
+
+ preview_collections["main"] = pcoll
+
+ bpy.utils.register_class(PreviewsExamplePanel)
+
+
+def unregister():
+
+ for pcoll in preview_collections.values():
+ bpy.utils.previews.remove(pcoll)
+ preview_collections.clear()
+
+ bpy.utils.unregister_class(PreviewsExamplePanel)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/templates_py/ui_previews_dynamic_enum.py b/release/scripts/templates_py/ui_previews_dynamic_enum.py
new file mode 100644
index 00000000000..0cfa232116d
--- /dev/null
+++ b/release/scripts/templates_py/ui_previews_dynamic_enum.py
@@ -0,0 +1,137 @@
+# This sample script demonstrates a dynamic EnumProperty with custom icons.
+# The EnumProperty is populated dynamically with thumbnails of the contents of
+# a chosen directory in 'enum_previews_from_directory_items'.
+# Then, the same enum is displayed with different interfaces. Note that the
+# generated icon previews do not have Blender IDs, which means that they can
+# not be used with UILayout templates that require IDs,
+# such as template_list and template_ID_preview.
+#
+# Other use cases:
+# - make a fixed list of enum_items instead of calculating them in a function
+# - generate isolated thumbnails to use as custom icons in buttons
+# and menu items
+#
+# For custom icons, see the template "ui_previews_custom_icon.py".
+#
+# For distributable scripts, it is recommended to place the icons inside the
+# script directory and access it relative to the py script file for portability:
+#
+# os.path.join(os.path.dirname(__file__), "images")
+
+
+import os
+import bpy
+
+
+def enum_previews_from_directory_items(self, context):
+ """EnumProperty callback"""
+ enum_items = []
+
+ if context is None:
+ return enum_items
+
+ wm = context.window_manager
+ directory = wm.my_previews_dir
+
+ # Get the preview collection (defined in register func).
+ pcoll = preview_collections["main"]
+
+ if directory == pcoll.my_previews_dir:
+ return pcoll.my_previews
+
+ print("Scanning directory: %s" % directory)
+
+ if directory and os.path.exists(directory):
+ # Scan the directory for png files
+ image_paths = []
+ for fn in os.listdir(directory):
+ if fn.lower().endswith(".png"):
+ image_paths.append(fn)
+
+ for i, name in enumerate(image_paths):
+ # generates a thumbnail preview for a file.
+ filepath = os.path.join(directory, name)
+ thumb = pcoll.load(filepath, filepath, 'IMAGE')
+ enum_items.append((name, name, "", thumb.icon_id, i))
+
+ pcoll.my_previews = enum_items
+ pcoll.my_previews_dir = directory
+ return pcoll.my_previews
+
+
+class PreviewsExamplePanel(bpy.types.Panel):
+ """Creates a Panel in the Object properties window"""
+ bl_label = "Previews Example Panel"
+ bl_idname = "OBJECT_PT_previews"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "object"
+
+ def draw(self, context):
+ layout = self.layout
+ wm = context.window_manager
+
+ row = layout.row()
+ row.prop(wm, "my_previews_dir")
+
+ row = layout.row()
+ row.template_icon_view(wm, "my_previews")
+
+ row = layout.row()
+ row.prop(wm, "my_previews")
+
+
+# We can store multiple preview collections here,
+# however in this example we only store "main"
+preview_collections = {}
+
+
+def register():
+ from bpy.types import WindowManager
+ from bpy.props import (
+ StringProperty,
+ EnumProperty,
+ )
+
+ WindowManager.my_previews_dir = StringProperty(
+ name="Folder Path",
+ subtype='DIR_PATH',
+ default=""
+ )
+
+ WindowManager.my_previews = EnumProperty(
+ items=enum_previews_from_directory_items,
+ )
+
+ # Note that preview collections returned by bpy.utils.previews
+ # are regular Python objects - you can use them to store custom data.
+ #
+ # This is especially useful here, since:
+ # - It avoids us regenerating the whole enum over and over.
+ # - It can store enum_items' strings
+ # (remember you have to keep those strings somewhere in py,
+ # else they get freed and Blender references invalid memory!).
+ import bpy.utils.previews
+ pcoll = bpy.utils.previews.new()
+ pcoll.my_previews_dir = ""
+ pcoll.my_previews = ()
+
+ preview_collections["main"] = pcoll
+
+ bpy.utils.register_class(PreviewsExamplePanel)
+
+
+def unregister():
+ from bpy.types import WindowManager
+
+ del WindowManager.my_previews
+
+ for pcoll in preview_collections.values():
+ bpy.utils.previews.remove(pcoll)
+ preview_collections.clear()
+
+ bpy.utils.unregister_class(PreviewsExamplePanel)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/release/windows/installer/00.sconsblender.nsi b/release/windows/installer/00.sconsblender.nsi
index f6e5b783faa..2d91b9da7f1 100644
--- a/release/windows/installer/00.sconsblender.nsi
+++ b/release/windows/installer/00.sconsblender.nsi
@@ -70,6 +70,13 @@ InstallDir $INSTDIR ; $INSTDIR is set inside .onInit
BrandingText "Blender Foundation | http://www.blender.org"
ComponentText "This will install Blender [VERSION] on your computer."
+VIAddVersionKey "ProductName" "Blender"
+VIAddVersionKey "CompanyName" "http://www.blender.org"
+VIAddVersionKey "FileDescription" "Free open source 3D content creation suite."
+VIAddVersionKey "FileVersion" "[SHORTVERSION].0.0"
+
+VIProductVersion "[SHORTVERSION].0.0"
+
DirText "Use the field below to specify the folder where you want Blender to be copied to. To specify a different folder, type a new name or use the Browse button to select an existing folder."
SilentUnInstall normal