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:
Diffstat (limited to 'release/scripts')
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/addon_utils.py21
-rw-r--r--release/scripts/modules/bl_previews_utils/bl_previews_render.py4
-rw-r--r--release/scripts/modules/bl_ui_utils/bug_report_url.py6
-rw-r--r--release/scripts/modules/bpy/ops.py2
-rw-r--r--release/scripts/modules/bpy/utils/previews.py7
-rw-r--r--release/scripts/modules/rna_keymap_ui.py3
-rw-r--r--release/scripts/modules/rna_prop_ui.py2
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py62
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py2
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/gpencil_mesh_bake.py162
-rw-r--r--release/scripts/startup/bl_operators/node.py9
-rw-r--r--release/scripts/startup/bl_operators/object.py5
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py7
-rw-r--r--release/scripts/startup/bl_operators/presets.py8
-rw-r--r--release/scripts/startup/bl_operators/screen_play_rendered_anim.py34
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py12
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py30
-rw-r--r--release/scripts/startup/bl_operators/view3d.py2
-rw-r--r--release/scripts/startup/bl_operators/wm.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py2097
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py28
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py484
-rw-r--r--release/scripts/startup/bl_ui/properties_data_shaderfx.py118
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py25
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py69
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py13
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py6
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py12
-rw-r--r--release/scripts/startup/bl_ui/space_text.py5
-rw-r--r--release/scripts/startup/bl_ui/space_time.py4
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py4
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py75
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py47
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py27
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py14
43 files changed, 1902 insertions, 1529 deletions
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 8397b98b8cb6510869d28a84592b8d7213c3b6c
+Subproject bc1262f4d61feeba235bb75046e65e0e8411241
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 7c36b48507f79ca62f8c038bad0fb3468c4f48e
+Subproject 45aa940dabda64f7877c6d5dd843998a86f0a83
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index a65ff15393a..8a074d23db9 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -172,8 +172,8 @@ def modules_refresh(module_cache=addons_fake_modules):
if mod.__file__ != mod_path:
print(
"multiple addons with the same name:\n"
- " " f"{mod.__file__!r}" "\n"
- " " f"{mod_path!r}"
+ " %r\n"
+ " %r" % (mod.__file__, mod_path)
)
error_duplicates.append((mod.bl_info["name"], mod.__file__, mod_path))
@@ -241,7 +241,7 @@ def check(module_name):
if loaded_state is Ellipsis:
print(
- "Warning: addon-module " f"{module_name:s}" " found module "
+ "Warning: addon-module", module_name, "found module "
"but without '__addon_enabled__' field, "
"possible name collision from file:",
repr(getattr(mod, "__file__", "<unknown>")),
@@ -439,8 +439,9 @@ def disable(module_name, *, default_set=False, handle_error=None):
handle_error(ex)
else:
print(
- "addon_utils.disable: " f"{module_name:s}" " not",
- ("disabled" if mod is None else "loaded")
+ "addon_utils.disable: %s not %s" % (
+ module_name,
+ "disabled" if mod is None else "loaded")
)
# could be in more than once, unlikely but better do this just in case.
@@ -502,7 +503,7 @@ def _blender_manual_url_prefix():
else:
manual_version = "dev"
- return f"https://docs.blender.org/manual/en/{manual_version}"
+ return "https://docs.blender.org/manual/en/" + manual_version
def module_bl_info(mod, info_basis=None):
@@ -544,11 +545,11 @@ def module_bl_info(mod, info_basis=None):
addon_info["doc_url"] = doc_url
if _bpy.app.debug:
print(
- "Warning: add-on \"{addon_name}\": 'wiki_url' in 'bl_info' "
+ "Warning: add-on \"%s\": 'wiki_url' in 'bl_info' "
"is deprecated please use 'doc_url' instead!\n"
- " {addon_path}".format(
- addon_name=addon_info['name'],
- addon_path=getattr(mod, "__file__", None),
+ " %s" % (
+ addon_info['name'],
+ getattr(mod, "__file__", None),
)
)
diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
index b79c0b744d0..73004cee731 100644
--- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py
+++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
@@ -505,7 +505,7 @@ def main():
if __name__ == "__main__":
- print("\n\n *** Running {} *** \n".format(__file__))
- print(" *** Blend file {} *** \n".format(bpy.data.filepath))
+ print("\n\n *** Running %s *** \n" % __file__)
+ print(" *** Blend file %s *** \n" % bpy.data.filepath)
main()
bpy.ops.wm.quit_blender()
diff --git a/release/scripts/modules/bl_ui_utils/bug_report_url.py b/release/scripts/modules/bl_ui_utils/bug_report_url.py
index 2adee70bc86..5676e0d6815 100644
--- a/release/scripts/modules/bl_ui_utils/bug_report_url.py
+++ b/release/scripts/modules/bl_ui_utils/bug_report_url.py
@@ -31,13 +31,13 @@ def url_prefill_from_blender(addon_info=None):
fh.write("**System Information**\n")
fh.write(
- "Operating system: {!s} {!s} Bits\n".format(
+ "Operating system: %s %d Bits\n" % (
platform.platform(),
struct.calcsize("P") * 8,
)
)
fh.write(
- "Graphics card: {!s} {!s} {!s}\n".format(
+ "Graphics card: %s %s %s\n" % (
bgl.glGetString(bgl.GL_RENDERER),
bgl.glGetString(bgl.GL_VENDOR),
bgl.glGetString(bgl.GL_VERSION),
@@ -48,7 +48,7 @@ def url_prefill_from_blender(addon_info=None):
"**Blender Version**\n"
)
fh.write(
- "Broken: version: {!s}, branch: {!s}, commit date: {!s} {!s}, hash: `rB{!s}`\n".format(
+ "Broken: version: %s, branch: %s, commit date: %s %s, hash: `rB%s`\n" % (
bpy.app.version_string,
bpy.app.build_branch.decode('utf-8', 'replace'),
bpy.app.build_commit_date.decode('utf-8', 'replace'),
diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py
index 8f8f42bcd46..4e226f80f79 100644
--- a/release/scripts/modules/bpy/ops.py
+++ b/release/scripts/modules/bpy/ops.py
@@ -123,7 +123,7 @@ class BPyOpsSubModOp:
# op_class = getattr(bpy.types, idname)
op_class = op_get_rna_type(idname)
descr = op_class.description
- return f"{sig}\n{descr}"
+ return "%s\n%s" % (sig, descr)
@staticmethod
def _parse_args(args):
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
index bfdf28e0db4..7f337677635 100644
--- a/release/scripts/modules/bpy/utils/previews.py
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -76,8 +76,7 @@ class ImagePreviewCollection(dict):
return
raise ResourceWarning(
- f"{self!r}: left open, remove with "
- "'bpy.utils.previews.remove()'"
+ "%r: left open, remove with 'bpy.utils.previews.remove()'" % self
)
self.close()
@@ -116,7 +115,9 @@ class ImagePreviewCollection(dict):
super().__delitem__(key)
def __repr__(self):
- return f"<{self.__class__.__name__:s} id={self._uuid:s}[{len(self):d}], {super()!r}>"
+ return "<%s id=%s[%d], %r>" % (
+ self.__class__.__name__, self._uuid, len(self), super()
+ )
def new():
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index 844daded570..6076bf00063 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -240,6 +240,9 @@ def draw_filtered(display_keymaps, filter_type, filter_text, layout):
"*": 'NUMPAD_ASTERIX',
"/": 'NUMPAD_SLASH',
'+': 'NUMPAD_PLUS',
+ "-": 'NUMPAD_MINUS',
+ ".": 'NUMPAD_PERIOD',
+ "'": 'QUOTE',
"RMB": 'RIGHTMOUSE',
"LMB": 'LEFTMOUSE',
"MMB": 'MIDDLEMOUSE',
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 8dda8c90f85..662c1d908fc 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -130,7 +130,7 @@ def rna_idprop_ui_prop_default_set(item, prop, value):
try:
prop_type, is_array = rna_idprop_value_item_type(item[prop])
- if prop_type in {int, float}:
+ if prop_type in {int, float, str}:
if is_array and isinstance(value, ARRAY_TYPES):
value = [prop_type(item) for item in value]
if any(value):
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index bbbe520441c..57b31175728 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -695,9 +695,12 @@ def km_user_interface(_params):
("ui.copy_data_path_button", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True},
{"properties": [("full_path", True)]}),
# Keyframes and drivers
- ("anim.keyframe_insert_button", {"type": 'I', "value": 'PRESS'}, None),
- ("anim.keyframe_delete_button", {"type": 'I', "value": 'PRESS', "alt": True}, None),
- ("anim.keyframe_clear_button", {"type": 'I', "value": 'PRESS', "shift": True, "alt": True}, None),
+ ("anim.keyframe_insert_button", {"type": 'I', "value": 'PRESS'},
+ {"properties": [("all", True)]}),
+ ("anim.keyframe_delete_button", {"type": 'I', "value": 'PRESS', "alt": True},
+ {"properties": [("all", True)]}),
+ ("anim.keyframe_clear_button", {"type": 'I', "value": 'PRESS', "shift": True, "alt": True},
+ {"properties": [("all", True)]}),
("anim.driver_button_add", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("anim.driver_button_remove", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None),
("anim.keyingset_button_add", {"type": 'K', "value": 'PRESS'}, None),
@@ -725,6 +728,16 @@ def km_property_editor(_params):
{"properties": [("direction", 'PREV'), ], },),
("screen.space_context_cycle", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("direction", 'NEXT'), ], },),
+ # Modifier panels
+ ("object.modifier_remove", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}),
+ ("object.modifier_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),
+ ("object.modifier_copy", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("object.modifier_apply", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("report", True)]}),
+ # Grease pencil modifier panels
+ ("object.gpencil_modifier_remove", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}),
+ ("object.gpencil_modifier_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),
+ ("object.gpencil_modifier_copy", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("object.gpencil_modifier_apply", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("report", True)]}),
])
return keymap
@@ -1893,7 +1906,7 @@ def km_file_browser_main(params):
{"properties": [("open", False), ("deselect_all", not params.legacy)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
- {"properties": [("extend", True)]}),
+ {"properties": [("extend", True), ("open", False)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("fill", True), ("open", False)]}),
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'},
@@ -2464,7 +2477,7 @@ def km_sequencer(params):
{"properties": [("all", False)]}),
("sequencer.gap_remove", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True},
{"properties": [("all", True)]}),
- ("sequencer.gap_insert", {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True}, None),
+ ("sequencer.gap_insert", {"type": 'EQUAL', "value": 'PRESS', "shift": True}, None),
("sequencer.snap", {"type": 'S', "value": 'PRESS', "shift": True}, None),
("sequencer.swap_inputs", {"type": 'S', "value": 'PRESS', "alt": True}, None),
*(
@@ -2520,14 +2533,6 @@ def km_sequencer(params):
{"properties": [("side", 'LEFT')]}),
("sequencer.select_side_of_frame", {"type": 'RIGHT_BRACKET', "value": 'PRESS'},
{"properties": [("side", 'RIGHT')]}),
- ("sequencer.select_side_of_frame", {"type": 'EQUAL', "value": 'PRESS'},
- {"properties": [("side", 'OVERLAP')]}),
- ("sequencer.select_side_of_frame", {"type": 'LEFT_BRACKET', "value": 'PRESS', "shift": True},
- {"properties": [("side", 'LEFT'), ("extend", True)]}),
- ("sequencer.select_side_of_frame", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True},
- {"properties": [("side", 'RIGHT'), ("extend", True)]}),
- ("sequencer.select_side_of_frame", {"type": 'EQUAL', "value": 'PRESS', "shift": True},
- {"properties": [("side", 'OVERLAP'), ("extend", True)]}),
*_template_items_context_menu("SEQUENCER_MT_context_menu", params.context_menu_event),
])
@@ -4348,6 +4353,8 @@ def km_sculpt(params):
("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("object.voxel_size_edit", {"type": 'R', "value": 'PRESS', "shift": True}, None),
("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
+ # Color
+ ("sculpt.sample_color", {"type": 'S', "value": 'PRESS'}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
@@ -4370,7 +4377,7 @@ def km_sculpt(params):
# Tools
("paint.brush_select", {"type": 'X', "value": 'PRESS'},
{"properties": [("sculpt_tool", 'DRAW')]}),
- ("paint.brush_select", {"type": 'S', "value": 'PRESS'},
+ ("paint.brush_select", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("sculpt_tool", 'SMOOTH')]}),
("paint.brush_select", {"type": 'P', "value": 'PRESS'},
{"properties": [("sculpt_tool", 'PINCH')]}),
@@ -5184,7 +5191,7 @@ def km_bevel_modal_map(_params):
("MARK_SHARP_TOGGLE", {"type": 'K', "value": 'PRESS', "any": True}, None),
("OUTER_MITER_CHANGE", {"type": 'O', "value": 'PRESS', "any": True}, None),
("INNER_MITER_CHANGE", {"type": 'I', "value": 'PRESS', "any": True}, None),
- ("CUSTOM_PROFILE_TOGGLE", {"type": 'Z', "value": 'PRESS', "any": True}, None),
+ ("PROFILE_TYPE_CHANGE", {"type": 'Z', "value": 'PRESS', "any": True}, None),
("VERTEX_MESH_CHANGE", {"type": 'N', "value": 'PRESS', "any": True}, None),
])
@@ -5914,12 +5921,12 @@ def km_3d_view_tool_edit_mesh_extrude_region(params):
]},
)
-def km_3d_view_tool_edit_mesh_extrude_dissolve_and_intersect(params):
+def km_3d_view_tool_edit_mesh_extrude_manifold(params):
return (
- "3D View Tool: Edit Mesh, Extrude Dissolve and Intersect",
+ "3D View Tool: Edit Mesh, Extrude Manifold",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
- ("mesh.extrude_region_dissolve_move_intersect", {"type": params.tool_tweak, "value": 'ANY'},
+ ("mesh.extrude_manifold", {"type": params.tool_tweak, "value": 'ANY'},
{"properties": [
("MESH_OT_extrude_region", [("use_dissolve_ortho_edges", True)]),
("TRANSFORM_OT_translate", [
@@ -6215,9 +6222,9 @@ def km_3d_view_tool_edit_curve_extrude(params):
)
-def km_3d_view_tool_edit_curve_extrude_cursor(params):
+def km_3d_view_tool_edit_curve_extrude_to_cursor(params):
return (
- "3D View Tool: Edit Curve, Extrude Cursor",
+ "3D View Tool: Edit Curve, Extrude to Cursor",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("curve.vertex_add", {"type": params.tool_mouse, "value": 'PRESS'}, None),
@@ -6285,6 +6292,16 @@ def km_3d_view_tool_sculpt_cloth_filter(params):
]},
)
+def km_3d_view_tool_sculpt_color_filter(params):
+ return (
+ "3D View Tool: Sculpt, Color Filter",
+ {"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
+ {"items": [
+ ("sculpt.color_filter", {"type": params.tool_tweak, "value": 'ANY'},
+ None)
+ ]},
+ )
+
def km_3d_view_tool_paint_weight_sample_weight(params):
return (
"3D View Tool: Paint Weight, Sample Weight",
@@ -6792,7 +6809,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_edit_armature_extrude(params),
km_3d_view_tool_edit_armature_extrude_to_cursor(params),
km_3d_view_tool_edit_mesh_extrude_region(params),
- km_3d_view_tool_edit_mesh_extrude_dissolve_and_intersect(params),
+ km_3d_view_tool_edit_mesh_extrude_manifold(params),
km_3d_view_tool_edit_mesh_extrude_along_normals(params),
km_3d_view_tool_edit_mesh_extrude_individual(params),
km_3d_view_tool_edit_mesh_extrude_to_cursor(params),
@@ -6819,12 +6836,13 @@ def generate_keymaps(params=None):
km_3d_view_tool_edit_curve_tilt(params),
km_3d_view_tool_edit_curve_randomize(params),
km_3d_view_tool_edit_curve_extrude(params),
- km_3d_view_tool_edit_curve_extrude_cursor(params),
+ km_3d_view_tool_edit_curve_extrude_to_cursor(params),
km_3d_view_tool_sculpt_box_hide(params),
km_3d_view_tool_sculpt_box_mask(params),
km_3d_view_tool_sculpt_lasso_mask(params),
km_3d_view_tool_sculpt_mesh_filter(params),
km_3d_view_tool_sculpt_cloth_filter(params),
+ km_3d_view_tool_sculpt_color_filter(params),
km_3d_view_tool_paint_weight_sample_weight(params),
km_3d_view_tool_paint_weight_sample_vertex_group(params),
km_3d_view_tool_paint_weight_gradient(params),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 4cb6cefc960..f275d892abe 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -1246,7 +1246,7 @@ def km_file_browser_main(params):
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("open", False), ("deselect_all", True)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
- {"properties": [("extend", True)]}),
+ {"properties": [("extend", True), ("open", False)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True,},
{"properties": [("extend", True), ("fill", True), ("open", False)]}),
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True},
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index d7df29f1769..c39a7afcff9 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -49,6 +49,7 @@ _modules = [
"uvcalc_smart_project",
"vertexpaint_dirt",
"view3d",
+ "gpencil_mesh_bake",
"wm",
]
diff --git a/release/scripts/startup/bl_operators/gpencil_mesh_bake.py b/release/scripts/startup/bl_operators/gpencil_mesh_bake.py
new file mode 100644
index 00000000000..ae75fa0e4d9
--- /dev/null
+++ b/release/scripts/startup/bl_operators/gpencil_mesh_bake.py
@@ -0,0 +1,162 @@
+# ##### 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-80 compliant>
+
+import bpy
+from bpy.types import Operator
+from bpy.props import (
+ IntProperty,
+ FloatProperty,
+ BoolProperty,
+ EnumProperty,
+)
+
+gp_object_items = []
+
+
+def my_objlist_callback(scene, context):
+ gp_object_items.clear()
+ gp_object_items.append(('*NEW', "New Object", ""))
+ for o in context.scene.objects:
+ if o.type == 'GPENCIL':
+ gp_object_items.append((o.name, o.name, ""))
+
+ return gp_object_items
+
+
+class GPENCIL_OT_mesh_bake(Operator):
+ """Bake all mesh animation into grease pencil strokes"""
+ bl_idname = "gpencil.mesh_bake"
+ bl_label = "Bake Mesh to Grease Pencil"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ frame_start: IntProperty(
+ name="Start Frame",
+ description="Start frame for baking",
+ min=0, max=300000,
+ default=1,
+ )
+ frame_end: IntProperty(
+ name="End Frame",
+ description="End frame for baking",
+ min=1, max=300000,
+ default=250,
+ )
+ step: IntProperty(
+ name="Frame Step",
+ description="Frame Step",
+ min=1, max=120,
+ default=1,
+ )
+ thickness: IntProperty(
+ name="Thickness",
+ description="Thickness of the stroke lines",
+ min=1, max=100,
+ default=1,
+ )
+ angle: FloatProperty(
+ name="Threshold Angle",
+ description="Threshold to determine ends of the strokes",
+ min=0,
+ max=+3.141592,
+ default=+1.22173, # 70 Degress
+ subtype='ANGLE',
+ )
+ offset: FloatProperty(
+ name="Stroke Offset",
+ description="Offset strokes from fill",
+ soft_min=0.0, soft_max=100.0,
+ min=0.0, max=100.0,
+ default=0.001,
+ precision=3,
+ step=1,
+ subtype='DISTANCE',
+ unit='LENGTH',
+ )
+ seams: BoolProperty(
+ name="Only Seam Edges",
+ description="Convert only seam edges",
+ default=False,
+ )
+ faces: BoolProperty(
+ name="Export Faces",
+ description="Export faces as filled strokes",
+ default=True,
+ )
+ target: EnumProperty(
+ name="Target Object",
+ description="Grease Pencil Object",
+ items=my_objlist_callback
+ )
+ frame_target: IntProperty(
+ name="Target Frame",
+ description="Destination frame for the baked animation",
+ min=1, max=300000,
+ default=1,
+ )
+ project_type: EnumProperty(
+ name="Reproject Type",
+ description="Type of projection",
+ items=(
+ ("KEEP", "No Reproject", ""),
+ ("FRONT", "Front", "Reproject the strokes using the X-Z plane"),
+ ("SIDE", "Side", "Reproject the strokes using the Y-Z plane"),
+ ("TOP", "Top", "Reproject the strokes using the X-Y plane"),
+ ("VIEW", "View", "Reproject the strokes to current viewpoint"),
+ ("CURSOR", "Cursor", "Reproject the strokes using the orientation of 3D cursor")
+ )
+ )
+
+ @classmethod
+ def poll(self, context):
+ ob = context.active_object
+ return ((ob is not None) and
+ (ob.type in {'EMPTY', 'MESH'}) and
+ (context.mode == 'OBJECT'))
+
+ def execute(self, context):
+ bpy.ops.gpencil.bake_mesh_animation(
+ frame_start=self.frame_start,
+ frame_end=self.frame_end,
+ step=self.step,
+ angle=self.angle,
+ thickness=self.thickness,
+ seams=self.seams,
+ faces=self.faces,
+ offset=self.offset,
+ target=self.target,
+ frame_target=self.frame_target,
+ project_type=self.project_type
+ )
+
+ return {'FINISHED'}
+
+ def invoke(self, context, _event):
+ scene = context.scene
+ self.frame_start = scene.frame_start
+ self.frame_end = scene.frame_end
+ self.frame_target = scene.frame_start
+
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self)
+
+
+classes = (
+ GPENCIL_OT_mesh_bake,
+)
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 9fdaebc7540..1c5ebb4fa17 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -94,9 +94,16 @@ class NodeAddOperator:
for setting in self.settings:
# XXX catch exceptions here?
value = eval(setting.value)
+ node_data = node
+ node_attr_name = setting.name
+
+ # Support path to nested data.
+ if '.' in node_attr_name:
+ node_data_path, node_attr_name = node_attr_name.rsplit(".", 1)
+ node_data = node.path_resolve(node_data_path)
try:
- setattr(node, setting.name, value)
+ setattr(node_data, node_attr_name, value)
except AttributeError as e:
self.report(
{'ERROR_INVALID_INPUT'},
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index 09a98100796..cf91cd3c961 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -194,7 +194,7 @@ class SelectHierarchy(Operator):
for obj in selected_objects:
parent = obj.parent
- if parent:
+ if parent and parent.visible_get():
if obj_act == obj:
act_new = parent
@@ -202,12 +202,13 @@ class SelectHierarchy(Operator):
else:
for obj in selected_objects:
- select_new.extend(obj.children)
+ select_new.extend([child for child in obj.children if child.visible_get()])
if select_new:
select_new.sort(key=lambda obj_iter: obj_iter.name)
act_new = select_new[0]
+
# don't edit any object settings above this
if select_new:
if not self.extend:
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 71153ba8b74..311631ac65f 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -399,8 +399,8 @@ class QuickSmoke(ObjectModeOperator, Operator):
if self.style == 'FIRE' or self.style == 'BOTH':
obj.modifiers[-1].domain_settings.use_noise = True
- # set correct cache file format for smoke
- obj.modifiers[-1].domain_settings.cache_data_format = 'UNI'
+ # ensure correct cache file format for smoke
+ obj.modifiers[-1].domain_settings.cache_data_format = 'OPENVDB'
# Setup material
@@ -514,7 +514,8 @@ class QuickLiquid(Operator):
obj.modifiers[-1].domain_settings.use_collision_border_top = True
obj.modifiers[-1].domain_settings.use_collision_border_bottom = True
- # set correct cache file format for liquid
+ # ensure correct cache file formats for liquid
+ obj.modifiers[-1].domain_settings.cache_data_format = 'OPENVDB'
obj.modifiers[-1].domain_settings.cache_mesh_format = 'BOBJECT'
# change domain type, will also allocate and show particle system for FLIP
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index c83d0b9f4d8..2ea93a1aee9 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -80,7 +80,8 @@ class AddPresetBase:
name = name.lower().strip()
name = bpy.path.display_name_to_filepath(name)
trans = maketrans_init()
- return name.translate(trans)
+ # Strip surrounding "_" as they are displayed as spaces.
+ return name.translate(trans).strip("_")
def execute(self, context):
import os
@@ -92,15 +93,16 @@ class AddPresetBase:
preset_menu_class = getattr(bpy.types, self.preset_menu)
is_xml = getattr(preset_menu_class, "preset_type", None) == 'XML'
+ is_preset_add = not (self.remove_name or self.remove_active)
if is_xml:
ext = ".xml"
else:
ext = ".py"
- name = self.name.strip()
- if not (self.remove_name or self.remove_active):
+ name = self.name.strip() if is_preset_add else self.name
+ if is_preset_add:
if not name:
return {'FINISHED'}
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 3900fc3f2c2..255852d3b26 100644
--- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
+++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
@@ -32,25 +32,11 @@ def guess_player_path(preset):
if preset == 'INTERNAL':
return bpy.app.binary_path
- elif preset == 'BLENDER24':
- player_path = "blender"
-
- if sys.platform == "darwin":
- test_path = "/Applications/blender 2.49.app/Contents/MacOS/blender"
- elif sys.platform[:3] == "win":
- test_path = "/Program Files/Blender Foundation/Blender/blender.exe"
-
- if os.path.exists(test_path):
- player_path = test_path
elif preset == 'DJV':
- player_path = "djv_view"
-
+ player_path = "djv"
if sys.platform == "darwin":
- # TODO, crummy supporting only 1 version,
- # could find the newest installed version
- test_path = ("/Applications/djv-0.8.2.app"
- "/Contents/Resources/bin/djv_view")
+ test_path = "/Applications/DJV2.app/Contents/Resources/bin/djv"
if os.path.exists(test_path):
player_path = test_path
@@ -148,7 +134,13 @@ class PlayRenderedAnim(Operator):
]
cmd.extend(opts)
elif preset == 'DJV':
- opts = [file, "-playback_speed", str(int(fps_final))]
+ opts = [
+ file,
+ "-speed", str(fps_final),
+ "-in_out", str(frame_start), str(frame_end),
+ "-frame", str(scene.frame_current),
+ "-time_units", "Frames"
+ ]
cmd.extend(opts)
elif preset == 'FRAMECYCLER':
opts = [file, f"{scene.frame_start:d}-{scene.frame_end:d}"]
@@ -175,14 +167,8 @@ class PlayRenderedAnim(Operator):
# launch it
print("Executing command:\n ", " ".join(quote(c) for c in cmd))
- # workaround for boost 1.46, can be eventually removed. bug: [#32350]
- env_copy = os.environ.copy()
- if preset == 'INTERNAL':
- env_copy["LC_ALL"] = "C"
- # end workaround
-
try:
- subprocess.Popen(cmd, env=env_copy)
+ subprocess.Popen(cmd)
except Exception as e:
err_msg = tip_("Couldn't run external animation player with command %r\n%s") % (cmd, e)
self.report(
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index af071561232..9ffb23287f8 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -164,6 +164,7 @@ class SequencerFadesClear(Operator):
if curve:
fcurves.remove(curve)
setattr(sequence, animated_property, 1.0)
+ sequence.invalidate('COMPOSITE')
return {'FINISHED'}
@@ -184,8 +185,10 @@ class SequencerFadesAdd(Operator):
('IN_OUT', 'Fade In And Out', 'Fade selected strips in and out'),
('IN', 'Fade In', 'Fade in selected strips'),
('OUT', 'Fade Out', 'Fade out selected strips'),
- ('CURSOR_FROM', 'From Playhead', 'Fade from the time cursor to the end of overlapping sequences'),
- ('CURSOR_TO', 'To Playhead', 'Fade from the start of sequences under the time cursor to the current frame'),
+ ('CURSOR_FROM', 'From Current Frame',
+ 'Fade from the time cursor to the end of overlapping sequences'),
+ ('CURSOR_TO', 'To Current Frame',
+ 'Fade from the start of sequences under the time cursor to the current frame'),
),
name="Fade type",
description="Fade in, out, both in and out, to, or from the current frame. Default is both in and out",
@@ -230,9 +233,10 @@ class SequencerFadesAdd(Operator):
self.fade_animation_clear(fade_fcurve, fades)
self.fade_animation_create(fade_fcurve, fades)
faded_sequences.append(sequence)
+ sequence.invalidate('COMPOSITE')
sequence_string = "sequence" if len(faded_sequences) == 1 else "sequences"
- self.report({'INFO'}, "Added fade animation to {} {}.".format(len(faded_sequences), sequence_string))
+ self.report({'INFO'}, "Added fade animation to %d %s." % (len(faded_sequences), sequence_string))
return {'FINISHED'}
def calculate_fade_duration(self, context, sequence):
@@ -360,7 +364,7 @@ class Fade:
return max_value if max_value > 0.0 else 1.0
def __repr__(self):
- return "Fade {}: {} to {}".format(self.type, self.start, self.end)
+ return "Fade %r: %r to %r" % (self.type, self.start, self.end)
def calculate_duration_frames(context, duration_seconds):
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 7024582ad30..62ef3cb34b5 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -32,7 +32,7 @@ def get_vcolor_layer_data(me):
return lay.data
-def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only):
+def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only, normalize):
from mathutils import Vector
from math import acos
import array
@@ -74,14 +74,14 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
tot_con = len(con[i])
if tot_con == 0:
- continue
+ ang = pi / 2.0 # assume 90°, i. e. flat
+ else:
+ vec /= tot_con
- vec /= tot_con
-
- # angle is the acos() of the dot product between normal and connected verts.
- # > 90 degrees: convex
- # < 90 degrees: concave
- ang = acos(no.dot(vec))
+ # angle is the acos() of the dot product between normal and connected verts.
+ # > 90 degrees: convex
+ # < 90 degrees: concave
+ ang = acos(no.dot(vec))
# enforce min/max
ang = max(clamp_dirt, ang)
@@ -104,8 +104,12 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
vert_tone[j] /= len(c) * blur_strength + 1
del orig_vert_tone
- min_tone = min(vert_tone)
- max_tone = max(vert_tone)
+ if normalize:
+ min_tone = min(vert_tone)
+ max_tone = max(vert_tone)
+ else:
+ min_tone = clamp_dirt
+ max_tone = clamp_clean
tone_range = max_tone - min_tone
@@ -181,6 +185,11 @@ class VertexPaintDirt(Operator):
description="Don't calculate cleans for convex areas",
default=False,
)
+ normalize: BoolProperty(
+ name="Normalize",
+ description="Normalize the colors, increasing the contrast",
+ default=True,
+ )
@classmethod
def poll(cls, context):
@@ -198,6 +207,7 @@ class VertexPaintDirt(Operator):
self.dirt_angle,
self.clean_angle,
self.dirt_only,
+ self.normalize,
)
return ret
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index 88fa06a913f..a8e04eb2f24 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -98,7 +98,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
TRANSFORM_OT_shrink_fatten={},
)
elif dissolve_and_intersect:
- bpy.ops.mesh.extrude_region_dissolve_move_intersect(
+ bpy.ops.mesh.extrude_manifold(
'INVOKE_REGION_WIN',
MESH_OT_extrude_region={
"use_dissolve_ortho_edges": True,
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 4c4736cd669..a543ea6685c 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1457,7 +1457,7 @@ class WM_OT_properties_edit(Operator):
proptype, is_array = rna_idprop_value_item_type(value)
row = layout.row()
- row.enabled = proptype in {int, float}
+ row.enabled = proptype in {int, float, str}
row.prop(self, "default")
row = layout.row(align=True)
@@ -1697,7 +1697,7 @@ class WM_OT_tool_set_by_id(Operator):
tool_settings.workspace_tool_type = 'FALLBACK'
return {'FINISHED'}
else:
- self.report({'WARNING'}, f"Tool {self.name!r:s} not found for space {space_type!r:s}.")
+ self.report({'WARNING'}, "Tool %r not found for space %r." % (self.name, space_type))
return {'CANCELLED'}
@@ -2216,8 +2216,8 @@ class WM_OT_batch_rename(Operator):
elif ty == 'STRIP':
chars = action.strip_chars
chars_strip = (
- "{:s}{:s}{:s}"
- ).format(
+ "%s%s%s"
+ ) % (
string.punctuation if 'PUNCT' in chars else "",
string.digits if 'DIGIT' in chars else "",
" " if 'SPACE' in chars else "",
@@ -2282,7 +2282,7 @@ class WM_OT_batch_rename(Operator):
split.prop(self, "data_type", text="")
split = layout.split(factor=0.5)
- split.label(text="Rename {:d} {:s}:".format(len(self._data[0]), self._data[2]))
+ split.label(text="Rename %d %s:" % (len(self._data[0]), self._data[2]))
split.row().prop(self, "data_source", expand=True)
for action in self.actions:
@@ -2397,7 +2397,7 @@ class WM_OT_batch_rename(Operator):
change_len += 1
total_len += 1
- self.report({'INFO'}, "Renamed {:d} of {:d} {:s}".format(change_len, total_len, descr))
+ self.report({'INFO'}, "Renamed %d of %d %s" % (change_len, total_len, descr))
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 3fc54ff6d12..8bae32775a9 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -20,894 +20,762 @@
from bpy.types import Panel
-class ConstraintButtonsPanel:
+class ObjectConstraintPanel(Panel):
+ bl_context = "constraint"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.object)
+
+
+class BoneConstraintPanel(Panel):
+ bl_context = "bone_constraint"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.pose_bone)
+
+
+class OBJECT_PT_constraints(ObjectConstraintPanel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
- bl_context = "constraint"
+ bl_label = "Object Constraints"
+ bl_options = {'HIDE_HEADER'}
- def draw_constraint(self, context, con):
+ def draw(self, context):
layout = self.layout
- box = layout.template_constraint(con)
+ layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
- if box:
- # match enum type to our functions, avoids a lookup table.
- getattr(self, con.type)(context, box, con)
+ layout.template_constraints(use_bone_constraints=False)
- if con.type in {'RIGID_BODY_JOINT', 'NULL'}:
- return
- if con.type in {'IK', 'SPLINE_IK'}:
- # constraint.disable_keep_transform doesn't work well
- # for these constraints.
- box.prop(con, "influence")
- else:
- row = box.row(align=True)
- row.prop(con, "influence")
- row.operator("constraint.disable_keep_transform", text="", icon='CANCEL')
+class BONE_PT_constraints(BoneConstraintPanel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_label = "Bone Constraints"
+ bl_options = {'HIDE_HEADER'}
- @staticmethod
- def space_template(layout, con, target=True, owner=True):
- if target or owner:
+ def draw(self, context):
+ layout = self.layout
- split = layout.split(factor=0.2)
+ layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
- split.label(text="Space:")
- row = split.row()
+ layout.template_constraints(use_bone_constraints=True)
- if target:
- row.prop(con, "target_space", text="")
- if target and owner:
- row.label(icon='ARROW_LEFTRIGHT')
+# Parent class for constraint panels, with templates and drawing methods
+# shared between the bone and object constraint panels
+class ConstraintButtonsPanel(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_label = ""
+ bl_options = {'INSTANCED', 'HEADER_LAYOUT_EXPAND', 'DRAW_BOX'}
+
+ @staticmethod
+ def draw_influence(layout, con):
+ layout.separator()
+ if con.type in {'IK', 'SPLINE_IK'}:
+ # constraint.disable_keep_transform doesn't work well
+ # for these constraints.
+ layout.prop(con, "influence")
+ else:
+ row = layout.row(align=True)
+ row.prop(con, "influence")
+ row.operator("constraint.disable_keep_transform", text="", icon='CANCEL')
+ @staticmethod
+ def space_template(layout, con, target=True, owner=True):
+ if target or owner:
+ layout.separator()
+ if target:
+ layout.prop(con, "target_space", text="Target")
if owner:
- row.prop(con, "owner_space", text="")
+ layout.prop(con, "owner_space", text="Owner")
@staticmethod
def target_template(layout, con, subtargets=True):
- layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
+ col = layout.column()
+ col.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
if con.target and subtargets:
if con.target.type == 'ARMATURE':
- layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
+ col.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
- if hasattr(con, "head_tail"):
- row = layout.row(align=True)
- row.label(text="Head/Tail:")
- row.prop(con, "head_tail", text="")
+ if con.subtarget and hasattr(con, "head_tail"):
+ row = col.row(align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "head_tail")
# XXX icon, and only when bone has segments?
- row.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER')
+ sub.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER')
+ row.prop_decorator(con, "head_tail")
elif con.target.type in {'MESH', 'LATTICE'}:
- layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
+ col.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
- @staticmethod
- def ik_template(layout, con):
- # only used for iTaSC
- layout.prop(con, "pole_target")
+ def get_constraint(self, context):
+ con = None
+ if context.pose_bone:
+ con = context.pose_bone.constraints[self.list_panel_index]
+ else:
+ con = context.object.constraints[self.list_panel_index]
+ self.layout.context_pointer_set("constraint", con)
+ return con
- if con.pole_target and con.pole_target.type == 'ARMATURE':
- layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+ def draw_header(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
- if con.pole_target:
- row = layout.row()
- row.label()
- row.prop(con, "pole_angle")
+ layout.template_constraint_header(con)
- split = layout.split(factor=0.33)
- col = split.column()
- col.prop(con, "use_tail")
- col.prop(con, "use_stretch")
+ # Drawing methods for specific constraints. (Shared by object and bone constraint panels)
- col = split.column()
- col.prop(con, "chain_count")
+ def draw_childof(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def CHILD_OF(self, _context, layout, con):
self.target_template(layout, con)
- split = layout.split()
-
- col = split.column()
- col.label(text="Location:")
- col.prop(con, "use_location_x", text="X")
- col.prop(con, "use_location_y", text="Y")
- col.prop(con, "use_location_z", text="Z")
-
- col = split.column()
- col.label(text="Rotation:")
- col.prop(con, "use_rotation_x", text="X")
- col.prop(con, "use_rotation_y", text="Y")
- col.prop(con, "use_rotation_z", text="Z")
-
- col = split.column()
- col.label(text="Scale:")
- col.prop(con, "use_scale_x", text="X")
- col.prop(con, "use_scale_y", text="Y")
- col.prop(con, "use_scale_z", text="Z")
+ row = layout.row(heading="Location")
+ row.use_property_decorate = False
+ row.prop(con, "use_location_x", text="X", toggle=True)
+ row.prop(con, "use_location_y", text="Y", toggle=True)
+ row.prop(con, "use_location_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Rotation")
+ row.use_property_decorate = False
+ row.prop(con, "use_rotation_x", text="X", toggle=True)
+ row.prop(con, "use_rotation_y", text="Y", toggle=True)
+ row.prop(con, "use_rotation_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Scale")
+ row.use_property_decorate = False
+ row.prop(con, "use_scale_x", text="X", toggle=True)
+ row.prop(con, "use_scale_y", text="Y", toggle=True)
+ row.prop(con, "use_scale_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
row = layout.row()
row.operator("constraint.childof_set_inverse")
row.operator("constraint.childof_clear_inverse")
- def TRACK_TO(self, _context, layout, con):
- self.target_template(layout, con)
-
- row = layout.row()
- row.label(text="To:")
- row.prop(con, "track_axis", expand=True)
-
- row = layout.row()
- row.prop(con, "up_axis", text="Up")
- row.prop(con, "use_target_z")
-
- self.space_template(layout, con)
-
- def IK(self, context, layout, con):
- if context.object.pose.ik_solver == 'ITASC':
- layout.prop(con, "ik_type")
- getattr(self, 'IK_' + con.ik_type)(context, layout, con)
- else:
- # Standard IK constraint
- self.target_template(layout, con)
- layout.prop(con, "pole_target")
-
- if con.pole_target and con.pole_target.type == 'ARMATURE':
- layout.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
-
- if con.pole_target:
- row = layout.row()
- row.prop(con, "pole_angle")
- row.label()
-
- split = layout.split()
- col = split.column()
- col.prop(con, "iterations")
- col.prop(con, "chain_count")
-
- col = split.column()
- col.prop(con, "use_tail")
- col.prop(con, "use_stretch")
-
- layout.label(text="Weight:")
-
- split = layout.split()
- col = split.column()
- row = col.row(align=True)
- row.prop(con, "use_location", text="")
- sub = row.row(align=True)
- sub.active = con.use_location
- sub.prop(con, "weight", text="Position", slider=True)
-
- col = split.column()
- row = col.row(align=True)
- row.prop(con, "use_rotation", text="")
- sub = row.row(align=True)
- sub.active = con.use_rotation
- sub.prop(con, "orient_weight", text="Rotation", slider=True)
+ self.draw_influence(layout, con)
- def IK_COPY_POSE(self, _context, layout, con):
- self.target_template(layout, con)
- self.ik_template(layout, con)
+ def draw_trackto(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- row = layout.row()
- row.label(text="Axis Ref:")
- row.prop(con, "reference_axis", expand=True)
- split = layout.split(factor=0.33)
- split.row().prop(con, "use_location")
- row = split.row()
- row.prop(con, "weight", text="Weight", slider=True)
- row.active = con.use_location
- split = layout.split(factor=0.33)
- row = split.row()
- row.label(text="Lock:")
- row = split.row()
- row.prop(con, "lock_location_x", text="X")
- row.prop(con, "lock_location_y", text="Y")
- row.prop(con, "lock_location_z", text="Z")
- split.active = con.use_location
-
- split = layout.split(factor=0.33)
- split.row().prop(con, "use_rotation")
- row = split.row()
- row.prop(con, "orient_weight", text="Weight", slider=True)
- row.active = con.use_rotation
- split = layout.split(factor=0.33)
- row = split.row()
- row.label(text="Lock:")
- row = split.row()
- row.prop(con, "lock_rotation_x", text="X")
- row.prop(con, "lock_rotation_y", text="Y")
- row.prop(con, "lock_rotation_z", text="Z")
- split.active = con.use_rotation
-
- def IK_DISTANCE(self, _context, layout, con):
self.target_template(layout, con)
- self.ik_template(layout, con)
- layout.prop(con, "limit_mode")
+ layout.prop(con, "track_axis", expand=True)
+ layout.prop(con, "up_axis", text="Up", expand=True)
+ layout.prop(con, "use_target_z")
- row = layout.row()
- row.prop(con, "weight", text="Weight", slider=True)
- row.prop(con, "distance", text="Distance", slider=True)
+ self.space_template(layout, con)
- def FOLLOW_PATH(self, _context, layout, con):
- self.target_template(layout, con)
- layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
+ self.draw_influence(layout, con)
- split = layout.split()
+ def draw_follow_path(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- col = split.column()
- col.prop(con, "use_curve_follow")
- col.prop(con, "use_curve_radius")
+ self.target_template(layout, con)
- col = split.column()
- col.prop(con, "use_fixed_location")
if con.use_fixed_location:
- col.prop(con, "offset_factor", text="Offset")
+ layout.prop(con, "offset_factor", text="Offset Factor")
else:
- col.prop(con, "offset")
+ layout.prop(con, "offset")
- row = layout.row()
- row.label(text="Forward:")
- row.prop(con, "forward_axis", expand=True)
+ layout.prop(con, "forward_axis", expand=True)
+ layout.prop(con, "up_axis", expand=True)
- row = layout.row()
- row.prop(con, "up_axis", text="Up")
- row.label()
+ col = layout.column()
+ col.prop(con, "use_fixed_location")
+ col.prop(con, "use_curve_radius")
+ col.prop(con, "use_curve_follow")
- def LIMIT_ROTATION(self, _context, layout, con):
- split = layout.split()
+ layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
- col = split.column(align=True)
- col.prop(con, "use_limit_x")
- sub = col.column(align=True)
+ self.draw_influence(layout, con)
+
+ def draw_rot_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ # Decorators and property split are really buggy with these properties
+ row = layout.row(heading="Limit X", align=True)
+ row.use_property_decorate = False
+ row.prop(con, "use_limit_x", text="")
+ sub = row.column(align=True)
sub.active = con.use_limit_x
sub.prop(con, "min_x", text="Min")
sub.prop(con, "max_x", text="Max")
+ row.label(icon="BLANK1")
- col = split.column(align=True)
- col.prop(con, "use_limit_y")
- sub = col.column(align=True)
+ row = layout.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ row.prop(con, "use_limit_y", text="")
+ sub = row.column(align=True)
sub.active = con.use_limit_y
sub.prop(con, "min_y", text="Min")
sub.prop(con, "max_y", text="Max")
+ row.label(icon="BLANK1")
- col = split.column(align=True)
- col.prop(con, "use_limit_z")
- sub = col.column(align=True)
+ row = layout.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ row.prop(con, "use_limit_z", text="")
+ sub = row.column(align=True)
sub.active = con.use_limit_z
sub.prop(con, "min_z", text="Min")
sub.prop(con, "max_z", text="Max")
+ row.label(icon="BLANK1")
layout.prop(con, "use_transform_limit")
+ layout.prop(con, "owner_space")
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
-
- def LIMIT_LOCATION(self, _context, layout, con):
- split = layout.split()
-
- col = split.column()
- col.prop(con, "use_min_x")
- sub = col.column()
- sub.active = con.use_min_x
- sub.prop(con, "min_x", text="")
- col.prop(con, "use_max_x")
- sub = col.column()
- sub.active = con.use_max_x
- sub.prop(con, "max_x", text="")
-
- col = split.column()
- col.prop(con, "use_min_y")
- sub = col.column()
- sub.active = con.use_min_y
- sub.prop(con, "min_y", text="")
- col.prop(con, "use_max_y")
- sub = col.column()
- sub.active = con.use_max_y
- sub.prop(con, "max_y", text="")
-
- col = split.column()
- col.prop(con, "use_min_z")
- sub = col.column()
- sub.active = con.use_min_z
- sub.prop(con, "min_z", text="")
- col.prop(con, "use_max_z")
- sub = col.column()
- sub.active = con.use_max_z
- sub.prop(con, "max_z", text="")
+ self.draw_influence(layout, con)
- row = layout.row()
- row.prop(con, "use_transform_limit")
- row.label()
+ def draw_loc_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
-
- def LIMIT_SCALE(self, _context, layout, con):
- split = layout.split()
-
- col = split.column()
- col.prop(con, "use_min_x")
- sub = col.column()
- sub.active = con.use_min_x
- sub.prop(con, "min_x", text="")
- col.prop(con, "use_max_x")
- sub = col.column()
- sub.active = con.use_max_x
- sub.prop(con, "max_x", text="")
-
- col = split.column()
- col.prop(con, "use_min_y")
- sub = col.column()
- sub.active = con.use_min_y
- sub.prop(con, "min_y", text="")
- col.prop(con, "use_max_y")
- sub = col.column()
- sub.active = con.use_max_y
- sub.prop(con, "max_y", text="")
-
- col = split.column()
- col.prop(con, "use_min_z")
- sub = col.column()
- sub.active = con.use_min_z
- sub.prop(con, "min_z", text="")
- col.prop(con, "use_max_z")
- sub = col.column()
- sub.active = con.use_max_z
- sub.prop(con, "max_z", text="")
+ col = layout.column()
- row = layout.row()
- row.prop(con, "use_transform_limit")
- row.label()
+ row = col.row(heading="Minimum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_x
+ subsub.prop(con, "min_x", text="")
+ row.prop_decorator(con, "min_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_y
+ subsub.prop(con, "min_y", text="")
+ row.prop_decorator(con, "min_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_z
+ subsub.prop(con, "min_z", text="")
+ row.prop_decorator(con, "min_z")
+
+ col.separator()
+
+ row = col.row(heading="Maximum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_x
+ subsub.prop(con, "max_x", text="")
+ row.prop_decorator(con, "max_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_y
+ subsub.prop(con, "max_y", text="")
+ row.prop_decorator(con, "max_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_z
+ subsub.prop(con, "max_z", text="")
+ row.prop_decorator(con, "max_z")
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
+ layout.prop(con, "use_transform_limit")
+ layout.prop(con, "owner_space")
- def COPY_ROTATION(self, _context, layout, con):
- self.target_template(layout, con)
+ self.draw_influence(layout, con)
- layout.prop(con, "euler_order", text="Order")
+ def draw_size_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- split = layout.split()
+ col = layout.column()
- col = split.column()
- col.prop(con, "use_x", text="X")
- sub = col.column()
- sub.active = con.use_x
- sub.prop(con, "invert_x", text="Invert")
+ row = col.row(heading="Minimum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_x
+ subsub.prop(con, "min_x", text="")
+ row.prop_decorator(con, "min_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_y
+ subsub.prop(con, "min_y", text="")
+ row.prop_decorator(con, "min_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_min_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_min_z
+ subsub.prop(con, "min_z", text="")
+ row.prop_decorator(con, "min_z")
+
+ col.separator()
+
+ row = col.row(heading="Maximum X", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_x", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_x
+ subsub.prop(con, "max_x", text="")
+ row.prop_decorator(con, "max_x")
+
+ row = col.row(heading="Y", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_y", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_y
+ subsub.prop(con, "max_y", text="")
+ row.prop_decorator(con, "max_y")
+
+ row = col.row(heading="Z", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_max_z", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_max_z
+ subsub.prop(con, "max_z", text="")
+ row.prop_decorator(con, "max_z")
- col = split.column()
- col.prop(con, "use_y", text="Y")
- sub = col.column()
- sub.active = con.use_y
- sub.prop(con, "invert_y", text="Invert")
- col = split.column()
- col.prop(con, "use_z", text="Z")
- sub = col.column()
- sub.active = con.use_z
- sub.prop(con, "invert_z", text="Invert")
+ layout.prop(con, "use_transform_limit")
+ layout.prop(con, "owner_space")
- layout.prop(con, "mix_mode", text="Mix")
+ self.draw_influence(layout, con)
- self.space_template(layout, con)
+ def draw_rotate_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def COPY_LOCATION(self, _context, layout, con):
self.target_template(layout, con)
- split = layout.split()
+ layout.prop(con, "euler_order", text="Order")
- col = split.column()
- col.prop(con, "use_x", text="X")
- sub = col.column()
- sub.active = con.use_x
- sub.prop(con, "invert_x", text="Invert")
+ row = layout.row(heading="Axis", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_x", text="X", toggle=True)
+ sub.prop(con, "use_y", text="Y", toggle=True)
+ sub.prop(con, "use_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Invert", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "invert_x", text="X", toggle=True)
+ sub.prop(con, "invert_y", text="Y", toggle=True)
+ sub.prop(con, "invert_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
- col = split.column()
- col.prop(con, "use_y", text="Y")
- sub = col.column()
- sub.active = con.use_y
- sub.prop(con, "invert_y", text="Invert")
+ layout.prop(con, "mix_mode", text="Mix")
- col = split.column()
- col.prop(con, "use_z", text="Z")
- sub = col.column()
- sub.active = con.use_z
- sub.prop(con, "invert_z", text="Invert")
+ self.space_template(layout, con)
+
+ self.draw_influence(layout, con)
+
+ def draw_locate_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ self.target_template(layout, con)
+
+ row = layout.row(heading="Axis", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_x", text="X", toggle=True)
+ sub.prop(con, "use_y", text="Y", toggle=True)
+ sub.prop(con, "use_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ row = layout.row(heading="Invert", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "invert_x", text="X", toggle=True)
+ sub.prop(con, "invert_y", text="Y", toggle=True)
+ sub.prop(con, "invert_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
layout.prop(con, "use_offset")
self.space_template(layout, con)
- def COPY_SCALE(self, _context, layout, con):
+ self.draw_influence(layout, con)
+
+ def draw_size_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
self.target_template(layout, con)
- row = layout.row(align=True)
- row.prop(con, "use_x", text="X")
- row.prop(con, "use_y", text="Y")
- row.prop(con, "use_z", text="Z")
+ row = layout.row(heading="Axis", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_x", text="X", toggle=True)
+ sub.prop(con, "use_y", text="Y", toggle=True)
+ sub.prop(con, "use_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
- layout.prop(con, "power")
- layout.prop(con, "use_make_uniform")
+ col = layout.column()
+ col.prop(con, "power")
+ col.prop(con, "use_make_uniform")
- row = layout.row()
- row.prop(con, "use_offset")
- row = row.row()
+ col.prop(con, "use_offset")
+ row = col.row()
row.active = con.use_offset
row.prop(con, "use_add")
self.space_template(layout, con)
- def MAINTAIN_VOLUME(self, _context, layout, con):
+ self.draw_influence(layout, con)
+
+ def draw_same_volume(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
layout.prop(con, "mode")
- row = layout.row()
- row.label(text="Free:")
+ row = layout.row(heading="Free Axis")
row.prop(con, "free_axis", expand=True)
layout.prop(con, "volume")
- row = layout.row()
- row.label(text="Convert:")
- row.prop(con, "owner_space", text="")
-
- def COPY_TRANSFORMS(self, _context, layout, con):
- self.target_template(layout, con)
-
- layout.prop(con, "mix_mode", text="Mix")
+ layout.prop(con, "owner_space")
- self.space_template(layout, con)
+ self.draw_influence(layout, con)
- # def SCRIPT(self, context, layout, con):
+ def draw_trans_like(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def ACTION(self, _context, layout, con):
self.target_template(layout, con)
- split = layout.split()
-
- col = split.column()
- col.label(text="From Target:")
- col.prop(con, "transform_channel", text="")
- col.prop(con, "target_space", text="")
-
- col = split.column()
- col.label(text="To Action:")
- col.prop(con, "action", text="")
- col.prop(con, "use_bone_object_action")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.label(text="Target Range:")
- col.prop(con, "min", text="Min")
- col.prop(con, "max", text="Max")
-
- col = split.column(align=True)
- col.label(text="Action Range:")
- col.prop(con, "frame_start", text="Start")
- col.prop(con, "frame_end", text="End")
-
layout.prop(con, "mix_mode", text="Mix")
- def LOCKED_TRACK(self, _context, layout, con):
- self.target_template(layout, con)
+ self.space_template(layout, con)
- row = layout.row()
- row.label(text="To:")
- row.prop(con, "track_axis", expand=True)
+ self.draw_influence(layout, con)
- row = layout.row()
- row.label(text="Lock:")
- row.prop(con, "lock_axis", expand=True)
+ def draw_action(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def LIMIT_DISTANCE(self, _context, layout, con):
self.target_template(layout, con)
- col = layout.column(align=True)
- col.prop(con, "distance")
- col.operator("constraint.limitdistance_reset")
-
- row = layout.row()
- row.label(text="Clamp Region:")
- row.prop(con, "limit_mode", text="")
+ layout.prop(con, "mix_mode", text="Mix")
- row = layout.row()
- row.prop(con, "use_transform_limit")
- row.label()
+ self.draw_influence(layout, con)
- self.space_template(layout, con)
+ def draw_lock_track(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def STRETCH_TO(self, _context, layout, con):
self.target_template(layout, con)
- row = layout.row()
- row.prop(con, "rest_length", text="Rest Length")
- row.operator("constraint.stretchto_reset", text="Reset")
-
- layout.prop(con, "bulge", text="Volume Variation")
- split = layout.split()
- col = split.column(align=True)
- col.prop(con, "use_bulge_min", text="Volume Min")
- sub = col.column()
- sub.active = con.use_bulge_min
- sub.prop(con, "bulge_min", text="")
- col = split.column(align=True)
- col.prop(con, "use_bulge_max", text="Volume Max")
- sub = col.column()
- sub.active = con.use_bulge_max
- sub.prop(con, "bulge_max", text="")
- col = layout.column()
- col.active = con.use_bulge_min or con.use_bulge_max
- col.prop(con, "bulge_smooth", text="Smooth")
+ layout.prop(con, "track_axis", expand=True)
+ layout.prop(con, "lock_axis", expand=True)
- split = layout.split(factor=0.3)
- split.label(text="Volume:")
- row = split.row()
- row.prop(con, "volume", expand=True)
+ self.draw_influence(layout, con)
- split = layout.split(factor=0.3)
- split.label(text="Rotation:")
- row = split.row()
- row.prop(con, "keep_axis", expand=True)
+ def draw_dist_limit(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def FLOOR(self, _context, layout, con):
self.target_template(layout, con)
- layout.prop(con, "use_rotation")
- layout.prop(con, "offset")
-
row = layout.row()
- row.label(text="Min/Max:")
- row.prop(con, "floor_location", expand=True)
+ row.prop(con, "distance")
+ row.operator("constraint.limitdistance_reset", text="", icon="X")
- self.space_template(layout, con)
+ layout.prop(con, "limit_mode", text="Clamp Region")
- def RIGID_BODY_JOINT(self, _context, layout, con):
- self.target_template(layout, con, subtargets=False)
-
- layout.prop(con, "pivot_type")
- layout.prop(con, "child")
+ layout.prop(con, "use_transform_limit")
- row = layout.row()
- row.prop(con, "use_linked_collision", text="Linked Collision")
- row.prop(con, "show_pivot", text="Display Pivot")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.label(text="Pivot:")
- col.prop(con, "pivot_x", text="X")
- col.prop(con, "pivot_y", text="Y")
- col.prop(con, "pivot_z", text="Z")
-
- col = split.column(align=True)
- col.label(text="Axis:")
- col.prop(con, "axis_x", text="X")
- col.prop(con, "axis_y", text="Y")
- col.prop(con, "axis_z", text="Z")
-
- if con.pivot_type == 'CONE_TWIST':
- layout.label(text="Limits:")
- split = layout.split()
-
- col = split.column()
- col.prop(con, "use_angular_limit_x", text="Angle X")
- sub = col.column()
- sub.active = con.use_angular_limit_x
- sub.prop(con, "limit_angle_max_x", text="")
-
- col = split.column()
- col.prop(con, "use_angular_limit_y", text="Angle Y")
- sub = col.column()
- sub.active = con.use_angular_limit_y
- sub.prop(con, "limit_angle_max_y", text="")
-
- col = split.column()
- col.prop(con, "use_angular_limit_z", text="Angle Z")
- sub = col.column()
- sub.active = con.use_angular_limit_z
- sub.prop(con, "limit_angle_max_z", text="")
-
- elif con.pivot_type == 'GENERIC_6_DOF':
- layout.label(text="Limits:")
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(con, "use_limit_x", text="X")
- sub = col.column(align=True)
- sub.active = con.use_limit_x
- sub.prop(con, "limit_min_x", text="Min")
- sub.prop(con, "limit_max_x", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_limit_y", text="Y")
- sub = col.column(align=True)
- sub.active = con.use_limit_y
- sub.prop(con, "limit_min_y", text="Min")
- sub.prop(con, "limit_max_y", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_limit_z", text="Z")
- sub = col.column(align=True)
- sub.active = con.use_limit_z
- sub.prop(con, "limit_min_z", text="Min")
- sub.prop(con, "limit_max_z", text="Max")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(con, "use_angular_limit_x", text="Angle X")
- sub = col.column(align=True)
- sub.active = con.use_angular_limit_x
- sub.prop(con, "limit_angle_min_x", text="Min")
- sub.prop(con, "limit_angle_max_x", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_angular_limit_y", text="Angle Y")
- sub = col.column(align=True)
- sub.active = con.use_angular_limit_y
- sub.prop(con, "limit_angle_min_y", text="Min")
- sub.prop(con, "limit_angle_max_y", text="Max")
-
- col = split.column(align=True)
- col.prop(con, "use_angular_limit_z", text="Angle Z")
- sub = col.column(align=True)
- sub.active = con.use_angular_limit_z
- sub.prop(con, "limit_angle_min_z", text="Min")
- sub.prop(con, "limit_angle_max_z", text="Max")
-
- elif con.pivot_type == 'HINGE':
- layout.label(text="Limits:")
- split = layout.split()
+ self.space_template(layout, con)
- row = split.row(align=True)
- col = row.column()
- col.prop(con, "use_angular_limit_x", text="Angle X")
+ self.draw_influence(layout, con)
- col = row.column()
- col.active = con.use_angular_limit_x
- col.prop(con, "limit_angle_min_x", text="Min")
- col = row.column()
- col.active = con.use_angular_limit_x
- col.prop(con, "limit_angle_max_x", text="Max")
+ def draw_stretch_to(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def CLAMP_TO(self, _context, layout, con):
self.target_template(layout, con)
row = layout.row()
- row.label(text="Main Axis:")
- row.prop(con, "main_axis", expand=True)
-
- layout.prop(con, "use_cyclic")
-
- def TRANSFORM(self, _context, layout, con):
- self.target_template(layout, con)
+ row.prop(con, "rest_length")
+ row.operator("constraint.stretchto_reset", text="", icon="X")
- layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
+ layout.separator()
col = layout.column()
- col.row().label(text="Source:")
- col.row().prop(con, "map_from", expand=True)
-
- if con.map_from == 'ROTATION':
- layout.prop(con, "from_rotation_mode", text="Mode")
-
- split = layout.split()
- ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
+ col.prop(con, "bulge", text="Volume Variation")
+
+ row = col.row(heading="Volume Min", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_bulge_min", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_bulge_min
+ subsub.prop(con, "bulge_min", text="")
+ row.prop_decorator(con, "bulge_min")
+
+ row = col.row(heading="Max", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_bulge_max", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_bulge_max
+ subsub.prop(con, "bulge_max", text="")
+ row.prop_decorator(con, "bulge_max")
- sub = split.column(align=True)
- sub.label(text="X:")
- sub.prop(con, "from_min_x" + ext, text="Min")
- sub.prop(con, "from_max_x" + ext, text="Max")
+ row = col.row()
+ row.active = con.use_bulge_min or con.use_bulge_max
+ row.prop(con, "bulge_smooth", text="Smooth")
- sub = split.column(align=True)
- sub.label(text="Y:")
- sub.prop(con, "from_min_y" + ext, text="Min")
- sub.prop(con, "from_max_y" + ext, text="Max")
+ layout.prop(con, "volume", expand=True)
+ layout.prop(con, "keep_axis", text="Rotation", expand=True)
- sub = split.column(align=True)
- sub.label(text="Z:")
- sub.prop(con, "from_min_z" + ext, text="Min")
- sub.prop(con, "from_max_z" + ext, text="Max")
+ self.draw_influence(layout, con)
- col = layout.column()
- row = col.row()
- row.label(text="Source to Destination Mapping:")
+ def draw_min_max(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- # note: chr(187) is the ASCII arrow ( >> ). Blender Text Editor can't
- # open it. Thus we are using the hard-coded value instead.
- row = col.row()
- row.prop(con, "map_to_x_from", expand=False, text="")
- row.label(text=" %s X" % chr(187))
+ self.target_template(layout, con)
- row = col.row()
- row.prop(con, "map_to_y_from", expand=False, text="")
- row.label(text=" %s Y" % chr(187))
+ layout.prop(con, "offset")
+ layout.prop(con, "floor_location", expand=True, text="Min/Max")
+ layout.prop(con, "use_rotation")
- row = col.row()
- row.prop(con, "map_to_z_from", expand=False, text="")
- row.label(text=" %s Z" % chr(187))
+ self.space_template(layout, con)
- split = layout.split()
+ self.draw_influence(layout, con)
- col = split.column()
- col.label(text="Destination:")
- col.row().prop(con, "map_to", expand=True)
+ def draw_clamp_to(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- if con.map_to == 'ROTATION':
- layout.prop(con, "to_euler_order", text="Order")
+ self.target_template(layout, con)
- split = layout.split()
- ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
+ layout.prop(con, "main_axis", expand=True)
- col = split.column()
- col.label(text="X:")
+ layout.prop(con, "use_cyclic")
- sub = col.column(align=True)
- sub.prop(con, "to_min_x" + ext, text="Min")
- sub.prop(con, "to_max_x" + ext, text="Max")
+ self.draw_influence(layout, con)
- col = split.column()
- col.label(text="Y:")
+ def draw_transform(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- sub = col.column(align=True)
- sub.prop(con, "to_min_y" + ext, text="Min")
- sub.prop(con, "to_max_y" + ext, text="Max")
+ self.target_template(layout, con)
- col = split.column()
- col.label(text="Z:")
+ layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
- sub = col.column(align=True)
- sub.prop(con, "to_min_z" + ext, text="Min")
- sub.prop(con, "to_max_z" + ext, text="Max")
+ self.space_template(layout, con)
- layout.prop(con, "mix_mode" + ext, text="Mix")
+ self.draw_influence(layout, con)
- self.space_template(layout, con)
+ def draw_shrinkwrap(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def SHRINKWRAP(self, _context, layout, con):
self.target_template(layout, con, False)
layout.prop(con, "distance")
- layout.prop(con, "shrinkwrap_type")
+ layout.prop(con, "shrinkwrap_type", text="Mode")
- if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
- layout.prop(con, "wrap_mode", text="Snap Mode")
+ layout.separator()
if con.shrinkwrap_type == 'PROJECT':
- row = layout.row(align=True)
- row.prop(con, "project_axis", expand=True)
- split = layout.split(factor=0.4)
- split.label(text="Axis Space:")
- rowsub = split.row()
- rowsub.prop(con, "project_axis_space", text="")
- split = layout.split(factor=0.4)
- split.label(text="Face Culling:")
- rowsub = split.row()
- rowsub.prop(con, "cull_face", expand=True)
- row = layout.row()
- row.prop(con, "use_project_opposite")
- rowsub = row.row()
- rowsub.active = con.use_project_opposite and con.cull_face != 'OFF'
- rowsub.prop(con, "use_invert_cull")
- layout.prop(con, "project_limit")
+ layout.prop(con, "project_axis", expand=True, text="Project Axis")
+ layout.prop(con, "project_axis_space", text="Space")
+ layout.prop(con, "project_limit", text="Distance")
+ layout.prop(con, "use_project_opposite")
- if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
- layout.prop(con, "use_track_normal")
+ layout.separator()
- row = layout.row(align=True)
- row.active = con.use_track_normal
- row.prop(con, "track_axis", expand=True)
+ col = layout.column()
+ row = col.row()
+ row.prop(con, "cull_face", expand=True)
+ row = col.row()
+ row.active = con.use_project_opposite and con.cull_face != 'OFF'
+ row.prop(con, "use_invert_cull")
- def DAMPED_TRACK(self, _context, layout, con):
- self.target_template(layout, con)
+ layout.separator()
- row = layout.row()
- row.label(text="To:")
- row.prop(con, "track_axis", expand=True)
+ if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
+ layout.prop(con, "wrap_mode", text="Snap Mode")
+ row = layout.row(heading="Align to Normal", align=True)
+ row.use_property_decorate = False
+ sub = row.row(align=True)
+ sub.prop(con, "use_track_normal", text="")
+ subsub = sub.row(align=True)
+ subsub.active = con.use_track_normal
+ subsub.prop(con, "track_axis", text="")
+ row.prop_decorator(con, "track_axis")
+
+ self.draw_influence(layout, con)
+
+ def draw_damp_track(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def SPLINE_IK(self, _context, layout, con):
self.target_template(layout, con)
- col = layout.column()
- col.label(text="Spline Fitting:")
- col.prop(con, "chain_count")
- col.prop(con, "use_even_divisions")
- col.prop(con, "use_chain_offset")
+ layout.prop(con, "track_axis", expand=True)
- col = layout.column()
- col.label(text="Chain Scaling:")
- col.prop(con, "use_curve_radius")
+ self.draw_influence(layout, con)
- layout.prop(con, "y_scale_mode")
- layout.prop(con, "xz_scale_mode")
+ def draw_spline_ik(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- if con.xz_scale_mode in {'INVERSE_PRESERVE', 'VOLUME_PRESERVE'}:
- layout.prop(con, "use_original_scale")
+ self.target_template(layout, con)
- if con.xz_scale_mode == 'VOLUME_PRESERVE':
- layout.prop(con, "bulge", text="Volume Variation")
- split = layout.split()
- col = split.column(align=True)
- col.prop(con, "use_bulge_min", text="Volume Min")
- sub = col.column()
- sub.active = con.use_bulge_min
- sub.prop(con, "bulge_min", text="")
- col = split.column(align=True)
- col.prop(con, "use_bulge_max", text="Volume Max")
- sub = col.column()
- sub.active = con.use_bulge_max
- sub.prop(con, "bulge_max", text="")
- col = layout.column()
- col.active = con.use_bulge_min or con.use_bulge_max
- col.prop(con, "bulge_smooth", text="Smooth")
+ self.draw_influence(layout, con)
+
+ def draw_pivot(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- def PIVOT(self, _context, layout, con):
self.target_template(layout, con)
if con.target:
- col = layout.column()
- col.prop(con, "offset", text="Pivot Offset")
+ layout.prop(con, "offset", text="Pivot Offset")
else:
- col = layout.column()
- col.prop(con, "use_relative_location")
+ layout.prop(con, "use_relative_location")
if con.use_relative_location:
- col.prop(con, "offset", text="Relative Pivot Point")
+ layout.prop(con, "offset", text="Pivot Point")
else:
- col.prop(con, "offset", text="Absolute Pivot Point")
+ layout.prop(con, "offset", text="Pivot Point")
col = layout.column()
- col.prop(con, "rotation_range", text="Pivot When")
+ col.prop(con, "rotation_range", text="Rotation Range")
- @staticmethod
- def _getConstraintClip(context, con):
- if not con.use_active_clip:
- return con.clip
+ self.draw_influence(layout, con)
+
+ def draw_follow_track(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ clip = None
+ if con.use_active_clip:
+ clip = context.scene.active_clip
else:
- return context.scene.active_clip
+ clip = con.clip
- def FOLLOW_TRACK(self, context, layout, con):
- clip = self._getConstraintClip(context, con)
+ layout.prop(con, "use_active_clip")
+ layout.prop(con, "use_3d_position")
row = layout.row()
- row.prop(con, "use_active_clip")
- row.prop(con, "use_3d_position")
-
- sub = row.column()
- sub.active = not con.use_3d_position
- sub.prop(con, "use_undistorted_position")
+ row.active = not con.use_3d_position
+ row.prop(con, "use_undistorted_position")
- col = layout.column()
if not con.use_active_clip:
- col.prop(con, "clip")
+ layout.prop(con, "clip")
- row = col.row()
- row.prop(con, "frame_method", expand=True)
+ layout.prop(con, "frame_method")
if clip:
tracking = clip.tracking
- col.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
+ layout.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
tracking_object = tracking.objects.get(con.object, tracking.objects[0])
- col.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
+ layout.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
- col.prop(con, "camera")
+ layout.prop(con, "camera")
- row = col.row()
+ row = layout.row()
row.active = not con.use_3d_position
row.prop(con, "depth_object")
layout.operator("clip.constraint_to_fcurve")
- def CAMERA_SOLVER(self, _context, layout, con):
+ self.draw_influence(layout, con)
+
+ def draw_camera_solver(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
layout.prop(con, "use_active_clip")
if not con.use_active_clip:
@@ -915,8 +783,19 @@ class ConstraintButtonsPanel:
layout.operator("clip.constraint_to_fcurve")
- def OBJECT_SOLVER(self, context, layout, con):
- clip = self._getConstraintClip(context, con)
+ self.draw_influence(layout, con)
+
+ def draw_object_solver(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ clip = None
+ if con.use_active_clip:
+ clip = context.scene.active_clip
+ else:
+ clip = con.clip
layout.prop(con, "use_active_clip")
@@ -934,36 +813,240 @@ class ConstraintButtonsPanel:
layout.operator("clip.constraint_to_fcurve")
- def TRANSFORM_CACHE(self, _context, layout, con):
- layout.label(text="Cache File Properties:")
- box = layout.box()
- box.template_cache_file(con, "cache_file")
+ self.draw_influence(layout, con)
- cache_file = con.cache_file
+ def draw_transform_cache(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ layout.template_cache_file(con, "cache_file")
- layout.label(text="Constraint Properties:")
- box = layout.box()
+ cache_file = con.cache_file
if cache_file is not None:
- box.prop_search(con, "object_path", cache_file, "object_paths")
+ layout.prop_search(con, "object_path", cache_file, "object_paths")
+
+ self.draw_influence(layout, con)
- def SCRIPT(self, _context, layout, _con):
+ def draw_python_constraint(self, context):
+ layout = self.layout
layout.label(text="Blender 2.6 doesn't support python constraints yet")
- def ARMATURE(self, context, layout, con):
- topcol = layout.column()
- topcol.use_property_split = True
- topcol.operator("constraint.add_target", text="Add Target Bone")
+ def draw_armature(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ col = layout.column()
+ col.prop(con, "use_deform_preserve_volume")
+ col.prop(con, "use_bone_envelopes")
+
+ if context.pose_bone:
+ col.prop(con, "use_current_location")
+
+ layout.operator("constraint.add_target", text="Add Target Bone")
+
+ layout.operator("constraint.normalize_target_weights")
+
+ self.draw_influence(layout, con)
if not con.targets:
- box = topcol.box()
- box.label(text="No target bones were added", icon='ERROR')
+ layout.label(text="No target bones added", icon='ERROR')
- for i, tgt in enumerate(con.targets):
- box = topcol.box()
+ def draw_kinematic(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ self.target_template(layout, con)
+
+ if context.object.pose.ik_solver == 'ITASC':
+ layout.prop(con, "ik_type")
+ # This button gives itself too much padding, so put it in a column with the subtarget
+ col = layout.column()
+ col.prop(con, "pole_target")
+
+ if con.pole_target and con.pole_target.type == 'ARMATURE':
+ col.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+
+ col = layout.column()
+ if con.pole_target:
+ col.prop(con, "pole_angle")
+ col.prop(con, "use_tail")
+ col.prop(con, "use_stretch")
+ col.prop(con, "chain_count")
+
+ if con.ik_type == 'COPY_POSE':
+ layout.prop(con, "reference_axis", expand=True)
+
+ # Use separate rows and columns here to avoid an alignment issue with the lock buttons
+ loc_col = layout.column()
+ loc_col.prop(con, "use_location")
+
+ row = loc_col.row()
+ row.active = con.use_location
+ row.prop(con, "weight", text="Weight", slider=True)
+
+ row = loc_col.row(heading="Lock", align=True)
+ row.use_property_decorate = False
+ row.active = con.use_location
+ sub = row.row(align=True)
+ sub.prop(con, "lock_location_x", text="X", toggle=True)
+ sub.prop(con, "lock_location_y", text="Y", toggle=True)
+ sub.prop(con, "lock_location_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ rot_col = layout.column()
+ rot_col.prop(con, "use_rotation")
+
+ row = rot_col.row()
+ row.active = con.use_rotation
+ row.prop(con, "orient_weight", text="Weight", slider=True)
+
+ row = rot_col.row(heading="Lock", align=True)
+ row.use_property_decorate = False
+ row.active = con.use_rotation
+ sub = row.row(align=True)
+ sub.prop(con, "lock_rotation_x", text="X", toggle=True)
+ sub.prop(con, "lock_rotation_y", text="Y", toggle=True)
+ sub.prop(con, "lock_rotation_z", text="Z", toggle=True)
+ row.label(icon='BLANK1')
+
+ elif con.ik_type == 'DISTANCE':
+ layout.prop(con, "limit_mode")
+
+ col = layout.column()
+ col.prop(con, "weight", text="Weight", slider=True)
+ col.prop(con, "distance", text="Distance", slider=True)
+ else:
+ # Standard IK constraint
+ col = layout.column()
+ col.prop(con, "pole_target")
+
+ if con.pole_target and con.pole_target.type == 'ARMATURE':
+ col.prop_search(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
+
+ col = layout.column()
+ if con.pole_target:
+ col.prop(con, "pole_angle")
+ col.prop(con, "iterations")
+ col.prop(con, "chain_count")
+ col.prop(con, "use_tail")
+ col.prop(con, "use_stretch")
+
+ col = layout.column()
+ row = col.row(align=True, heading="Weight Position")
+ row.prop(con, "use_location", text="")
+ sub = row.row(align=True)
+ sub.active = con.use_location
+ sub.prop(con, "weight", text="", slider=True)
+
+ row = col.row(align=True, heading="Rotation")
+ row.prop(con, "use_rotation", text="")
+ sub = row.row(align=True)
+ sub.active = con.use_rotation
+ sub.prop(con, "orient_weight", text="", slider=True)
+
+ self.draw_influence(layout, con)
+
+
+# Parent class for constraint subpanels
+class ConstraintButtonsSubPanel(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_label = ""
+ bl_options = {'DRAW_BOX'}
+
+ def get_constraint(self, context):
+ con = None
+ if context.pose_bone:
+ con = context.pose_bone.constraints[self.list_panel_index]
+ else:
+ con = context.object.constraints[self.list_panel_index]
+ self.layout.context_pointer_set("constraint", con)
+ return con
+
+ def draw_transform_source(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+
+ layout.prop(con, "map_from", expand=True)
+
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ if con.map_from == 'ROTATION':
+ layout.prop(con, "from_rotation_mode", text="Mode")
+
+ ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
+
+ col = layout.column(align=True)
+ col.prop(con, "from_min_x" + ext, text="X Min")
+ col.prop(con, "from_max_x" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "from_min_y" + ext, text="Y Min")
+ col.prop(con, "from_max_y" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "from_min_z" + ext, text="Z Min")
+ col.prop(con, "from_max_z" + ext, text="Max")
+
+ def draw_transform_mapping(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ layout.prop(con, "map_to_x_from", expand=False, text="Source Axis X")
+
+ layout.prop(con, "map_to_y_from", expand=False, text="Y")
+
+ layout.prop(con, "map_to_z_from", expand=False, text="Z")
+
+ def draw_transform_destination(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+
+ layout.prop(con, "map_to", expand=True)
+
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ if con.map_to == 'ROTATION':
+ layout.prop(con, "to_euler_order", text="Order")
+
+ ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
+
+ col = layout.column(align=True)
+ col.prop(con, "to_min_x" + ext, text="X Min")
+ col.prop(con, "to_max_x" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "to_min_y" + ext, text="Y Min")
+ col.prop(con, "to_max_y" + ext, text="Max")
+
+ col = layout.column(align=True)
+ col.prop(con, "to_min_z" + ext, text="Z Min")
+ col.prop(con, "to_max_z" + ext, text="Max")
+
+ layout.prop(con, "mix_mode" + ext, text="Mix")
+
+ def draw_armature_bones(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+
+ for i, tgt in enumerate(con.targets):
has_target = tgt.target is not None
+ box = layout.box()
header = box.row()
header.use_property_split = False
@@ -977,61 +1060,615 @@ class ConstraintButtonsPanel:
else:
row.prop(tgt, "subtarget", text="", icon='BONE_DATA')
- header.operator("constraint.remove_target", text="", icon='REMOVE').index = i
+ header.operator("constraint.remove_target", text="", icon='X').index = i
- col = box.column()
- col.active = has_target and tgt.subtarget != ""
- col.prop(tgt, "weight", slider=True)
+ row = box.row()
+ row.active = has_target and tgt.subtarget != ""
+ row.prop(tgt, "weight", slider=True, text="Weight")
- topcol.operator("constraint.normalize_target_weights")
- topcol.prop(con, "use_deform_preserve_volume")
- topcol.prop(con, "use_bone_envelopes")
+ def draw_spline_ik_fitting(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- if context.pose_bone:
- topcol.prop(con, "use_current_location")
+ col = layout.column()
+ col.prop(con, "chain_count")
+ col.prop(con, "use_even_divisions")
+ col.prop(con, "use_chain_offset")
+ def draw_spline_ik_chain_scaling(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
-class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
- bl_label = "Object Constraints"
- bl_context = "constraint"
- bl_options = {'HIDE_HEADER'}
+ layout.prop(con, "use_curve_radius")
- @classmethod
- def poll(cls, context):
- return (context.object)
+ layout.prop(con, "y_scale_mode")
+ layout.prop(con, "xz_scale_mode")
- def draw(self, context):
+ if con.xz_scale_mode in {'INVERSE_PRESERVE', 'VOLUME_PRESERVE'}:
+ layout.prop(con, "use_original_scale")
+
+ if con.xz_scale_mode == 'VOLUME_PRESERVE':
+ col = layout.column()
+ col.prop(con, "bulge", text="Volume Variation")
+
+ row = col.row(heading="Volume Min")
+ row.prop(con, "use_bulge_min", text="")
+ sub = row.row()
+ sub.active = con.use_bulge_min
+ sub.prop(con, "bulge_min", text="")
+
+ row = col.row(heading="Max")
+ row.prop(con, "use_bulge_max", text="")
+ sub = row.row()
+ sub.active = con.use_bulge_max
+ sub.prop(con, "bulge_max", text="")
+
+ row = layout.row()
+ row.active = con.use_bulge_min or con.use_bulge_max
+ row.prop(con, "bulge_smooth", text="Smooth")
+
+ def draw_action_target(self, context):
layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
- obj = context.object
+ layout.prop(con, "transform_channel", text="Channel")
+ layout.prop(con, "target_space")
- layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
+ col = layout.column(align=True)
+ col.prop(con, "min", text="Range Min")
+ col.prop(con, "max", text="Max")
- for con in obj.constraints:
- self.draw_constraint(context, con)
+ def draw_action_action(self, context):
+ layout = self.layout
+ con = self.get_constraint(context)
+ layout.use_property_split = True
+ layout.use_property_decorate = True
-class BONE_PT_constraints(ConstraintButtonsPanel, Panel):
- bl_label = "Bone Constraints"
- bl_context = "bone_constraint"
- bl_options = {'HIDE_HEADER'}
+ layout.prop(con, "action")
+ layout.prop(con, "use_bone_object_action")
+
+ col = layout.column(align=True)
+ col.prop(con, "frame_start", text="Frame Start")
+ col.prop(con, "frame_end", text="End")
- @classmethod
- def poll(cls, context):
- return (context.pose_bone)
+# Child Of Constraint
+
+class OBJECT_PT_bChildOfConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
def draw(self, context):
- layout = self.layout
+ self.draw_childof(context)
- layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
- for con in context.pose_bone.constraints:
- self.draw_constraint(context, con)
+class BONE_PT_bChildOfConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_childof(context)
+
+# Track To Constraint
+
+class OBJECT_PT_bTrackToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trackto(context)
+
+
+class BONE_PT_bTrackToConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trackto(context)
+
+# Follow Path Constraint
+
+class OBJECT_PT_bFollowPathConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_path(context)
+
+
+class BONE_PT_bFollowPathConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_path(context)
+
+
+# Rotation Limit Constraint
+
+class OBJECT_PT_bRotLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rot_limit(context)
+
+
+class BONE_PT_bRotLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rot_limit(context)
+
+
+# Location Limit Constraint
+
+class OBJECT_PT_bLocLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_loc_limit(context)
+
+
+class BONE_PT_bLocLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_loc_limit(context)
+
+
+# Size Limit Constraint
+
+class OBJECT_PT_bSizeLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_limit(context)
+
+
+class BONE_PT_bSizeLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_limit(context)
+
+
+# Rotate Like Constraint
+
+class OBJECT_PT_bRotateLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rotate_like(context)
+
+
+class BONE_PT_bRotateLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_rotate_like(context)
+
+
+# Locate Like Constraint
+
+class OBJECT_PT_bLocateLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_locate_like(context)
+
+
+class BONE_PT_bLocateLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_locate_like(context)
+
+
+# Size Like Constraint
+
+class OBJECT_PT_bSizeLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_like(context)
+
+
+class BONE_PT_bSizeLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_size_like(context)
+
+
+# Same Volume Constraint
+
+class OBJECT_PT_bSameVolumeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_same_volume(context)
+
+
+class BONE_PT_bSameVolumeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_same_volume(context)
+
+
+# Trans Like Constraint
+
+class OBJECT_PT_bTransLikeConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trans_like(context)
+
+
+class BONE_PT_bTransLikeConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_trans_like(context)
+
+
+# Action Constraint
+
+class OBJECT_PT_bActionConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_action(context)
+
+
+class BONE_PT_bActionConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_action(context)
+
+
+class OBJECT_PT_bActionConstraint_target(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bActionConstraint"
+ bl_label = "Target"
+
+ def draw(self, context):
+ self.draw_action_target(context)
+
+
+class BONE_PT_bActionConstraint_target(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bActionConstraint"
+ bl_label = "Target"
+
+ def draw(self, context):
+ self.draw_action_target(context)
+
+
+class OBJECT_PT_bActionConstraint_action(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bActionConstraint"
+ bl_label = "Action"
+
+ def draw(self, context):
+ self.draw_action_action(context)
+
+
+class BONE_PT_bActionConstraint_action(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bActionConstraint"
+ bl_label = "Action"
+
+ def draw(self, context):
+ self.draw_action_action(context)
+
+
+# Lock Track Constraint
+
+class OBJECT_PT_bLockTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_lock_track(context)
+
+
+class BONE_PT_bLockTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_lock_track(context)
+
+
+# Disance Limit Constraint
+
+class OBJECT_PT_bDistLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_dist_limit(context)
+
+
+class BONE_PT_bDistLimitConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_dist_limit(context)
+
+
+# Stretch To Constraint
+
+class OBJECT_PT_bStretchToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_stretch_to(context)
+
+
+class BONE_PT_bStretchToConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_stretch_to(context)
+
+
+# Min Max Constraint
+
+class OBJECT_PT_bMinMaxConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_min_max(context)
+
+
+class BONE_PT_bMinMaxConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_min_max(context)
+
+
+# Clamp To Constraint
+
+class OBJECT_PT_bClampToConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_clamp_to(context)
+
+
+class BONE_PT_bClampToConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_clamp_to(context)
+
+
+# Transform Constraint
+
+class OBJECT_PT_bTransformConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform(context)
+
+
+class BONE_PT_bTransformConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform(context)
+
+
+class OBJECT_PT_bTransformConstraint_source(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bTransformConstraint"
+ bl_label = "Source"
+
+ def draw(self, context):
+ self.draw_transform_source(context)
+
+
+class BONE_PT_bTransformConstraint_source(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bTransformConstraint"
+ bl_label = "Source"
+
+ def draw(self, context):
+ self.draw_transform_source(context)
+
+
+class OBJECT_PT_bTransformConstraint_mapping(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bTransformConstraint"
+ bl_label = "Mapping"
+
+ def draw(self, context):
+ self.draw_transform_mapping(context)
+
+
+class BONE_PT_bTransformConstraint_mapping(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bTransformConstraint"
+ bl_label = "Mapping"
+
+ def draw(self, context):
+ self.draw_transform_mapping(context)
+
+
+class OBJECT_PT_bTransformConstraint_destination(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bTransformConstraint"
+ bl_label = "Destination"
+
+ def draw(self, context):
+ self.draw_transform_destination(context)
+
+
+class BONE_PT_bTransformConstraint_destination(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bTransformConstraint"
+ bl_label = "Destination"
+
+ def draw(self, context):
+ self.draw_transform_destination(context)
+
+
+# Shrinkwrap Constraint
+
+class OBJECT_PT_bShrinkwrapConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_shrinkwrap(context)
+
+
+class BONE_PT_bShrinkwrapConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_shrinkwrap(context)
+
+
+# Damp Track Constraint
+
+class OBJECT_PT_bDampTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_damp_track(context)
+
+
+class BONE_PT_bDampTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_damp_track(context)
+
+
+# Spline IK Constraint
+
+class BONE_PT_bSplineIKConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_spline_ik(context)
+
+
+class BONE_PT_bSplineIKConstraint_fitting(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bSplineIKConstraint"
+ bl_label = "Fitting"
+
+ def draw(self, context):
+ self.draw_spline_ik_fitting(context)
+
+
+class BONE_PT_bSplineIKConstraint_chain_scaling(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bSplineIKConstraint"
+ bl_label = "Chain Scaling"
+
+ def draw(self, context):
+ self.draw_spline_ik_chain_scaling(context)
+
+
+# Pivot Constraint
+
+class OBJECT_PT_bPivotConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_pivot(context)
+
+
+class BONE_PT_bPivotConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_pivot(context)
+
+
+# Follow Track Constraint
+
+class OBJECT_PT_bFollowTrackConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_track(context)
+
+
+class BONE_PT_bFollowTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_follow_track(context)
+
+
+# Camera Solver Constraint
+
+class OBJECT_PT_bCameraSolverConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_camera_solver(context)
+
+
+class BONE_PT_bCameraSolverConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_camera_solver(context)
+
+
+# Object Solver Constraint
+
+class OBJECT_PT_bObjectSolverConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_object_solver(context)
+
+
+class BONE_PT_bObjectSolverConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_object_solver(context)
+
+
+# Transform Cache Constraint
+
+class OBJECT_PT_bTransformCacheConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform_cache(context)
+
+
+class BONE_PT_bTransformCacheConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_transform_cache(context)
+
+
+# Python Constraint
+
+class OBJECT_PT_bPythonConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_python_constraint(context)
+
+class BONE_PT_bPythonConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_python_constraint(context)
+
+
+
+# Armature Constraint
+
+class OBJECT_PT_bArmatureConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_armature(context)
+
+
+class BONE_PT_bArmatureConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_armature(context)
+
+
+class OBJECT_PT_bArmatureConstraint_bones(ObjectConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "OBJECT_PT_bArmatureConstraint"
+ bl_label = "Bones"
+
+ def draw(self, context):
+ self.draw_armature_bones(context)
+
+
+class BONE_PT_bArmatureConstraint_bones(BoneConstraintPanel, ConstraintButtonsSubPanel):
+ bl_parent_id = "BONE_PT_bArmatureConstraint"
+ bl_label = "Bones"
+
+ def draw(self, context):
+ self.draw_armature_bones(context)
+
+
+# Inverse Kinematic Constraint
+
+class OBJECT_PT_bKinematicConstraint(ObjectConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_kinematic(context)
+
+
+class BONE_PT_bKinematicConstraint(BoneConstraintPanel, ConstraintButtonsPanel):
+ def draw(self, context):
+ self.draw_kinematic(context)
+
classes = (
+ # Object Panels
OBJECT_PT_constraints,
BONE_PT_constraints,
+ OBJECT_PT_bChildOfConstraint,
+ OBJECT_PT_bTrackToConstraint,
+ OBJECT_PT_bKinematicConstraint,
+ OBJECT_PT_bFollowPathConstraint,
+ OBJECT_PT_bRotLimitConstraint,
+ OBJECT_PT_bLocLimitConstraint,
+ OBJECT_PT_bSizeLimitConstraint,
+ OBJECT_PT_bRotateLikeConstraint,
+ OBJECT_PT_bLocateLikeConstraint,
+ OBJECT_PT_bSizeLikeConstraint,
+ OBJECT_PT_bSameVolumeConstraint,
+ OBJECT_PT_bTransLikeConstraint,
+ OBJECT_PT_bActionConstraint,
+ OBJECT_PT_bActionConstraint_target,
+ OBJECT_PT_bActionConstraint_action,
+ OBJECT_PT_bLockTrackConstraint,
+ OBJECT_PT_bDistLimitConstraint,
+ OBJECT_PT_bStretchToConstraint,
+ OBJECT_PT_bMinMaxConstraint,
+ OBJECT_PT_bClampToConstraint,
+ OBJECT_PT_bTransformConstraint,
+ OBJECT_PT_bTransformConstraint_source,
+ OBJECT_PT_bTransformConstraint_mapping,
+ OBJECT_PT_bTransformConstraint_destination,
+ OBJECT_PT_bShrinkwrapConstraint,
+ OBJECT_PT_bDampTrackConstraint,
+ OBJECT_PT_bPivotConstraint,
+ OBJECT_PT_bFollowTrackConstraint,
+ OBJECT_PT_bCameraSolverConstraint,
+ OBJECT_PT_bObjectSolverConstraint,
+ OBJECT_PT_bTransformCacheConstraint,
+ OBJECT_PT_bPythonConstraint,
+ OBJECT_PT_bArmatureConstraint,
+ OBJECT_PT_bArmatureConstraint_bones,
+ # Bone panels
+ BONE_PT_bChildOfConstraint,
+ BONE_PT_bTrackToConstraint,
+ BONE_PT_bKinematicConstraint,
+ BONE_PT_bFollowPathConstraint,
+ BONE_PT_bRotLimitConstraint,
+ BONE_PT_bLocLimitConstraint,
+ BONE_PT_bSizeLimitConstraint,
+ BONE_PT_bRotateLikeConstraint,
+ BONE_PT_bLocateLikeConstraint,
+ BONE_PT_bSizeLikeConstraint,
+ BONE_PT_bSameVolumeConstraint,
+ BONE_PT_bTransLikeConstraint,
+ BONE_PT_bActionConstraint,
+ BONE_PT_bActionConstraint_target,
+ BONE_PT_bActionConstraint_action,
+ BONE_PT_bLockTrackConstraint,
+ BONE_PT_bDistLimitConstraint,
+ BONE_PT_bStretchToConstraint,
+ BONE_PT_bMinMaxConstraint,
+ BONE_PT_bClampToConstraint,
+ BONE_PT_bTransformConstraint,
+ BONE_PT_bTransformConstraint_source,
+ BONE_PT_bTransformConstraint_mapping,
+ BONE_PT_bTransformConstraint_destination,
+ BONE_PT_bShrinkwrapConstraint,
+ BONE_PT_bDampTrackConstraint,
+ BONE_PT_bSplineIKConstraint,
+ BONE_PT_bSplineIKConstraint_fitting,
+ BONE_PT_bSplineIKConstraint_chain_scaling,
+ BONE_PT_bPivotConstraint,
+ BONE_PT_bFollowTrackConstraint,
+ BONE_PT_bCameraSolverConstraint,
+ BONE_PT_bObjectSolverConstraint,
+ BONE_PT_bTransformCacheConstraint,
+ BONE_PT_bPythonConstraint,
+ BONE_PT_bArmatureConstraint,
+ BONE_PT_bArmatureConstraint_bones,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 62dffa3b6ba..3de144c5a15 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -84,7 +84,6 @@ class DATA_PT_lens(CameraButtonsPanel, Panel):
col.separator()
if cam.type == 'PERSP':
- col = layout.column()
if cam.lens_unit == 'MILLIMETERS':
col.prop(cam, "lens")
elif cam.lens_unit == 'FOV':
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index 4ed5264549f..946578937bb 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -214,10 +214,6 @@ class DATA_PT_gpencil_onion_skinning(DataButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
- layout.enabled = gpd.users <= 1
-
- if gpd.users > 1:
- layout.label(text="Multiuser datablock not supported", icon='ERROR')
col = layout.column()
col.prop(gpd, "onion_mode")
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 425c94dfdcd..fbd8e2d7cff 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -459,6 +459,31 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
col.operator("mesh.vertex_color_remove", icon='REMOVE', text="")
+class DATA_PT_sculpt_vertex_colors(MeshButtonsPanel, Panel):
+ bl_label = "Sculpt Vertex Colors"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ me = context.mesh
+
+ row = layout.row()
+ col = row.column()
+
+ col.template_list("MESH_UL_vcols", "svcols", me, "sculpt_vertex_colors", me.sculpt_vertex_colors, "active_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("mesh.sculpt_vertex_color_add", icon='ADD', text="")
+ col.operator("mesh.sculpt_vertex_color_remove", icon='REMOVE', text="")
+
+ row = layout.row()
+ col = row.column()
+ col.operator("sculpt.vertex_to_loop_colors", text="Store Sculpt Vertex Color")
+ col.operator("sculpt.loop_to_vertex_colors", text="Load Sculpt Vertex Color")
+
+
class DATA_PT_remesh(MeshButtonsPanel, Panel):
bl_label = "Remesh"
bl_options = {'DEFAULT_CLOSED'}
@@ -483,6 +508,8 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel):
col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
col.prop(mesh, "use_remesh_preserve_paint_mask", text="Paint Mask")
col.prop(mesh, "use_remesh_preserve_sculpt_face_sets", text="Face Sets")
+ col.prop(mesh, "use_remesh_preserve_vertex_colors", text="Vertex Colors")
+
col.operator("object.voxel_remesh", text="Voxel Remesh")
else:
col.operator("object.quadriflow_remesh", text="QuadriFlow Remesh")
@@ -537,6 +564,7 @@ classes = (
DATA_PT_shape_keys,
DATA_PT_uv_texture,
DATA_PT_vertex_colors,
+ DATA_PT_sculpt_vertex_colors,
DATA_PT_face_maps,
DATA_PT_normals,
DATA_PT_texture_space,
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index e7536838199..d464a3ffc6b 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -46,13 +46,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
bl_label = "Modifiers"
- def check_conflicts(self, layout, ob):
- for md in ob.grease_pencil_modifiers:
- if md.type == 'GP_TIME':
- row = layout.row()
- row.label(text="Build and Time Offset modifier not compatible", icon='ERROR')
- break
-
@classmethod
def poll(cls, context):
ob = context.object
@@ -60,483 +53,8 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
-
- ob = context.object
-
layout.operator_menu_enum("object.gpencil_modifier_add", "type")
-
- for md in ob.grease_pencil_modifiers:
- box = layout.template_greasepencil_modifier(md)
- if box:
- # match enum type to our functions, avoids a lookup table.
- getattr(self, md.type)(box, ob, md)
-
- # the mt.type enum is (ab)used for a lookup on function names
- # ...to avoid lengthy if statements
- # so each type must have a function here.
-
- def gpencil_masking(self, layout, ob, md, use_vertex, use_curve=False):
- gpd = ob.data
- layout.separator()
- layout.label(text="Influence Filters:")
-
- split = layout.split(factor=0.25)
-
- col1 = split.column()
-
- col1.label(text="Layer:")
- col1.label(text="Material:")
- if use_vertex:
- col1.label(text="Vertex Group:")
-
- col2 = split.column()
-
- split = col2.split(factor=0.6)
- row = split.row(align=True)
- row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
- row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
-
- row = split.row(align=True)
- row.prop(md, "layer_pass", text="Pass")
- row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
-
- split = col2.split(factor=0.6)
-
- row = split.row(align=True)
-
- valid = md.material in (slot.material for slot in ob.material_slots) or md.material is None
- if valid:
- icon = 'SHADING_TEXTURE'
- else:
- icon = 'ERROR'
-
- row.alert = not valid
- row.prop_search(md, "material", gpd, "materials", text="", icon=icon)
- row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
-
- row = split.row(align=True)
- row.prop(md, "pass_index", text="Pass")
- row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
-
- if use_vertex:
- row = col2.row(align=True)
- row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
- row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
-
- if use_curve:
- col = layout.column()
- col.separator()
- col.prop(md, "use_custom_curve")
- if md.use_custom_curve:
- col.template_curve_mapping(md, "curve")
-
- def GP_NOISE(self, layout, ob, md):
- split = layout.split()
-
- col = split.column()
- row = col.row(align=True)
- row.prop(md, "factor", text="Position")
- row = col.row(align=True)
- row.prop(md, "factor_strength", text="Strength")
- row = col.row(align=True)
- row.prop(md, "factor_thickness", text="Thickness")
- row = col.row(align=True)
- row.prop(md, "factor_uvs", text="UV")
-
- col.separator()
- row = col.row(align=True)
- row.prop(md, "random", text="", icon='TIME', toggle=True)
-
- subrow = row.row(align=True)
- subrow.enabled = md.random
- subrow.prop(md, "step")
- subrow.prop(md, "seed")
-
- col.separator()
- col.prop(md, "noise_scale")
-
- self.gpencil_masking(layout, ob, md, True, True)
-
- def GP_SMOOTH(self, layout, ob, md):
- col = layout.column()
- col.prop(md, "factor")
- col.prop(md, "step", text="Repeat")
-
- col.label(text="Affect:")
- row = col.row(align=True)
- row.prop(md, "use_edit_position", text="Position", toggle=True)
- row.prop(md, "use_edit_strength", text="Strength", toggle=True)
- row.prop(md, "use_edit_thickness", text="Thickness", toggle=True)
- row.prop(md, "use_edit_uv", text="UV", toggle=True)
-
- self.gpencil_masking(layout, ob, md, True, True)
-
- def GP_SUBDIV(self, layout, ob, md):
- layout.row().prop(md, "subdivision_type", expand=True)
- split = layout.split()
- col = split.column()
- row = col.row(align=True)
- row.prop(md, "level", text="Subdivisions")
-
- self.gpencil_masking(layout, ob, md, False)
-
- def GP_SIMPLIFY(self, layout, ob, md):
- gpd = ob.data
-
- row = layout.row()
- row.prop(md, "mode")
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Settings:")
-
- if md.mode == 'FIXED':
- col.prop(md, "step")
- elif md.mode == 'ADAPTIVE':
- col.prop(md, "factor")
- elif md.mode == 'SAMPLE':
- col.prop(md, "length")
- elif md.mode == 'MERGE':
- col.prop(md, "distance")
-
- self.gpencil_masking(layout, ob, md, False)
-
- def GP_THICK(self, layout, ob, md):
- col = layout.column()
-
- col.prop(md, "normalize_thickness")
-
- if md.normalize_thickness:
- col.prop(md, "thickness")
- else:
- col.prop(md, "thickness_factor")
-
- self.gpencil_masking(layout, ob, md, True, True)
-
- def GP_TEXTURE(self, layout, ob, md):
- col = layout.column()
-
- col.prop(md, "mode")
- if md.mode in {'STROKE', 'STROKE_AND_FILL'}:
- col.label(text="Stroke Texture:")
- col.prop(md, "fit_method")
- col.prop(md, "uv_offset")
- col.prop(md, "uv_scale")
-
- if md.mode == 'STROKE_AND_FILL':
- col.separator()
-
- if md.mode in {'FILL', 'STROKE_AND_FILL'}:
- col.label(text="Fill Texture:")
- col.prop(md, "fill_rotation", text="Rotation")
- col.prop(md, "fill_offset", text="Location")
- col.prop(md, "fill_scale", text="Scale")
-
- self.gpencil_masking(layout, ob, md, True)
-
- def GP_TINT(self, layout, ob, md):
- layout.row().prop(md, "tint_type", expand=True)
-
- if md.tint_type == 'UNIFORM':
- col = layout.column()
- col.prop(md, "color")
-
- col.separator()
- col.prop(md, "factor")
-
- if md.tint_type == 'GRADIENT':
- col = layout.column()
- col.label(text="Colors:")
- col.template_color_ramp(md, "colors")
-
- col.separator()
-
- col.label(text="Object:")
- col.prop(md, "object", text="")
-
- col.separator()
- row = col.row(align=True)
- row.prop(md, "radius")
- row.prop(md, "factor")
-
- col.separator()
- col.prop(md, "vertex_mode")
-
- self.gpencil_masking(layout, ob, md, True, True)
-
- def GP_TIME(self, layout, ob, md):
- gpd = ob.data
-
- row = layout.row()
- row.prop(md, "mode", text="Mode")
-
- row = layout.row()
- if md.mode == 'FIX':
- txt = "Frame"
- else:
- txt = "Frame Offset"
- row.prop(md, "offset", text=txt)
-
- row = layout.row()
- row.enabled = md.mode != 'FIX'
- row.prop(md, "frame_scale")
-
- row = layout.row()
- row.separator()
-
- row = layout.row()
- row.enabled = md.mode != 'FIX'
- row.prop(md, "use_custom_frame_range")
-
- row = layout.row(align=True)
- row.enabled = md.mode != 'FIX' and md.use_custom_frame_range is True
- row.prop(md, "frame_start")
- row.prop(md, "frame_end")
-
- row = layout.row()
- row.enabled = md.mode != 'FIX'
- row.prop(md, "use_keep_loop")
-
- row = layout.row()
- row.label(text="Layer:")
- row = layout.row(align=True)
- row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
- row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
-
- row = layout.row(align=True)
- row.prop(md, "layer_pass", text="Pass")
- row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
-
- def GP_COLOR(self, layout, ob, md):
- split = layout.split()
-
- col = split.column()
- col.label(text="Color:")
- col.prop(md, "hue", text="H", slider=True)
- col.prop(md, "saturation", text="S", slider=True)
- col.prop(md, "value", text="V", slider=True)
-
- row = layout.row()
- row.prop(md, "modify_color")
-
- self.gpencil_masking(layout, ob, md, False, True)
-
- def GP_OPACITY(self, layout, ob, md):
- split = layout.split()
-
- col = split.column()
- col.prop(md, "modify_color")
-
- if md.modify_color == 'HARDNESS':
- col.prop(md, "hardness")
- show = False
- else:
- col.prop(md, "normalize_opacity")
- if md.normalize_opacity is True:
- text="Strength"
- else:
- text="Opacity Factor"
-
- col.prop(md, "factor", text=text)
- show = True
- self.gpencil_masking(layout, ob, md, show, show)
-
- def GP_ARRAY(self, layout, ob, md):
- col = layout.column()
- col.prop(md, "count")
-
- split = layout.split()
- col = split.column()
- col.prop(md, "use_constant_offset", text="Constant Offset")
- subcol = col.column()
- subcol.enabled = md.use_constant_offset
- subcol.prop(md, "constant_offset", text="")
-
- col.prop(md, "use_object_offset")
- subcol = col.column()
- subcol.enabled = md.use_object_offset
- subcol.prop(md, "offset_object", text="")
-
- col = split.column()
- col.prop(md, "use_relative_offset", text="Relative Offset")
- subcol = col.column()
- subcol.enabled = md.use_relative_offset
- subcol.prop(md, "relative_offset", text="")
-
- split = layout.split()
- col = split.column()
- col.label(text="Random Offset:")
- col.prop(md, "random_offset", text="")
-
- col = split.column()
- col.label(text="Random Rotation:")
- col.prop(md, "random_rotation", text="")
-
- col = split.column()
- col.label(text="Random Scale:")
- col.prop(md, "random_scale", text="")
-
- col = layout.column()
- col.prop(md, "seed")
- col.separator()
- col.prop(md, "replace_material", text="Material Override")
-
- self.gpencil_masking(layout, ob, md, False)
-
- def GP_BUILD(self, layout, ob, md):
- gpd = ob.data
-
- split = layout.split()
-
- col = split.column()
- self.check_conflicts(col, ob)
-
- col.prop(md, "mode")
- if md.mode == 'CONCURRENT':
- col.prop(md, "concurrent_time_alignment")
-
- col.separator()
- col.prop(md, "transition")
- sub = col.column(align=True)
- sub.prop(md, "start_delay")
- sub.prop(md, "length")
-
- col = layout.column(align=True)
- col.prop(md, "use_restrict_frame_range")
- sub = col.column(align=True)
- sub.active = md.use_restrict_frame_range
- sub.prop(md, "frame_start", text="Start")
- sub.prop(md, "frame_end", text="End")
-
- col.prop(md, "use_percentage")
- sub = col.column(align=True)
- sub.active = md.use_percentage
- sub.prop(md, "percentage_factor")
-
- layout.label(text="Influence Filters:")
-
- split = layout.split(factor=0.25)
-
- col1 = split.column()
-
- col1.label(text="Layer:")
-
- col2 = split.column()
-
- split = col2.split(factor=0.6)
- row = split.row(align=True)
- row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
- row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
-
- row = split.row(align=True)
- row.prop(md, "layer_pass", text="Pass")
- row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
-
- def GP_LATTICE(self, layout, ob, md):
- split = layout.split()
-
- col = split.column()
- col.label(text="Object:")
- col.prop(md, "object", text="")
-
- layout.prop(md, "strength", slider=True)
-
- self.gpencil_masking(layout, ob, md, True)
-
- def GP_MIRROR(self, layout, ob, md):
- row = layout.row(align=True)
- row.prop(md, "x_axis")
- row.prop(md, "y_axis")
- row.prop(md, "z_axis")
-
- layout.label(text="Mirror Object:")
- layout.prop(md, "object", text="")
-
- self.gpencil_masking(layout, ob, md, False)
-
- def GP_HOOK(self, layout, ob, md):
- split = layout.split()
-
- col = split.column()
- col.label(text="Object:")
- col.prop(md, "object", text="")
- if md.object and md.object.type == 'ARMATURE':
- col.label(text="Bone:")
- col.prop_search(md, "subtarget", md.object.data, "bones", text="")
-
- use_falloff = (md.falloff_type != 'NONE')
-
- layout.separator()
-
- row = layout.row(align=True)
- if use_falloff:
- row.prop(md, "falloff_radius")
- row.prop(md, "strength", slider=True)
- layout.prop(md, "falloff_type")
-
- col = layout.column()
- if use_falloff:
- if md.falloff_type == 'CURVE':
- col.template_curve_mapping(md, "falloff_curve")
-
- split = layout.split()
-
- col = split.column()
- col.prop(md, "use_falloff_uniform")
-
- self.gpencil_masking(layout, ob, md, True)
-
- def GP_OFFSET(self, layout, ob, md):
- split = layout.split()
-
- split.column().prop(md, "location")
- split.column().prop(md, "rotation")
- split.column().prop(md, "scale")
-
- self.gpencil_masking(layout, ob, md, True)
-
- def GP_ARMATURE(self, layout, ob, md):
- split = layout.split()
-
- col = split.column()
- col.label(text="Object:")
- col.prop(md, "object", text="")
- # col.prop(md, "use_deform_preserve_volume")
-
- col = split.column()
- col.label(text="Bind To:")
- col.prop(md, "use_vertex_groups", text="Vertex Groups")
- col.prop(md, "use_bone_envelopes", text="Bone Envelopes")
-
- layout.separator()
-
- row = layout.row(align=True)
- row.label(text="Vertex Group:")
- row = layout.row(align=True)
- row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
- sub = row.row(align=True)
- sub.active = bool(md.vertex_group)
- sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
-
- def GP_MULTIPLY(self, layout, ob, md):
- col = layout.column()
-
- col.prop(md, "duplicates")
- subcol = col.column()
- subcol.enabled = md.duplicates > 0
- subcol.prop(md, "distance")
- subcol.prop(md, "offset", slider=True)
-
- subcol.separator()
-
- subcol.prop(md, "use_fade")
- if md.use_fade:
- subcol.prop(md, "fading_center")
- subcol.prop(md, "fading_thickness", slider=True)
- subcol.prop(md, "fading_opacity", slider=True)
-
- self.gpencil_masking(layout, ob, md, False)
+ layout.template_grease_pencil_modifiers()
classes = (
diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
index 1d4bf37b282..a96fef018c7 100644
--- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py
+++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
@@ -24,11 +24,11 @@ class ShaderFxButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "shaderfx"
- bl_options = {'HIDE_HEADER'}
class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
bl_label = "Effects"
+ bl_options = {'HIDE_HEADER'}
# Unused: always show for now.
@@ -39,122 +39,8 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
-
- ob = context.object
-
layout.operator_menu_enum("object.shaderfx_add", "type")
-
- for fx in ob.shader_effects:
- box = layout.template_shaderfx(fx)
- if box:
- # match enum type to our functions, avoids a lookup table.
- getattr(self, fx.type)(box, fx)
-
- # the mt.type enum is (ab)used for a lookup on function names
- # ...to avoid lengthy if statements
- # so each type must have a function here.
-
- def FX_BLUR(self, layout, fx):
-
- layout.prop(fx, "use_dof_mode", text="Use Depth of Field")
- layout.separator()
-
- col = layout.column()
- col.enabled = not fx.use_dof_mode
- col.prop(fx, "size", text="Size")
- col.separator()
- col.prop(fx, "rotation")
-
- layout.prop(fx, "samples", text="Samples")
-
-
- def FX_COLORIZE(self, layout, fx):
- layout.prop(fx, "mode", text="Mode")
-
- if fx.mode == 'DUOTONE':
- layout.prop(fx, "low_color", text="Low Color")
- if fx.mode == 'CUSTOM':
- layout.prop(fx, "low_color", text="Color")
-
- if fx.mode == 'DUOTONE':
- layout.prop(fx, "high_color", text="High Color")
-
- layout.prop(fx, "factor")
-
- def FX_WAVE(self, layout, fx):
- row = layout.row(align=True)
- row.prop(fx, "orientation", expand=True)
-
- layout.separator()
- layout.prop(fx, "amplitude")
- layout.prop(fx, "period")
- layout.prop(fx, "phase")
-
- def FX_PIXEL(self, layout, fx):
- layout.prop(fx, "size", text="Size")
-
- def FX_RIM(self, layout, fx):
- layout.prop(fx, "offset", text="Offset")
-
- layout.prop(fx, "rim_color")
- layout.prop(fx, "mask_color")
- layout.prop(fx, "mode", text="Blend")
- layout.prop(fx, "blur")
- layout.prop(fx, "samples")
-
- def FX_SHADOW(self, layout, fx):
- layout.prop(fx, "offset", text="Offset")
-
- layout.prop(fx, "shadow_color")
- layout.prop(fx, "scale")
- layout.prop(fx, "rotation")
-
- layout.separator()
- layout.prop(fx, "blur")
- layout.prop(fx, "samples")
-
- layout.separator()
- layout.prop(fx, "use_object", text="Use Object as Pivot")
- if fx.use_object:
- row = layout.row()
- row.prop(fx, "object", text="Object")
-
- layout.separator()
- layout.prop(fx, "use_wave", text="Use Wave Effect")
- if fx.use_wave is True:
- row = layout.row(align=True)
- row.prop(fx, "orientation", expand=True)
- layout.prop(fx, "amplitude")
- layout.prop(fx, "period")
- layout.prop(fx, "phase")
-
- def FX_GLOW(self, layout, fx):
- layout.prop(fx, "mode")
- if fx.mode == 'LUMINANCE':
- layout.prop(fx, "threshold")
- else:
- layout.prop(fx, "select_color")
-
- layout.prop(fx, "glow_color")
- layout.separator()
- layout.prop(fx, "blend_mode", text="Blend")
- layout.prop(fx, "opacity")
-
- layout.prop(fx, "size")
- layout.prop(fx, "rotation")
- layout.prop(fx, "samples")
-
- layout.prop(fx, "use_glow_under", text="Glow Under")
-
- def FX_SWIRL(self, layout, fx):
- layout.prop(fx, "object", text="Object")
-
- layout.prop(fx, "radius")
- layout.prop(fx, "angle")
-
- def FX_FLIP(self, layout, fx):
- layout.prop(fx, "flip_horizontal")
- layout.prop(fx, "flip_vertical")
+ layout.template_shaderfx()
classes = (
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index 5f0fd3374d2..69c557d336f 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -411,6 +411,8 @@ class RENDER_PT_encoding_audio(RenderOutputButtonsPanel, Panel):
layout.prop(ffmpeg, "audio_codec", text="Audio Codec")
if ffmpeg.audio_codec != 'NONE':
+ layout.prop(ffmpeg, "audio_channels")
+ layout.prop(ffmpeg, "audio_mixrate", text="Sample Rate")
layout.prop(ffmpeg, "audio_bitrate")
layout.prop(ffmpeg, "audio_volume", slider=True)
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 1612cce3c51..209231cacb0 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -607,6 +607,16 @@ def brush_settings(layout, context, brush, popover=False):
layout.operator("sculpt.set_persistent_base")
layout.separator()
+ if capabilities.has_color:
+ ups = context.scene.tool_settings.unified_paint_settings
+ row = layout.row(align=True)
+ UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="")
+ UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="")
+ row.separator()
+ row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False)
+ row.prop(ups, "use_unified_color", text="", icon='BRUSHES_ALL')
+ layout.prop(brush, "blend", text="Blend Mode")
+
if brush.sculpt_tool == 'CLAY_STRIPS':
row = layout.row()
row.prop(brush, "tip_roundness")
@@ -623,9 +633,13 @@ def brush_settings(layout, context, brush, popover=False):
layout.prop(brush, "pose_origin_type")
layout.prop(brush, "pose_offset")
layout.prop(brush, "pose_smooth_iterations")
- if brush.pose_deform_type == 'ROTATE_TWIST' and brush.pose_origin_type in ('TOPOLOGY','FACE_SETS'):
+ if brush.pose_deform_type == 'ROTATE_TWIST' and brush.pose_origin_type in {'TOPOLOGY', 'FACE_SETS'}:
layout.prop(brush, "pose_ik_segments")
layout.prop(brush, "use_pose_ik_anchored")
+ layout.prop(brush, "use_connected_only")
+ layout.prop(brush, "disconnected_distance_max")
+
+
layout.separator()
if brush.sculpt_tool == 'CLOTH':
@@ -655,6 +669,15 @@ def brush_settings(layout, context, brush, popover=False):
if brush.sculpt_tool == 'GRAB':
layout.prop(brush, "use_grab_active_vertex")
+ if brush.sculpt_tool == 'PAINT':
+ col = layout.column()
+ col.prop(brush, "flow")
+ col.prop(brush, "wet_mix")
+ col.prop(brush, "wet_persistence")
+ col.prop(brush, "density")
+ col.prop(brush, "tip_roundness")
+ col.prop(brush, "tip_scale_x")
+
if brush.sculpt_tool == 'MULTIPLANE_SCRAPE':
col = layout.column()
col.prop(brush, "multiplane_scrape_angle")
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 210d850ad06..db33fda3b17 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -330,6 +330,7 @@ def basic_force_field_settings_ui(self, field):
col.prop(field, "use_gravity_falloff", text="Gravitation")
col.prop(field, "use_absorption")
+ col.prop(field, "wind_factor")
def basic_force_field_falloff_ui(self, field):
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index 833cd05dd81..0bfa70b008b 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -210,10 +210,10 @@ class PHYSICS_PT_settings(PhysicButtonsPanel, Panel):
note.label(icon='INFO', text="Unbaked Guides: Bake Guides or disable them")
split = layout.split()
- split.enabled = note_flag
+ split.enabled = note_flag and ob.mode == 'OBJECT'
bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end)
- if domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete:
+ if domain.cache_resumable and domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete:
col = split.column()
col.operator("fluid.bake_data", text="Resume")
col = split.column()
@@ -705,6 +705,7 @@ class PHYSICS_PT_noise(PhysicButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
+ ob = context.object
domain = context.fluid.domain_settings
layout.active = domain.use_noise
@@ -736,7 +737,7 @@ class PHYSICS_PT_noise(PhysicButtonsPanel, Panel):
note.label(icon='INFO', text="Unbaked Data: Bake Data first")
split = layout.split()
- split.enabled = domain.has_cache_baked_data and note_flag
+ split.enabled = domain.has_cache_baked_data and note_flag and ob.mode == 'OBJECT'
bake_incomplete = (domain.cache_frame_pause_noise < domain.cache_frame_end)
if domain.has_cache_baked_noise and not domain.is_cache_baking_noise and bake_incomplete:
@@ -777,6 +778,7 @@ class PHYSICS_PT_mesh(PhysicButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
+ ob = context.object
domain = context.fluid.domain_settings
layout.active = domain.use_mesh
@@ -821,7 +823,7 @@ class PHYSICS_PT_mesh(PhysicButtonsPanel, Panel):
note.label(icon='INFO', text="Unbaked Data: Bake Data first")
split = layout.split()
- split.enabled = domain.has_cache_baked_data and note_flag
+ split.enabled = domain.has_cache_baked_data and note_flag and ob.mode == 'OBJECT'
bake_incomplete = (domain.cache_frame_pause_mesh < domain.cache_frame_end)
if domain.has_cache_baked_mesh and not domain.is_cache_baking_mesh and bake_incomplete:
@@ -855,6 +857,7 @@ class PHYSICS_PT_particles(PhysicButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
+ ob = context.object
domain = context.fluid.domain_settings
is_baking_any = domain.is_cache_baking_any
@@ -936,6 +939,7 @@ class PHYSICS_PT_particles(PhysicButtonsPanel, Panel):
split = layout.split()
split.enabled = (
note_flag and
+ ob.mode == 'OBJECT' and
domain.has_cache_baked_data and
(domain.use_spray_particles or
domain.use_bubble_particles or
@@ -1114,14 +1118,13 @@ class PHYSICS_PT_cache(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ ob = context.object
md = context.fluid
domain = context.fluid.domain_settings
is_baking_any = domain.is_cache_baking_any
has_baked_data = domain.has_cache_baked_data
- has_baked_noise = domain.has_cache_baked_noise
has_baked_mesh = domain.has_cache_baked_mesh
- has_baked_particles = domain.has_cache_baked_particles
col = layout.column()
col.prop(domain, "cache_directory", text="")
@@ -1146,35 +1149,33 @@ class PHYSICS_PT_cache(PhysicButtonsPanel, Panel):
col.separator()
col = flow.column()
+ col.enabled = not is_baking_any and not has_baked_data
+ col.prop(domain, "cache_resumable", text="Is Resumable")
+
row = col.row()
row.enabled = not is_baking_any and not has_baked_data
- row.prop(domain, "cache_data_format", text="Data File Format")
-
- if md.domain_settings.domain_type in {'GAS'}:
- if domain.use_noise:
- row = col.row()
- row.enabled = not is_baking_any and not has_baked_noise
- row.prop(domain, "cache_noise_format", text="Noise File Format")
+ row.prop(domain, "cache_data_format", text="Format Volumes")
- if md.domain_settings.domain_type in {'LIQUID'}:
- # File format for all particle systemes (FLIP and secondary)
+ if md.domain_settings.domain_type in {'LIQUID'} and domain.use_mesh:
row = col.row()
- row.enabled = not is_baking_any and not has_baked_particles and not has_baked_data
- row.prop(domain, "cache_particle_format", text="Particle File Format")
+ row.enabled = not is_baking_any and not has_baked_mesh
+ row.prop(domain, "cache_mesh_format", text="Meshes")
- if domain.use_mesh:
- row = col.row()
- row.enabled = not is_baking_any and not has_baked_mesh
- row.prop(domain, "cache_mesh_format", text="Mesh File Format")
-
- if domain.cache_type == 'FINAL':
+ if domain.cache_type == 'ALL':
col.separator()
split = layout.split()
+ split.enabled = ob.mode == 'OBJECT'
- if domain.is_cache_baking_data and not domain.has_cache_baked_data:
+ bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end)
+ if domain.cache_resumable and domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete:
+ col = split.column()
+ col.operator("fluid.bake_all", text="Resume")
+ col = split.column()
+ col.operator("fluid.free_all", text="Free")
+ elif domain.is_cache_baking_data and not domain.has_cache_baked_data:
split.enabled = False
- split.operator("fluid.pause_bake", text="Baking All - ESC to cancel")
+ split.operator("fluid.pause_bake", text="Baking All - ESC to pause")
elif not domain.has_cache_baked_data and not domain.is_cache_baking_data:
split.operator("fluid.bake_all", text="Bake All")
else:
@@ -1189,8 +1190,8 @@ class PHYSICS_PT_export(PhysicButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- # Only show the advanced panel to advanced users who know Mantaflow's birthday :)
- if not PhysicButtonsPanel.poll_fluid_domain(context) or bpy.app.debug_value != 3001:
+ domain = context.fluid.domain_settings
+ if not PhysicButtonsPanel.poll_fluid_domain(context) or (domain.cache_data_format != 'OPENVDB' and bpy.app.debug_value != 3001):
return False
return (context.engine in cls.COMPAT_ENGINES)
@@ -1203,12 +1204,24 @@ class PHYSICS_PT_export(PhysicButtonsPanel, Panel):
is_baking_any = domain.is_cache_baking_any
has_baked_any = domain.has_cache_baked_any
+ has_baked_data = domain.has_cache_baked_data
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
flow.enabled = not is_baking_any and not has_baked_any
col = flow.column()
- col.prop(domain, "export_manta_script", text="Export Mantaflow Script")
+
+ if domain.cache_data_format == 'OPENVDB':
+ col.enabled = not is_baking_any and not has_baked_data
+ col.prop(domain, "openvdb_cache_compress_type", text="Compression Volumes")
+
+ col = flow.column()
+ col.prop(domain, "openvdb_data_depth", text="Precision Volumes")
+
+ # Only show the advanced panel to advanced users who know Mantaflow's birthday :)
+ if bpy.app.debug_value == 3001:
+ col = flow.column()
+ col.prop(domain, "export_manta_script", text="Export Mantaflow Script")
class PHYSICS_PT_field_weights(PhysicButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 11b02cfb552..fcaa715cfd8 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -173,8 +173,10 @@ class RENDER_PT_eevee_motion_blur(RenderButtonsPanel, Panel):
layout.active = props.use_motion_blur
col = layout.column()
- col.prop(props, "motion_blur_samples")
col.prop(props, "motion_blur_shutter")
+ col.prop(props, "motion_blur_depth_scale")
+ col.prop(props, "motion_blur_max")
+ col.prop(props, "motion_blur_steps", text="Steps")
class RENDER_PT_eevee_depth_of_field(RenderButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 0b4ca2902c1..22f455fe5be 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -289,8 +289,6 @@ class SCENE_PT_audio(SceneButtonsPanel, Panel):
layout.use_property_split = True
scene = context.scene
- rd = context.scene.render
- ffmpeg = rd.ffmpeg
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
@@ -299,17 +297,8 @@ class SCENE_PT_audio(SceneButtonsPanel, Panel):
col.separator()
- col.prop(scene, "audio_distance_model")
- col.prop(ffmpeg, "audio_channels")
-
- col.separator()
-
- col = flow.column()
- col.prop(ffmpeg, "audio_mixrate", text="Sample Rate")
-
- col.separator()
-
col = col.column(align=True)
+ col.prop(scene, "audio_distance_model")
col.prop(scene, "audio_doppler_speed", text="Doppler Speed")
col.prop(scene, "audio_doppler_factor", text="Doppler Factor")
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index ee8015df273..aa4d0b94b7f 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -213,7 +213,7 @@ class OUTLINER_MT_collection(Menu):
layout.separator()
layout.operator("outliner.delete", text="Delete", icon='X')
- layout.operator("outliner.collection_hierarchy_delete")
+ layout.operator("outliner.delete", text="Delete Hierarchy").hierarchy = True
layout.separator()
@@ -279,9 +279,7 @@ class OUTLINER_MT_object(Menu):
layout.separator()
layout.operator("outliner.delete", text="Delete", icon='X')
-
- if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection:
- layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY'
+ layout.operator("outliner.delete", text="Delete Hierarchy").hierarchy = True
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index abe6f614f28..8dfa182f52d 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -474,7 +474,7 @@ class SEQUENCER_MT_navigation(Menu):
layout.separator()
- layout.operator("sequencer.view_frame", text="Go to Playhead")
+ layout.operator("sequencer.view_frame")
layout.separator()
@@ -635,7 +635,7 @@ class SEQUENCER_MT_strip_transform(Menu):
layout = self.layout
layout.operator("transform.seq_slide", text="Move")
- layout.operator("transform.transform", text="Move/Extend from Playhead").mode = 'TIME_EXTEND'
+ layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND'
layout.operator("sequencer.slip", text="Slip Strip Contents")
layout.separator()
@@ -731,7 +731,7 @@ class SEQUENCER_MT_strip(Menu):
layout.operator("sequencer.copy", text="Copy")
layout.operator("sequencer.paste", text="Paste")
layout.operator("sequencer.duplicate_move")
- layout.operator("sequencer.delete", text="Delete...")
+ layout.operator("sequencer.delete", text="Delete")
strip = act_strip(context)
@@ -1528,7 +1528,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
split.alignment = 'RIGHT'
split.label(text="End")
split = split.split(factor=0.8 + max_factor, align=True)
- split.label(text="{:>14}".format(smpte_from_frame(frame_final_end)))
+ split.label(text="%14s" % smpte_from_frame(frame_final_end))
split.alignment = 'RIGHT'
split.label(text=str(frame_final_end) + " ")
@@ -1569,10 +1569,10 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
split = col.split(factor=0.5 + max_factor, align=True)
split.alignment = 'RIGHT'
- split.label(text="Playhead")
+ split.label(text="Current Frame")
split = split.split(factor=0.8 + max_factor, align=True)
frame_display = frame_current - frame_final_start
- split.label(text="{:>14}".format(smpte_from_frame(frame_display)))
+ split.label(text="%14s" % smpte_from_frame(frame_display))
split.alignment = 'RIGHT'
split.label(text=str(frame_display) + " ")
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 553d79fb349..4f518d8e2d4 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -174,7 +174,10 @@ class TEXT_PT_find(Panel):
row = col.row(align=True)
row.prop(st, "replace_text", icon='DECORATE_OVERRIDE', text="")
row.operator("text.replace_set_selected", text="", icon='EYEDROPPER')
- col.operator("text.replace")
+
+ row = col.row(align=True)
+ row.operator("text.replace")
+ row.operator("text.replace", text = "Replace all").all = True
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 257e0c26a5d..1a9244a3051 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -243,8 +243,8 @@ class TIME_PT_playback(TimelinePanelButtons, Panel):
layout.prop(scene, "show_subframe", text="Subframes")
- layout.prop(scene, "lock_frame_selection_to_range", text="Limit Playhead to Frame Range")
- layout.prop(screen, "use_follow", text="Follow Playhead")
+ layout.prop(scene, "lock_frame_selection_to_range", text="Limit Playback to Frame Range")
+ layout.prop(screen, "use_follow", text="Follow Current Frame")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index e0651dcac2b..080e66b59e7 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -36,7 +36,7 @@ __all__ = (
# Support reloading icons.
if "_icon_cache" in locals():
release = bpy.app.icons.release
- for icon_value in _icon_cache.values():
+ for icon_value in set(_icon_cache.values()):
if icon_value != 0:
release(icon_value)
del release
@@ -450,7 +450,7 @@ class ToolSelectPanelHelper:
@classmethod
def _km_action_simple(cls, kc_default, kc, context_descr, label, keymap_fn):
- km_idname = f"{cls.keymap_prefix:s} {context_descr:s}, {label:s}"
+ km_idname = "%s %s, %s" % (cls.keymap_prefix, context_descr, label)
km = kc.keymaps.get(km_idname)
km_kwargs = dict(space_type=cls.bl_space_type, region_type='WINDOW', tool=True)
if km is None:
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 2c3108e0a11..2391678b99b 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -124,12 +124,12 @@ class _defs_view3d_generic:
kmi_remove = None
return tip_(
"Measure distance and angles.\n"
- "\u2022 {} anywhere for new measurement.\n"
+ "\u2022 %s anywhere for new measurement.\n"
"\u2022 Drag ruler segment to measure an angle.\n"
- "\u2022 {} to remove the active ruler.\n"
+ "\u2022 %s to remove the active ruler.\n"
"\u2022 Ctrl while dragging to snap.\n"
"\u2022 Shift while dragging to measure surface thickness"
- ).format(
+ ) % (
kmi_to_string_or_none(kmi_add),
kmi_to_string_or_none(kmi_remove),
)
@@ -482,7 +482,7 @@ class _defs_view3d_add:
return dict(
idname="builtin.primitive_cone_add",
label="Add Cone",
- icon="ops.mesh.primitive_cube_add_gizmo",
+ icon="ops.mesh.primitive_cone_add_gizmo",
description=(
"Add cone to mesh interactively"
),
@@ -738,27 +738,40 @@ class _defs_edit_mesh:
def bevel():
def draw_settings(context, layout, tool, *, extra=False):
props = tool.operator_properties("mesh.bevel")
- region_type = context.region.type
+
+ region_is_header = context.region.type == 'TOOL_HEADER'
if not extra:
- if region_type == 'TOOL_HEADER':
+ if region_is_header:
layout.prop(props, "offset_type", text="")
else:
layout.prop(props, "offset_type")
layout.prop(props, "segments")
- layout.prop(props, "profile", slider=True)
- if region_type == 'TOOL_HEADER':
+ row = layout.row()
+ row.prop(props, "profile_type", text="" if region_is_header else None)
+ if props.profile_type == 'SUPERELLIPSE':
+ layout.prop(props, "profile", text="Shape", slider=True)
+
+ if region_is_header:
layout.popover("TOPBAR_PT_tool_settings_extra", text="...")
else:
extra = True
- if extra or region_type != 'TOOL_HEADER':
- layout.prop(props, "vertex_only")
- layout.prop(props, "clamp_overlap")
- layout.prop(props, "loop_slide")
- layout.prop(props, "harden_normals")
+ if extra:
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ if props.profile_type == 'CUSTOM':
+ layout.prop(props, "profile", text="Miter Shape", slider=True)
+
+ col = layout.column()
+ col.prop(props, "vertex_only")
+ col.prop(props, "clamp_overlap")
+ col.prop(props, "loop_slide")
+ col.prop(props, "harden_normals")
+
col = layout.column(heading="Mark")
col.prop(props, "mark_seam", text="Seam")
col.prop(props, "mark_sharp", text="Sharp")
@@ -770,8 +783,7 @@ class _defs_edit_mesh:
if props.miter_inner == 'ARC':
layout.prop(props, "spread")
- layout.prop(props, "use_custom_profile")
- if props.use_custom_profile:
+ if props.profile_type == 'CUSTOM':
tool_settings = context.tool_settings
layout.template_curveprofile(tool_settings, "custom_bevel_profile_preset")
@@ -802,14 +814,14 @@ class _defs_edit_mesh:
)
@ToolDef.from_fn
- def extrude_dissolve_and_intersect():
+ def extrude_manifold():
return dict(
- idname="builtin.extrude_dissolve_and_intersect",
- label="Extrude Dissolve and Intersect",
+ idname="builtin.extrude_manifold",
+ label="Extrude Manifold",
description=(
"Extrude, dissolves edges whose faces form a flat surface and intersect new edges"
),
- icon="none",
+ icon="ops.mesh.extrude_manifold",
widget="VIEW3D_GGT_tool_generic_handle_normal",
keymap=(),
)
@@ -1212,10 +1224,10 @@ class _defs_sculpt:
layout.prop(props, "strength")
layout.prop(props, "deform_axis")
layout.prop(props, "use_face_sets")
- if (props.type == "SURFACE_SMOOTH"):
+ if props.type == 'SURFACE_SMOOTH':
layout.prop(props, "surface_smooth_shape_preservation", expand=False)
layout.prop(props, "surface_smooth_current_vertex", expand=False)
- if (props.type == "SHARPEN"):
+ elif props.type == 'SHARPEN':
layout.prop(props, "sharpen_smooth_ratio", expand=False)
return dict(
@@ -1246,6 +1258,24 @@ class _defs_sculpt:
draw_settings=draw_settings,
)
+ @ToolDef.from_fn
+ def color_filter():
+ def draw_settings(_context, layout, tool):
+ props = tool.operator_properties("sculpt.color_filter")
+ layout.prop(props, "type", expand=False)
+ if props.type == 'FILL':
+ layout.prop(props, "fill_color", expand=False)
+ layout.prop(props, "strength")
+
+ return dict(
+ idname="builtin.color_filter",
+ label="Color Filter",
+ icon="ops.sculpt.color_filter",
+ widget=None,
+ keymap=(),
+ draw_settings=draw_settings,
+ )
+
class _defs_vertex_paint:
@@ -2327,7 +2357,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
(
_defs_edit_mesh.extrude,
- _defs_edit_mesh.extrude_dissolve_and_intersect,
+ _defs_edit_mesh.extrude_manifold,
_defs_edit_mesh.extrude_normals,
_defs_edit_mesh.extrude_individual,
_defs_edit_mesh.extrude_cursor,
@@ -2421,6 +2451,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_sculpt.mesh_filter,
_defs_sculpt.cloth_filter,
+ _defs_sculpt.color_filter,
None,
_defs_transform.translate,
_defs_transform.rotate,
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 436d866886b..e5171df597a 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -45,7 +45,7 @@ class USERPREF_HT_header(Header):
# Show '*' to let users know the preferences have been modified.
layout.operator(
"wm.save_userpref",
- text="Save Preferences{:s}".format(" *" if prefs.is_dirty else ""),
+ text="Save Preferences" + (" *" if prefs.is_dirty else ""),
)
def draw(self, context):
@@ -1903,8 +1903,10 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
"wm.url_open", text="Report a Bug", icon='URL',
).url = info["tracker_url"]
elif not user_addon:
- addon_info = ("Name: {} {}\nAuthor: {}\n").format(
- info["name"], info["version"], info["author"])
+ addon_info = (
+ "Name: %s %s\n"
+ "Author: %s\n"
+ ) % (info["name"], str(info["version"]), info["author"])
props = sub.operator(
"wm.url_open_preset", text="Report a Bug", icon='URL',
)
@@ -1987,7 +1989,7 @@ class StudioLightPanelMixin:
for studio_light in lights:
self.draw_studio_light(flow, studio_light)
else:
- layout.label(text="No custom {} configured".format(self.bl_label))
+ layout.label(text="No custom %s configured" % self.bl_label)
def draw_studio_light(self, layout, studio_light):
box = layout.box()
@@ -2112,8 +2114,10 @@ class ExperimentalPanel:
split = layout.split(factor=0.66)
col = split.split()
col.prop(experimental, **prop_keywords)
- col = split.split()
- col.operator("wm.url_open", text=task, icon='URL').url = self.url_prefix + task
+
+ if task:
+ col = split.split()
+ col.operator("wm.url_open", text=task, icon='URL').url = self.url_prefix + task
"""
# Example panel, leave it here so we always have a template to follow even
@@ -2132,13 +2136,36 @@ class USERPREF_PT_experimental_virtual_reality(ExperimentalPanel, Panel):
"""
-class USERPREF_PT_experimental_system(ExperimentalPanel, Panel):
- bl_label = "System"
+class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
+ bl_label = "New Features"
+
+ def draw(self, context):
+ self._draw_items(
+ context, (
+ ({"property": "use_new_particle_system"}, "T73324"),
+ ),
+ )
+
+
+class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
+ bl_label = "Prototypes"
+
+ def draw(self, context):
+ self._draw_items(
+ context, (
+ ({"property": "use_new_hair_type"}, "T68981"),
+ ),
+ )
+
+
+class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
+ bl_label = "Debugging"
def draw(self, context):
self._draw_items(
context, (
({"property": "use_undo_legacy"}, "T60695"),
+ ({"property": "use_cycles_debug"}, None),
),
)
@@ -2233,7 +2260,9 @@ classes = (
# Popovers.
USERPREF_PT_ndof_settings,
- USERPREF_PT_experimental_system,
+ USERPREF_PT_experimental_new_features,
+ USERPREF_PT_experimental_prototypes,
+ USERPREF_PT_experimental_debugging,
# Add dynamically generated editor theme panels last,
# so they show up last in the theme section.
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index c982d8e93a9..1403e43a8af 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -131,7 +131,7 @@ class VIEW3D_HT_tool_header(Header):
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
tool = brush.gpencil_tool
- if tool in ('SMOOTH', 'RANDOMIZE'):
+ if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_options")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
@@ -295,6 +295,11 @@ class _draw_tool_settings_context_mode:
if not capabilities.has_direction:
layout.row().prop(brush, "direction", expand=True, text="")
+ if capabilities.has_color:
+ UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text = "")
+ layout.prop(brush, "blend", text="", expand = False)
+
+
return True
@staticmethod
@@ -2171,9 +2176,9 @@ class VIEW3D_MT_add(Menu):
layout.menu("VIEW3D_MT_surface_add", icon='OUTLINER_OB_SURFACE')
layout.menu("VIEW3D_MT_metaball_add", text="Metaball", icon='OUTLINER_OB_META')
layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
- if hasattr(bpy.data, "hairs"):
+ if context.preferences.experimental.use_new_hair_type:
layout.operator("object.hair_add", text="Hair", icon='OUTLINER_OB_HAIR')
- if hasattr(bpy.data, "pointclouds"):
+ if context.preferences.experimental.use_new_particle_system:
layout.operator("object.pointcloud_add", text="Point Cloud", icon='OUTLINER_OB_POINTCLOUD')
layout.menu("VIEW3D_MT_volume_add", text="Volume", icon='OUTLINER_OB_VOLUME')
layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
@@ -2348,6 +2353,7 @@ class VIEW3D_MT_object_animation(Menu):
layout.separator()
layout.operator("nla.bake", text="Bake Action...")
+ layout.operator("gpencil.mesh_bake", text="Bake Mesh to Grease Pencil...")
class VIEW3D_MT_object_rigid_body(Menu):
@@ -5620,8 +5626,8 @@ class VIEW3D_PT_object_type_visibility(Panel):
elif attr == "pointcloud" and not hasattr(bpy.data, "pointclouds"):
continue
- attr_v = "show_object_viewport_" f"{attr:s}"
- attr_s = "show_object_select_" f"{attr:s}"
+ attr_v = "show_object_viewport_" + attr
+ attr_s = "show_object_select_" + attr
icon_v = 'HIDE_OFF' if getattr(view, attr_v) else 'HIDE_ON'
icon_s = 'RESTRICT_SELECT_OFF' if getattr(view, attr_s) else 'RESTRICT_SELECT_ON'
@@ -6786,7 +6792,10 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
if context.object.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}:
layout.label(text="Vertex Paint")
- layout.prop(overlay, "gpencil_vertex_paint_opacity", text="Opacity", slider=True)
+ row = layout.row()
+ shading = VIEW3D_PT_shading.get_shading(context)
+ row.enabled = shading.type not in {'WIREFRAME', 'RENDERED'}
+ row.prop(overlay, "gpencil_vertex_paint_opacity", text="Opacity", slider=True)
class VIEW3D_PT_quad_view(Panel):
@@ -7329,6 +7338,12 @@ class VIEW3D_PT_sculpt_context_menu(Panel):
brush = context.tool_settings.sculpt.brush
capabilities = brush.sculpt_capabilities
+ if capabilities.has_color:
+ split = layout.split(factor=0.1)
+ UnifiedPaintPanel.prop_unified_color(split, context, brush, "color", text="")
+ UnifiedPaintPanel.prop_unified_color_picker(split, context, brush, "color", value_slider=True)
+ layout.prop(brush, "blend", text="")
+
UnifiedPaintPanel.prop_unified(
layout,
context,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 3d72a2a588c..549b89938e0 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -187,6 +187,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
+ bl_ui_units_x = 12
@classmethod
def poll(cls, context):
@@ -198,11 +199,15 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
+ tool_settings = context.tool_settings
ob = context.active_object
mesh = ob.data
split = layout.split()
+ row = layout.row(align=True, heading="Transform")
+ row.prop(tool_settings, "use_transform_correct_face_attributes")
+
row = layout.row(heading="Mirror")
sub = row.row(align=True)
sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
@@ -806,6 +811,8 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
col.prop(mesh, "use_remesh_preserve_volume", text="Volume")
col.prop(mesh, "use_remesh_preserve_paint_mask", text="Paint Mask")
col.prop(mesh, "use_remesh_preserve_sculpt_face_sets", text="Face Sets")
+ col.prop(mesh, "use_remesh_preserve_vertex_colors", text="Vertex Colors")
+
layout.operator("object.voxel_remesh", text="Remesh")
@@ -829,7 +836,6 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
sculpt = tool_settings.sculpt
col = layout.column(heading="Display", align=True)
- col.prop(sculpt, "use_threaded", text="Threaded Sculpt")
col.prop(sculpt, "show_low_resolution")
col.prop(sculpt, "use_sculpt_delay_updates")
col.prop(sculpt, "use_deform_only")
@@ -1694,7 +1700,7 @@ class GreasePencilSculptPanel:
@classmethod
def poll(cls, context):
- if context.space_data.type in ('VIEW_3D', 'PROPERTIES'):
+ if context.space_data.type in {'VIEW_3D', 'PROPERTIES'}:
if context.gpencil_data is None:
return False
@@ -1768,7 +1774,7 @@ class GreasePencilWeightPanel:
@classmethod
def poll(cls, context):
- if context.space_data.type in ('VIEW_3D', 'PROPERTIES'):
+ if context.space_data.type in {'VIEW_3D', 'PROPERTIES'}:
if context.gpencil_data is None:
return False
@@ -1843,7 +1849,7 @@ class GreasePencilVertexPanel:
@classmethod
def poll(cls, context):
- if context.space_data.type in ('VIEW_3D', 'PROPERTIES'):
+ if context.space_data.type in {'VIEW_3D', 'PROPERTIES'}:
if context.gpencil_data is None:
return False