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/startup')
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py18
-rw-r--r--release/scripts/startup/bl_operators/anim.py40
-rw-r--r--release/scripts/startup/bl_operators/clip.py60
-rw-r--r--release/scripts/startup/bl_operators/console.py4
-rw-r--r--release/scripts/startup/bl_operators/file.py59
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py22
-rw-r--r--release/scripts/startup/bl_operators/image.py2
-rw-r--r--release/scripts/startup/bl_operators/mesh.py6
-rw-r--r--release/scripts/startup/bl_operators/node.py12
-rw-r--r--release/scripts/startup/bl_operators/object.py221
-rw-r--r--release/scripts/startup/bl_operators/object_align.py8
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py164
-rw-r--r--release/scripts/startup/bl_operators/object_randomize_transform.py20
-rw-r--r--release/scripts/startup/bl_operators/presets.py170
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py20
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py6
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py27
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py14
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py10
-rw-r--r--release/scripts/startup/bl_operators/view3d.py12
-rw-r--r--release/scripts/startup/bl_operators/wm.py489
-rw-r--r--release/scripts/startup/bl_ui/__init__.py17
-rw-r--r--release/scripts/startup/bl_ui/properties_animviz.py31
-rw-r--r--release/scripts/startup/bl_ui/properties_data_armature.py65
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py320
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py353
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py331
-rw-r--r--release/scripts/startup/bl_ui/properties_data_empty.py11
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py414
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lattice.py33
-rw-r--r--release/scripts/startup/bl_ui/properties_data_light.py363
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lightprobe.py185
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py119
-rw-r--r--release/scripts/startup/bl_ui/properties_data_metaball.py50
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py32
-rw-r--r--release/scripts/startup/bl_ui/properties_data_speaker.py64
-rw-r--r--release/scripts/startup/bl_ui/properties_data_workspace.py101
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py83
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py881
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py28
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py997
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py281
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py1470
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_cloth.py48
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py64
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py86
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_field.py224
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py42
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody.py20
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py116
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_softbody.py35
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py806
-rw-r--r--release/scripts/startup/bl_ui/properties_render_layer.py242
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py209
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py864
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py82
-rw-r--r--release/scripts/startup/bl_ui/properties_world.py225
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py90
-rw-r--r--release/scripts/startup/bl_ui/space_console.py4
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py334
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py37
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py142
-rw-r--r--release/scripts/startup/bl_ui/space_image.py235
-rw-r--r--release/scripts/startup/bl_ui/space_info.py341
-rw-r--r--release/scripts/startup/bl_ui/space_logic.py145
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py42
-rw-r--r--release/scripts/startup/bl_ui/space_node.py158
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py238
-rw-r--r--release/scripts/startup/bl_ui/space_properties.py1
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py51
-rw-r--r--release/scripts/startup/bl_ui/space_statusbar.py68
-rw-r--r--release/scripts/startup/bl_ui/space_text.py29
-rw-r--r--release/scripts/startup/bl_ui/space_time.py254
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py725
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py1089
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py600
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py224
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2545
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py1012
-rw-r--r--release/scripts/startup/nodeitems_builtins.py155
84 files changed, 10350 insertions, 8864 deletions
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index 4af600473d1..4460af173ff 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -79,7 +79,7 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
def add_uvs(mesh, minor_seg, major_seg):
from math import fmod
- mesh.uv_textures.new()
+ mesh.uv_layers.new()
uv_data = mesh.uv_layers.active.data
polygons = mesh.polygons
u_step = 1.0 / major_seg
@@ -134,19 +134,19 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
self.abso_major_rad = self.major_radius + self.minor_radius
self.abso_minor_rad = self.major_radius - self.minor_radius
- major_segments = IntProperty(
+ major_segments: IntProperty(
name="Major Segments",
description="Number of segments for the main ring of the torus",
min=3, max=256,
default=48,
)
- minor_segments = IntProperty(
+ minor_segments: IntProperty(
name="Minor Segments",
description="Number of segments for the minor ring of the torus",
min=3, max=256,
default=12,
)
- mode = bpy.props.EnumProperty(
+ mode: bpy.props.EnumProperty(
name="Torus Dimensions",
items=(("MAJOR_MINOR", "Major/Minor",
"Use the major/minor radii for torus dimensions"),
@@ -154,7 +154,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
"Use the exterior/interior radii for torus dimensions")),
update=mode_update_callback,
)
- major_radius = FloatProperty(
+ major_radius: FloatProperty(
name="Major Radius",
description=("Radius from the origin to the "
"center of the cross sections"),
@@ -163,7 +163,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
subtype='DISTANCE',
unit='LENGTH',
)
- minor_radius = FloatProperty(
+ minor_radius: FloatProperty(
name="Minor Radius",
description="Radius of the torus' cross section",
min=0.01, max=100.0,
@@ -171,7 +171,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
subtype='DISTANCE',
unit='LENGTH',
)
- abso_major_rad = FloatProperty(
+ abso_major_rad: FloatProperty(
name="Exterior Radius",
description="Total Exterior Radius of the torus",
min=0.01, max=100.0,
@@ -179,7 +179,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
subtype='DISTANCE',
unit='LENGTH',
)
- abso_minor_rad = FloatProperty(
+ abso_minor_rad: FloatProperty(
name="Interior Radius",
description="Total Interior Radius of the torus",
min=0.01, max=100.0,
@@ -187,7 +187,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
subtype='DISTANCE',
unit='LENGTH',
)
- generate_uvs = BoolProperty(
+ generate_uvs: BoolProperty(
name="Generate UVs",
description="Generate a default UV map",
default=False,
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index 250c88b9009..31325cf0b50 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -40,20 +40,20 @@ class ANIM_OT_keying_set_export(Operator):
bl_idname = "anim.keying_set_export"
bl_label = "Export Keying Set..."
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
name="Filter folders",
default=True,
options={'HIDDEN'},
)
- filter_text = BoolProperty(
+ filter_text: BoolProperty(
name="Filter text",
default=True,
options={'HIDDEN'},
)
- filter_python = BoolProperty(
+ filter_python: BoolProperty(
name="Filter python",
default=True,
options={'HIDDEN'},
@@ -110,7 +110,7 @@ class ANIM_OT_keying_set_export(Operator):
# - special handling is needed for "nested" ID-blocks
# (e.g. nodetree in Material)
if ksp.id.bl_rna.identifier.startswith("ShaderNodeTree"):
- # Find material or lamp using this node tree...
+ # Find material or light using this node tree...
id_bpy_path = "bpy.data.nodes[\"%s\"]"
found = False
@@ -121,14 +121,14 @@ class ANIM_OT_keying_set_export(Operator):
break
if not found:
- for lamp in bpy.data.lamps:
- if lamp.node_tree == ksp.id:
- id_bpy_path = "bpy.data.lamps[\"%s\"].node_tree" % (lamp.name)
+ for light in bpy.data.lights:
+ if light.node_tree == ksp.id:
+ id_bpy_path = "bpy.data.lights[\"%s\"].node_tree" % (light.name)
found = True
break
if not found:
- self.report({'WARN'}, "Could not find material or lamp using Shader Node Tree - %s" % (ksp.id))
+ self.report({'WARN'}, "Could not find material or light using Shader Node Tree - %s" % (ksp.id))
elif ksp.id.bl_rna.identifier.startswith("CompositorNodeTree"):
# Find compositor nodetree using this node tree...
for scene in bpy.data.scenes:
@@ -203,51 +203,51 @@ class BakeAction(Operator):
bl_label = "Bake Action"
bl_options = {'REGISTER', 'UNDO'}
- frame_start = IntProperty(
+ frame_start: IntProperty(
name="Start Frame",
description="Start frame for baking",
min=0, max=300000,
default=1,
)
- frame_end = IntProperty(
+ frame_end: IntProperty(
name="End Frame",
description="End frame for baking",
min=1, max=300000,
default=250,
)
- step = IntProperty(
+ step: IntProperty(
name="Frame Step",
description="Frame Step",
min=1, max=120,
default=1,
)
- only_selected = BoolProperty(
+ only_selected: BoolProperty(
name="Only Selected Bones",
description="Only key selected bones (Pose baking only)",
default=True,
)
- visual_keying = BoolProperty(
+ visual_keying: BoolProperty(
name="Visual Keying",
description="Keyframe from the final transformations (with constraints applied)",
default=False,
)
- clear_constraints = BoolProperty(
+ clear_constraints: BoolProperty(
name="Clear Constraints",
description="Remove all constraints from keyed object/bones, and do 'visual' keying",
default=False,
)
- clear_parents = BoolProperty(
+ clear_parents: BoolProperty(
name="Clear Parents",
description="Bake animation onto the object then clear parents (objects only)",
default=False,
)
- use_current_action = BoolProperty(
+ use_current_action: BoolProperty(
name="Overwrite Current Action",
description="Bake animation into current action, instead of creating a new one "
"(useful for baking only part of bones in an armature)",
default=False,
)
- bake_types = EnumProperty(
+ bake_types: EnumProperty(
name="Bake Data",
description="Which data's transformations to bake",
options={'ENUM_FLAG'},
@@ -302,7 +302,7 @@ class ClearUselessActions(Operator):
bl_label = "Clear Useless Actions"
bl_options = {'REGISTER', 'UNDO'}
- only_unused = BoolProperty(
+ only_unused: BoolProperty(
name="Only Unused",
description="Only unused (Fake User only) actions get considered",
default=True,
@@ -341,7 +341,7 @@ class UpdateAnimatedTransformConstraint(Operator):
bl_label = "Update Animated Transform Constraints"
bl_options = {'REGISTER', 'UNDO'}
- use_convert_to_radians = BoolProperty(
+ use_convert_to_radians: BoolProperty(
name="Convert To Radians",
description="Convert fcurves/drivers affecting rotations to radians (Warning: use this only once!)",
default=True,
diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py
index dda6b2fa5ab..2717a4f62a3 100644
--- a/release/scripts/startup/bl_operators/clip.py
+++ b/release/scripts/startup/bl_operators/clip.py
@@ -133,7 +133,7 @@ class CLIP_OT_filter_tracks(bpy.types.Operator):
bl_idname = "clip.filter_tracks"
bl_options = {'UNDO', 'REGISTER'}
- track_threshold = FloatProperty(
+ track_threshold: FloatProperty(
name="Track Threshold",
description="Filter Threshold to select problematic tracks",
default=5.0,
@@ -236,7 +236,7 @@ class CLIP_OT_track_to_empty(Operator):
ob = None
ob = bpy.data.objects.new(name=track.name, object_data=None)
- ob.select = True
+ ob.select_set(action='SELECT')
context.scene.objects.link(ob)
context.scene.objects.active = ob
@@ -516,7 +516,7 @@ object's movement caused by this constraint"""
# XXX, should probably use context.selected_editable_objects
# since selected objects can be from a lib or in hidden layer!
for ob in scene.objects:
- if ob.select:
+ if ob.select_set(action='SELECT'):
self._bake_object(scene, ob)
return {'FINISHED'}
@@ -613,24 +613,24 @@ class CLIP_OT_setup_tracking_scene(Operator):
CLIP_set_viewport_background(context, True, sc.clip, sc.clip_user)
@staticmethod
- def _setupRenderLayers(context):
+ def _setupViewLayers(context):
scene = context.scene
- rlayers = scene.render.layers
+ view_layers = scene.view_layers
- if not scene.render.layers.get("Foreground"):
- if len(rlayers) == 1:
- fg = rlayers[0]
+ if not view_layers.get("Foreground"):
+ if len(view_layers) == 1:
+ fg = view_layers[0]
fg.name = 'Foreground'
else:
- fg = scene.render.layers.new("Foreground")
+ fg = view_layers.new("Foreground")
fg.use_sky = True
fg.layers = [True] + [False] * 19
fg.layers_zmask = [False] * 10 + [True] + [False] * 9
fg.use_pass_vector = True
- if not scene.render.layers.get("Background"):
- bg = scene.render.layers.new("Background")
+ if not view_layers.get("Background"):
+ bg = view_layers.new("Background")
bg.use_pass_shadow = True
bg.use_pass_ambient_occlusion = True
bg.layers = [False] * 10 + [True] + [False] * 9
@@ -915,17 +915,17 @@ class CLIP_OT_setup_tracking_scene(Operator):
return [(layers_a[i] | layers_b[i]) for i in range(len(layers_a))]
@staticmethod
- def _createLamp(scene):
- lamp = bpy.data.lamps.new(name="Lamp", type='POINT')
- lampob = bpy.data.objects.new(name="Lamp", object_data=lamp)
- scene.objects.link(lampob)
+ def _createLight(scene):
+ light = bpy.data.lights.new(name="Light", type='POINT')
+ lightob = bpy.data.objects.new(name="Light", object_data=light)
+ scene.objects.link(lightob)
- lampob.matrix_local = Matrix.Translation((4.076, 1.005, 5.904))
+ lightob.matrix_local = Matrix.Translation((4.076, 1.005, 5.904))
- lamp.distance = 30
- lamp.shadow_method = 'RAY_SHADOW'
+ light.distance = 30
+ light.shadow_method = 'RAY_SHADOW'
- return lampob
+ return lightob
def _createSampleObject(self, scene):
vertices = self._getPlaneVertices(1.0, -1.0) + \
@@ -942,25 +942,25 @@ class CLIP_OT_setup_tracking_scene(Operator):
def _setupObjects(self, context):
scene = context.scene
- fg = scene.render.layers.get("Foreground")
- bg = scene.render.layers.get("Background")
+ fg = scene.view_layers.get("Foreground")
+ bg = scene.view_layers.get("Background")
all_layers = self._mergeLayers(fg.layers, bg.layers)
- # ensure all lamps are active on foreground and background
- has_lamp = False
+ # ensure all lights are active on foreground and background
+ has_light = False
has_mesh = False
for ob in scene.objects:
- if ob.type == 'LAMP':
+ if ob.type == 'LIGHT':
ob.layers = all_layers
- has_lamp = True
+ has_light = True
elif ob.type == 'MESH' and "is_ground" not in ob:
has_mesh = True
- # create sample lamp if there's no lamps in the scene
- if not has_lamp:
- lamp = self._createLamp(scene)
- lamp.layers = all_layers
+ # create sample light if there's no lights in the scene
+ if not has_light:
+ light = self._createLight(scene)
+ light.layers = all_layers
# create sample object if there's no meshes in the scene
if not has_mesh:
@@ -987,7 +987,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
self._setupWorld(context)
self._setupCamera(context)
self._setupViewport(context)
- self._setupRenderLayers(context)
+ self._setupViewLayers(context)
self._setupNodes(context)
self._setupObjects(context)
diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py
index 2d32f84805e..b62b9310224 100644
--- a/release/scripts/startup/bl_operators/console.py
+++ b/release/scripts/startup/bl_operators/console.py
@@ -37,7 +37,7 @@ class ConsoleExec(Operator):
bl_idname = "console.execute"
bl_label = "Console Execute"
- interactive = BoolProperty(
+ interactive: BoolProperty(
options={'SKIP_SAVE'},
)
@@ -137,7 +137,7 @@ class ConsoleLanguage(Operator):
bl_idname = "console.language"
bl_label = "Console Language"
- language = StringProperty(
+ language: StringProperty(
name="Language",
maxlen=32,
)
diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py
index 5bb97ff298a..44948879fe6 100644
--- a/release/scripts/startup/bl_operators/file.py
+++ b/release/scripts/startup/bl_operators/file.py
@@ -37,56 +37,56 @@ class WM_OT_previews_batch_generate(Operator):
# -----------
# File props.
- files = CollectionProperty(
+ files: CollectionProperty(
type=bpy.types.OperatorFileListElement,
options={'HIDDEN', 'SKIP_SAVE'},
)
- directory = StringProperty(
+ directory: StringProperty(
maxlen=1024,
subtype='FILE_PATH',
options={'HIDDEN', 'SKIP_SAVE'},
)
# Show only images/videos, and directories!
- filter_blender = BoolProperty(
+ filter_blender: BoolProperty(
default=True,
options={'HIDDEN', 'SKIP_SAVE'},
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
default=True,
options={'HIDDEN', 'SKIP_SAVE'},
)
# -----------
# Own props.
- use_scenes = BoolProperty(
+ use_scenes: BoolProperty(
default=True,
name="Scenes",
description="Generate scenes' previews",
)
- use_groups = BoolProperty(
+ use_collections: BoolProperty(
default=True,
- name="Groups",
- description="Generate groups' previews",
+ name="Collections",
+ description="Generate collections' previews",
)
- use_objects = BoolProperty(
+ use_objects: BoolProperty(
default=True,
name="Objects",
description="Generate objects' previews",
)
- use_intern_data = BoolProperty(
+ use_intern_data: BoolProperty(
default=True,
name="Mat/Tex/...",
description="Generate 'internal' previews (materials, textures, images, etc.)",
)
- use_trusted = BoolProperty(
+ use_trusted: BoolProperty(
default=False,
name="Trusted Blend Files",
description="Enable python evaluation for selected files",
)
- use_backups = BoolProperty(
+ use_backups: BoolProperty(
default=True,
name="Save Backups",
description="Keep a backup (.blend1) version of the files when saving with generated previews",
@@ -121,8 +121,8 @@ class WM_OT_previews_batch_generate(Operator):
])
if not self.use_scenes:
cmd.append('--no_scenes')
- if not self.use_groups:
- cmd.append('--no_groups')
+ if not self.use_collections:
+ cmd.append('--no_collections')
if not self.use_objects:
cmd.append('--no_objects')
if not self.use_intern_data:
@@ -147,55 +147,56 @@ class WM_OT_previews_batch_clear(Operator):
# -----------
# File props.
- files = CollectionProperty(
+ files: CollectionProperty(
type=bpy.types.OperatorFileListElement,
options={'HIDDEN', 'SKIP_SAVE'},
)
- directory = StringProperty(
+ directory: StringProperty(
maxlen=1024,
subtype='FILE_PATH',
options={'HIDDEN', 'SKIP_SAVE'},
)
# Show only images/videos, and directories!
- filter_blender = BoolProperty(
+ filter_blender: BoolProperty(
default=True,
options={'HIDDEN', 'SKIP_SAVE'},
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
default=True,
options={'HIDDEN', 'SKIP_SAVE'},
)
# -----------
# Own props.
- use_scenes = BoolProperty(
+ use_scenes: BoolProperty(
default=True,
name="Scenes",
description="Clear scenes' previews",
)
- use_groups = BoolProperty(default=True,
- name="Groups",
- description="Clear groups' previews",
- )
- use_objects = BoolProperty(
+ use_collections: BoolProperty(
+ default=True,
+ name="Collections",
+ description="Clear collections' previews",
+ )
+ use_objects: BoolProperty(
default=True,
name="Objects",
description="Clear objects' previews",
)
- use_intern_data = BoolProperty(
+ use_intern_data: BoolProperty(
default=True,
name="Mat/Tex/...",
description="Clear 'internal' previews (materials, textures, images, etc.)",
)
- use_trusted = BoolProperty(
+ use_trusted: BoolProperty(
default=False,
name="Trusted Blend Files",
description="Enable python evaluation for selected files",
)
- use_backups = BoolProperty(
+ use_backups: BoolProperty(
default=True,
name="Save Backups",
description="Keep a backup (.blend1) version of the files when saving with cleared previews",
@@ -231,8 +232,8 @@ class WM_OT_previews_batch_clear(Operator):
])
if not self.use_scenes:
cmd.append('--no_scenes')
- if not self.use_groups:
- cmd.append('--no_groups')
+ if not self.use_collections:
+ cmd.append('--no_collections')
if not self.use_objects:
cmd.append('--no_objects')
if not self.use_intern_data:
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
index 6ee840ffc75..894808de3ed 100644
--- a/release/scripts/startup/bl_operators/freestyle.py
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -34,28 +34,28 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
bl_label = "Fill Range by Selection"
bl_options = {'INTERNAL'}
- type = EnumProperty(
+ type: EnumProperty(
name="Type", description="Type of the modifier to work on",
items=(("COLOR", "Color", "Color modifier type"),
("ALPHA", "Alpha", "Alpha modifier type"),
("THICKNESS", "Thickness", "Thickness modifier type")),
)
- name = StringProperty(
+ name: StringProperty(
name="Name",
description="Name of the modifier to work on",
)
@classmethod
def poll(cls, context):
- rl = context.scene.render.layers.active
- return rl and rl.freestyle_settings.linesets.active
+ view_layer = context.view_layer
+ return view_layer and view_layer.freestyle_settings.linesets.active
def execute(self, context):
import sys
scene = context.scene
- rl = scene.render.layers.active
- lineset = rl.freestyle_settings.linesets.active
+ view_layer = context.view_layer
+ lineset = view_layer.freestyle_settings.linesets.active
linestyle = lineset.linestyle
# Find the modifier to work on
if self.type == 'COLOR':
@@ -104,7 +104,7 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
m.range_max = max_dist
return {'FINISHED'}
# Find selected mesh objects
- selection = [ob for ob in scene.objects if ob.select and ob.type == 'MESH' and ob.name != ref.name]
+ selection = [ob for ob in scene.objects if ob.select_get() and ob.type == 'MESH' and ob.name != source.name]
if selection:
# Compute the min/max distance from the reference to mesh vertices
min_dist = sys.float_info.max
@@ -198,17 +198,17 @@ class SCENE_OT_freestyle_module_open(bpy.types.Operator):
bl_label = "Open Style Module File"
bl_options = {'INTERNAL'}
- filepath = StringProperty(subtype='FILE_PATH')
+ filepath: StringProperty(subtype='FILE_PATH')
- make_internal = BoolProperty(
+ make_internal: BoolProperty(
name="Make internal",
description="Make module file internal after loading",
default=True)
@classmethod
def poll(cls, context):
- rl = context.scene.render.layers.active
- return rl and rl.freestyle_settings.mode == 'SCRIPT'
+ view_layer = context.view_layer
+ return view_layer and view_layer.freestyle_settings.mode == 'SCRIPT'
def invoke(self, context, event):
self.freestyle_module = context.freestyle_module
diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py
index 5c5ca329cda..28e5e59d780 100644
--- a/release/scripts/startup/bl_operators/image.py
+++ b/release/scripts/startup/bl_operators/image.py
@@ -29,7 +29,7 @@ class EditExternally(Operator):
bl_label = "Image Edit Externally"
bl_options = {'REGISTER'}
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index 7fb1877d191..a7475dcc6ef 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -33,7 +33,7 @@ class MeshMirrorUV(Operator):
bl_label = "Copy Mirrored UV coords"
bl_options = {'REGISTER', 'UNDO'}
- direction = EnumProperty(
+ direction: EnumProperty(
name="Axis Direction",
items=(
('POSITIVE', "Positive", ""),
@@ -41,7 +41,7 @@ class MeshMirrorUV(Operator):
),
)
- precision = IntProperty(
+ precision: IntProperty(
name="Precision",
description=("Tolerance for finding vertex duplicates"),
min=1, max=16,
@@ -52,7 +52,7 @@ class MeshMirrorUV(Operator):
@classmethod
def poll(cls, context):
obj = context.active_object
- return (obj and obj.type == 'MESH' and obj.data.uv_textures.active)
+ return (obj and obj.type == 'MESH' and obj.data.uv_layers.active)
def execute(self, context):
DIR = (self.direction == 'NEGATIVE')
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index bb8f991e526..fbebee2d8a1 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -34,7 +34,7 @@ from bpy.props import (
class NodeSetting(PropertyGroup):
- value = StringProperty(
+ value: StringProperty(
name="Value",
description="Python expression to be evaluated "
"as the initial node setting",
@@ -45,16 +45,16 @@ class NodeSetting(PropertyGroup):
# Base class for node 'Add' operators
class NodeAddOperator:
- type = StringProperty(
+ type: StringProperty(
name="Node Type",
description="Node type",
)
- use_transform = BoolProperty(
+ use_transform: BoolProperty(
name="Use Transform",
description="Start transform operator after inserting the node",
default=False,
)
- settings = CollectionProperty(
+ settings: CollectionProperty(
name="Settings",
description="Settings to be applied on the newly created node",
type=NodeSetting,
@@ -152,7 +152,7 @@ class NODE_OT_add_and_link_node(NodeAddOperator, Operator):
bl_label = "Add and Link Node"
bl_options = {'REGISTER', 'UNDO'}
- link_socket_index = IntProperty(
+ link_socket_index: IntProperty(
name="Link Socket Index",
description="Index of the socket to link",
)
@@ -210,7 +210,7 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
return item
return None
- node_item = EnumProperty(
+ node_item: EnumProperty(
name="Node Type",
description="Node type",
items=node_enum_items,
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index 91e5859d2c0..be379ec6089 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -35,19 +35,19 @@ class SelectPattern(Operator):
bl_label = "Select Pattern"
bl_options = {'REGISTER', 'UNDO'}
- pattern = StringProperty(
+ pattern: StringProperty(
name="Pattern",
description="Name filter using '*', '?' and "
"'[abc]' unix style wildcards",
maxlen=64,
default="*",
)
- case_sensitive = BoolProperty(
+ case_sensitive: BoolProperty(
name="Case Sensitive",
description="Do a case sensitive compare",
default=False,
)
- extend = BoolProperty(
+ extend: BoolProperty(
name="Extend",
description="Extend the existing selection",
default=True,
@@ -81,16 +81,18 @@ class SelectPattern(Operator):
# Can be pose bones or objects
for item in items:
if pattern_match(item.name, self.pattern):
- item.select = True
# hrmf, perhaps there should be a utility function for this.
if is_ebone:
+ item.select = True
item.select_head = True
item.select_tail = True
if item.use_connect:
item_parent = item.parent
if item_parent is not None:
item_parent.select_tail = True
+ else:
+ item.select_set(action='SELECT')
return {'FINISHED'}
@@ -113,7 +115,7 @@ class SelectCamera(Operator):
bl_label = "Select Camera"
bl_options = {'REGISTER', 'UNDO'}
- extend = BoolProperty(
+ extend: BoolProperty(
name="Extend",
description="Extend the selection",
default=False
@@ -121,6 +123,7 @@ class SelectCamera(Operator):
def execute(self, context):
scene = context.scene
+ view_layer = context.view_layer
view = context.space_data
if view.type == 'VIEW_3D' and not view.lock_camera_and_layers:
camera = view.camera
@@ -134,9 +137,9 @@ class SelectCamera(Operator):
else:
if not self.extend:
bpy.ops.object.select_all(action='DESELECT')
- scene.objects.active = camera
- camera.hide = False
- camera.select = True
+ view_layer.objects.active = camera
+ # camera.hide = False # XXX TODO where is this now?
+ camera.select_set(action='SELECT')
return {'FINISHED'}
return {'CANCELLED'}
@@ -149,15 +152,15 @@ class SelectHierarchy(Operator):
bl_label = "Select Hierarchy"
bl_options = {'REGISTER', 'UNDO'}
- direction = EnumProperty(
+ direction: EnumProperty(
items=(('PARENT', "Parent", ""),
('CHILD', "Child", ""),
),
name="Direction",
description="Direction to select in the hierarchy",
- default='PARENT')
-
- extend = BoolProperty(
+ default='PARENT',
+ )
+ extend: BoolProperty(
name="Extend",
description="Extend the existing selection",
default=False,
@@ -169,6 +172,7 @@ class SelectHierarchy(Operator):
def execute(self, context):
scene = context.scene
+ view_layer = context.view_layer
select_new = []
act_new = None
@@ -202,9 +206,9 @@ class SelectHierarchy(Operator):
bpy.ops.object.select_all(action='DESELECT')
for obj in select_new:
- obj.select = True
+ obj.select_set(action='SELECT')
- scene.objects.active = act_new
+ view_layer.objects.active = act_new
return {'FINISHED'}
return {'CANCELLED'}
@@ -217,14 +221,13 @@ class SubdivisionSet(Operator):
bl_label = "Subdivision Set"
bl_options = {'REGISTER', 'UNDO'}
- level = IntProperty(
+ level: IntProperty(
name="Level",
min=-100, max=100,
soft_min=-6, soft_max=6,
default=1,
)
-
- relative = BoolProperty(
+ relative: BoolProperty(
name="Relative",
description=("Apply the subsurf level as an offset "
"relative to the current level"),
@@ -308,7 +311,7 @@ class ShapeTransfer(Operator):
bl_label = "Transfer Shape Key"
bl_options = {'REGISTER', 'UNDO'}
- mode = EnumProperty(
+ mode: EnumProperty(
items=(('OFFSET',
"Offset",
"Apply the relative positional offset",
@@ -326,7 +329,7 @@ class ShapeTransfer(Operator):
description="Relative shape positions to the new shape method",
default='OFFSET',
)
- use_clamp = BoolProperty(
+ use_clamp: BoolProperty(
name="Clamp Offset",
description=("Clamp the transformation to the distance each "
"vertex moves in the original shape"),
@@ -513,7 +516,7 @@ class JoinUVs(Operator):
if is_editmode:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
- if not mesh.uv_textures:
+ if not mesh.uv_layers:
self.report({'WARNING'},
"Object: %s, Mesh: '%s' has no UVs"
% (obj.name, mesh.name))
@@ -551,7 +554,7 @@ class JoinUVs(Operator):
else:
uv_other = mesh_other.uv_layers.active
if not uv_other:
- mesh_other.uv_textures.new()
+ mesh_other.uv_layers.new()
uv_other = mesh_other.uv_layers.active
if not uv_other:
self.report({'ERROR'}, "Could not add "
@@ -644,8 +647,8 @@ class MakeDupliFace(Operator):
ob_new.use_dupli_faces_scale = True
ob_new.dupli_faces_scale = 1.0 / SCALE_FAC
- ob_inst.select = True
- ob_new.select = True
+ ob_inst.select_set(action='SELECT')
+ ob_new.select_set(action='SELECT')
def execute(self, context):
self._main(context)
@@ -664,7 +667,7 @@ class IsolateTypeRender(Operator):
for obj in context.visible_objects:
- if obj.select:
+ if obj.select_get():
obj.hide_render = False
else:
if obj.type == act_type:
@@ -692,7 +695,7 @@ class TransformsToDeltas(Operator):
bl_label = "Transforms to Deltas"
bl_options = {'REGISTER', 'UNDO'}
- mode = EnumProperty(
+ mode: EnumProperty(
items=(
('ALL', "All Transforms", "Transfer location, rotation, and scale transforms"),
('LOC', "Location", "Transfer location transforms only"),
@@ -703,7 +706,7 @@ class TransformsToDeltas(Operator):
description="Which transforms to transfer",
default='ALL',
)
- reset_values = BoolProperty(
+ reset_values: BoolProperty(
name="Reset Values",
description=("Clear transform values after transferring to deltas"),
default=True,
@@ -850,7 +853,7 @@ class TransformsToDeltasAnim(Operator):
class DupliOffsetFromCursor(Operator):
- """Set offset used for DupliGroup based on cursor position"""
+ """Set offset used for collection instances based on cursor position"""
bl_idname = "object.dupli_offset_from_cursor"
bl_label = "Set Offset From Cursor"
bl_options = {'INTERNAL', 'UNDO'}
@@ -861,166 +864,9 @@ class DupliOffsetFromCursor(Operator):
def execute(self, context):
scene = context.scene
- group = context.group
-
- group.dupli_offset = scene.cursor_location
-
- return {'FINISHED'}
-
-
-class LodByName(Operator):
- """Add levels of detail to this object based on object names"""
- bl_idname = "object.lod_by_name"
- bl_label = "Setup Levels of Detail By Name"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- return (context.active_object is not None)
-
- def execute(self, context):
- ob = context.active_object
-
- prefix = ""
- suffix = ""
- name = ""
- if ob.name.lower().startswith("lod0"):
- prefix = ob.name[:4]
- name = ob.name[4:]
- elif ob.name.lower().endswith("lod0"):
- name = ob.name[:-4]
- suffix = ob.name[-4:]
- else:
- return {'CANCELLED'}
-
- level = 0
- while True:
- level += 1
-
- if prefix:
- prefix = prefix[:3] + str(level)
- if suffix:
- suffix = suffix[:3] + str(level)
-
- lod = None
- try:
- lod = bpy.data.objects[prefix + name + suffix]
- except KeyError:
- break
-
- try:
- ob.lod_levels[level]
- except IndexError:
- bpy.ops.object.lod_add()
-
- ob.lod_levels[level].object = lod
-
- return {'FINISHED'}
-
-
-class LodClearAll(Operator):
- """Remove all levels of detail from this object"""
- bl_idname = "object.lod_clear_all"
- bl_label = "Clear All Levels of Detail"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- return (context.active_object is not None)
-
- def execute(self, context):
- ob = context.active_object
-
- if ob.lod_levels:
- while 'CANCELLED' not in bpy.ops.object.lod_remove():
- pass
-
- return {'FINISHED'}
-
-
-class LodGenerate(Operator):
- """Generate levels of detail using the decimate modifier"""
- bl_idname = "object.lod_generate"
- bl_label = "Generate Levels of Detail"
- bl_options = {'REGISTER', 'UNDO'}
-
- count = IntProperty(
- name="Count",
- default=3,
- )
- target = FloatProperty(
- name="Target Size",
- min=0.0, max=1.0,
- default=0.1,
- )
- package = BoolProperty(
- name="Package into Group",
- default=False,
- )
-
- @classmethod
- def poll(cls, context):
- return (context.active_object is not None)
-
- def execute(self, context):
- scene = context.scene
- ob = scene.objects.active
-
- lod_name = ob.name
- lod_suffix = "lod"
- lod_prefix = ""
- if lod_name.lower().endswith("lod0"):
- lod_suffix = lod_name[-3:-1]
- lod_name = lod_name[:-3]
- elif lod_name.lower().startswith("lod0"):
- lod_suffix = ""
- lod_prefix = lod_name[:3]
- lod_name = lod_name[4:]
-
- group_name = lod_name.strip(' ._')
- if self.package:
- try:
- bpy.ops.object.group_link(group=group_name)
- except TypeError:
- bpy.ops.group.create(name=group_name)
-
- step = (1.0 - self.target) / (self.count - 1)
- for i in range(1, self.count):
- scene.objects.active = ob
- bpy.ops.object.duplicate()
- lod = context.selected_objects[0]
-
- scene.objects.active = ob
- bpy.ops.object.lod_add()
- scene.objects.active = lod
-
- if lod_prefix:
- lod.name = lod_prefix + str(i) + lod_name
- else:
- lod.name = lod_name + lod_suffix + str(i)
-
- lod.location.y = ob.location.y + 3.0 * i
-
- if i == 1:
- modifier = lod.modifiers.new("lod_decimate", 'DECIMATE')
- else:
- modifier = lod.modifiers[-1]
-
- modifier.ratio = 1.0 - step * i
-
- ob.lod_levels[i].object = lod
-
- if self.package:
- bpy.ops.object.group_link(group=group_name)
- lod.parent = ob
-
- if self.package:
- for level in ob.lod_levels[1:]:
- level.object.hide = level.object.hide_render = True
+ collection = context.collection
- lod.select = False
- ob.select = True
- scene.objects.active = ob
+ collection.dupli_offset = scene.cursor_location
return {'FINISHED'}
@@ -1030,9 +876,6 @@ classes = (
DupliOffsetFromCursor,
IsolateTypeRender,
JoinUVs,
- LodByName,
- LodClearAll,
- LodGenerate,
MakeDupliFace,
SelectCamera,
SelectHierarchy,
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index 11c1514e4bf..f627fd30162 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -363,7 +363,7 @@ class AlignObjects(Operator):
bl_label = "Align Objects"
bl_options = {'REGISTER', 'UNDO'}
- bb_quality = BoolProperty(
+ bb_quality: BoolProperty(
name="High Quality",
description=(
"Enables high quality calculation of the "
@@ -372,7 +372,7 @@ class AlignObjects(Operator):
),
default=True,
)
- align_mode = EnumProperty(
+ align_mode: EnumProperty(
name="Align Mode:",
description="Side of object to use for alignment",
items=(
@@ -382,7 +382,7 @@ class AlignObjects(Operator):
),
default='OPT_2',
)
- relative_to = EnumProperty(
+ relative_to: EnumProperty(
name="Relative To:",
description="Reference location to align to",
items=(
@@ -393,7 +393,7 @@ class AlignObjects(Operator):
),
default='OPT_4',
)
- align_axis = EnumProperty(
+ align_axis: EnumProperty(
name="Align",
description="Align to axis",
items=(
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index c2592f13d66..36dc1b46590 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -52,7 +52,7 @@ class QuickFur(Operator):
bl_label = "Quick Fur"
bl_options = {'REGISTER', 'UNDO'}
- density = EnumProperty(
+ density: EnumProperty(
name="Fur Density",
items=(
('LIGHT', "Light", ""),
@@ -61,13 +61,13 @@ class QuickFur(Operator):
),
default='MEDIUM',
)
- view_percentage = IntProperty(
+ view_percentage: IntProperty(
name="View %",
min=1, max=100,
soft_min=1, soft_max=100,
default=10,
)
- length = FloatProperty(
+ length: FloatProperty(
name="Length",
min=0.001, max=100,
soft_min=0.01, soft_max=10,
@@ -118,7 +118,7 @@ class QuickExplode(Operator):
bl_label = "Quick Explode"
bl_options = {'REGISTER', 'UNDO'}
- style = EnumProperty(
+ style: EnumProperty(
name="Explode Style",
items=(
('EXPLODE', "Explode", ""),
@@ -126,40 +126,40 @@ class QuickExplode(Operator):
),
default='EXPLODE',
)
- amount = IntProperty(
+ amount: IntProperty(
name="Amount of pieces",
min=2, max=10000,
soft_min=2, soft_max=10000,
default=100,
)
- frame_duration = IntProperty(
+ frame_duration: IntProperty(
name="Duration",
min=1, max=300000,
soft_min=1, soft_max=10000,
default=50,
)
- frame_start = IntProperty(
+ frame_start: IntProperty(
name="Start Frame",
min=1, max=300000,
soft_min=1, soft_max=10000,
default=1,
)
- frame_end = IntProperty(
+ frame_end: IntProperty(
name="End Frame",
min=1, max=300000,
soft_min=1, soft_max=10000,
default=10,
)
- velocity = FloatProperty(
+ velocity: FloatProperty(
name="Outwards Velocity",
min=0, max=300000,
soft_min=0, soft_max=10,
default=1,
)
- fade = BoolProperty(
+ fade: BoolProperty(
name="Fade",
description="Fade the pieces over time",
default=True,
@@ -226,7 +226,7 @@ class QuickExplode(Operator):
if self.fade:
explode.show_dead = False
- uv = obj.data.uv_textures.new("Explode fade")
+ uv = obj.data.uv_layers.new("Explode fade")
explode.particle_uv = uv.name
mat = object_ensure_material(obj, "Explode Fade")
@@ -306,7 +306,7 @@ class QuickSmoke(Operator):
bl_label = "Quick Smoke"
bl_options = {'REGISTER', 'UNDO'}
- style = EnumProperty(
+ style: EnumProperty(
name="Smoke Style",
items=(
('SMOKE', "Smoke", ""),
@@ -316,7 +316,7 @@ class QuickSmoke(Operator):
default='SMOKE',
)
- show_flows = BoolProperty(
+ show_flows: BoolProperty(
name="Render Smoke Objects",
description="Keep the smoke objects visible during rendering",
default=False,
@@ -369,88 +369,38 @@ class QuickSmoke(Operator):
# Setup material
- # Cycles
- if context.scene.render.use_shading_nodes:
- bpy.ops.object.material_slot_add()
-
- mat = bpy.data.materials.new("Smoke Domain Material")
- obj.material_slots[0].material = mat
-
- # Make sure we use nodes
- mat.use_nodes = True
-
- # Set node variables and clear the default nodes
- tree = mat.node_tree
- nodes = tree.nodes
- links = tree.links
-
- nodes.clear()
+ # Cycles and Eevee
+ bpy.ops.object.material_slot_add()
- # Create shader nodes
+ mat = bpy.data.materials.new("Smoke Domain Material")
+ obj.material_slots[0].material = mat
- # Material output
- node_out = nodes.new(type='ShaderNodeOutputMaterial')
- node_out.location = grid_location(6, 1)
+ # Make sure we use nodes
+ mat.use_nodes = True
- # Add Principled Volume
- node_principled = nodes.new(type='ShaderNodeVolumePrincipled')
- node_principled.location = grid_location(4, 1)
- links.new(node_principled.outputs["Volume"],
- node_out.inputs["Volume"])
+ # Set node variables and clear the default nodes
+ tree = mat.node_tree
+ nodes = tree.nodes
+ links = tree.links
- node_principled.inputs["Density"].default_value = 5.0
+ nodes.clear()
- if self.style in {'FIRE', 'BOTH'}:
- node_principled.inputs["Blackbody Intensity"].default_value = 1.0
+ # Create shader nodes
- # Blender Internal
- else:
- # create a volume material with a voxel data texture for the domain
- bpy.ops.object.material_slot_add()
-
- mat = bpy.data.materials.new("Smoke Domain Material")
- obj.material_slots[0].material = mat
- mat.type = 'VOLUME'
- mat.volume.density = 0
- mat.volume.density_scale = 5
- mat.volume.step_size = 0.1
-
- tex = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA')
- tex.voxel_data.domain_object = obj
- tex.voxel_data.interpolation = 'TRICUBIC_BSPLINE'
-
- tex_slot = mat.texture_slots.add()
- tex_slot.texture = tex
- tex_slot.texture_coords = 'ORCO'
- tex_slot.use_map_color_emission = False
- tex_slot.use_map_density = True
- tex_slot.use_map_color_reflection = True
-
- # for fire add a second texture for flame emission
- mat.volume.emission_color = Vector((0.0, 0.0, 0.0))
- tex = bpy.data.textures.new("Flame", 'VOXEL_DATA')
- tex.voxel_data.domain_object = obj
- tex.voxel_data.smoke_data_type = 'SMOKEFLAME'
- tex.voxel_data.interpolation = 'TRICUBIC_BSPLINE'
- tex.use_color_ramp = True
+ # Material output
+ node_out = nodes.new(type='ShaderNodeOutputMaterial')
+ node_out.location = grid_location(6, 1)
- tex_slot = mat.texture_slots.add()
- tex_slot.texture = tex
- tex_slot.texture_coords = 'ORCO'
+ # Add Principled Volume
+ node_principled = nodes.new(type='ShaderNodeVolumePrincipled')
+ node_principled.location = grid_location(4, 1)
+ links.new(node_principled.outputs["Volume"],
+ node_out.inputs["Volume"])
- # add color ramp for flame color
- ramp = tex.color_ramp
- # dark orange
- elem = ramp.elements.new(0.333)
- elem.color = (0.2, 0.03, 0.0, 1.0)
+ node_principled.inputs["Density"].default_value = 5.0
- # yellow glow
- elem = ramp.elements.new(0.666)
- elem.color = (1, 0.65, 0.25, 1.0)
-
- mat.texture_slots[1].use_map_density = True
- mat.texture_slots[1].use_map_emission = True
- mat.texture_slots[1].emission_factor = 5
+ if self.style in {'FIRE', 'BOTH'}:
+ node_principled.inputs["Blackbody Intensity"].default_value = 1.0
return {'FINISHED'}
@@ -460,7 +410,7 @@ class QuickFluid(Operator):
bl_label = "Quick Fluid"
bl_options = {'REGISTER', 'UNDO'}
- style = EnumProperty(
+ style: EnumProperty(
name="Fluid Style",
items=(
('INFLOW', "Inflow", ""),
@@ -468,19 +418,19 @@ class QuickFluid(Operator):
),
default='BASIC',
)
- initial_velocity = FloatVectorProperty(
+ initial_velocity: FloatVectorProperty(
name="Initial Velocity",
description="Initial velocity of the fluid",
min=-100.0, max=100.0,
default=(0.0, 0.0, 0.0),
subtype='VELOCITY',
)
- show_flows = BoolProperty(
+ show_flows: BoolProperty(
name="Render Fluid Objects",
description="Keep the fluid objects visible during rendering",
default=False,
)
- start_baking = BoolProperty(
+ start_baking: BoolProperty(
name="Start Fluid Bake",
description=("Start baking the fluid immediately "
"after creating the domain object"),
@@ -554,13 +504,33 @@ class QuickFluid(Operator):
mat = bpy.data.materials.new("Fluid Domain Material")
obj.material_slots[0].material = mat
- mat.specular_intensity = 1
- mat.specular_hardness = 100
- mat.use_transparency = True
- mat.alpha = 0.0
- mat.transparency_method = 'RAYTRACE'
- mat.raytrace_transparency.ior = 1.33
- mat.raytrace_transparency.depth = 4
+ # Make sure we use nodes
+ mat.use_nodes = True
+
+ # Set node variables and clear the default nodes
+ tree = mat.node_tree
+ nodes = tree.nodes
+ links = tree.links
+
+ nodes.clear()
+
+ # Create shader nodes
+
+ # Material output
+ node_out = nodes.new(type='ShaderNodeOutputMaterial')
+ node_out.location = grid_location(6, 1)
+
+ # Add Glass
+ node_glass = nodes.new(type='ShaderNodeBsdfGlass')
+ node_glass.location = grid_location(4, 1)
+ links.new(node_glass.outputs["BSDF"], node_out.inputs["Surface"])
+ node_glass.inputs["IOR"].default_value = 1.33
+
+ # Add Absorption
+ node_absorption = nodes.new(type='ShaderNodeVolumeAbsorption')
+ node_absorption.location = grid_location(4, 2)
+ links.new(node_absorption.outputs["Volume"], node_out.inputs["Volume"])
+ node_absorption.inputs["Color"].default_value = (0.8, 0.9, 1.0, 1.0)
if self.start_baking:
bpy.ops.fluid.bake('INVOKE_DEFAULT')
diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py
index dbc9461ad5a..6e2dad079ee 100644
--- a/release/scripts/startup/bl_operators/object_randomize_transform.py
+++ b/release/scripts/startup/bl_operators/object_randomize_transform.py
@@ -103,25 +103,25 @@ class RandomizeLocRotSize(Operator):
bl_label = "Randomize Transform"
bl_options = {'REGISTER', 'UNDO'}
- random_seed = IntProperty(
+ random_seed: IntProperty(
name="Random Seed",
description="Seed value for the random generator",
min=0,
max=10000,
default=0,
)
- use_delta = BoolProperty(
+ use_delta: BoolProperty(
name="Transform Delta",
description=("Randomize delta transform values "
"instead of regular transform"),
default=False,
)
- use_loc = BoolProperty(
+ use_loc: BoolProperty(
name="Randomize Location",
description="Randomize the location values",
default=True,
)
- loc = FloatVectorProperty(
+ loc: FloatVectorProperty(
name="Location",
description=("Maximum distance the objects "
"can spread over each axis"),
@@ -130,12 +130,12 @@ class RandomizeLocRotSize(Operator):
default=(0.0, 0.0, 0.0),
subtype='TRANSLATION',
)
- use_rot = BoolProperty(
+ use_rot: BoolProperty(
name="Randomize Rotation",
description="Randomize the rotation values",
default=True,
)
- rot = FloatVectorProperty(
+ rot: FloatVectorProperty(
name="Rotation",
description="Maximum rotation over each axis",
min=-3.141592, # math.pi
@@ -143,25 +143,25 @@ class RandomizeLocRotSize(Operator):
default=(0.0, 0.0, 0.0),
subtype='EULER',
)
- use_scale = BoolProperty(
+ use_scale: BoolProperty(
name="Randomize Scale",
description="Randomize the scale values",
default=True,
)
- scale_even = BoolProperty(
+ scale_even: BoolProperty(
name="Scale Even",
description="Use the same scale value for all axis",
default=False,
)
- '''scale_min = FloatProperty(
+ '''scale_min: FloatProperty(
name="Minimun Scale Factor",
description="Lowest scale percentage possible",
min=-1.0, max=1.0, precision=3,
default=0.15,
)'''
- scale = FloatVectorProperty(
+ scale: FloatVectorProperty(
name="Scale",
description="Maximum scale randomization over each axis",
min=-100.0,
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 8852bca971d..530194e5bb7 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -19,9 +19,16 @@
# <pep8 compliant>
import bpy
-from bpy.types import Menu, Operator
+from bpy.types import Menu, Operator, Panel, WindowManager
from bpy.props import StringProperty, BoolProperty
+# For preset popover menu
+WindowManager.preset_name = StringProperty(
+ name="Preset Name",
+ description="Name for new preset",
+ default="New Preset"
+)
+
class AddPresetBase:
"""Base preset class, only for subclassing
@@ -34,22 +41,20 @@ class AddPresetBase:
# only because invoke_props_popup requires. Also do not add to search menu.
bl_options = {'REGISTER', 'INTERNAL'}
- name = StringProperty(
+ name: StringProperty(
name="Name",
description="Name of the preset, used to make the path name",
maxlen=64,
options={'SKIP_SAVE'},
)
- remove_active = BoolProperty(
+ remove_name: BoolProperty(
+ default=False,
+ options={'HIDDEN', 'SKIP_SAVE'},
+ )
+ remove_active: BoolProperty(
default=False,
options={'HIDDEN', 'SKIP_SAVE'},
)
-
- # needed for mix-ins
- order = [
- "name",
- "remove_active",
- ]
@staticmethod
def as_filename(name): # could reuse for other presets
@@ -85,11 +90,17 @@ class AddPresetBase:
else:
ext = ".py"
- if not self.remove_active:
- name = self.name.strip()
+ name = self.name.strip()
+ if not (self.remove_name or self.remove_active):
+
if not name:
return {'FINISHED'}
+ # Reset preset name
+ wm = bpy.data.window_managers[0]
+ if name == wm.preset_name:
+ wm.preset_name = 'New Preset'
+
filename = self.as_filename(name)
target_path = os.path.join("presets", self.preset_subdir)
@@ -155,15 +166,16 @@ class AddPresetBase:
preset_menu_class.bl_label = bpy.path.display_name(filename)
else:
- preset_active = preset_menu_class.bl_label
+ if self.remove_active:
+ name = preset_menu_class.bl_label
# fairly sloppy but convenient.
- filepath = bpy.utils.preset_find(preset_active,
+ filepath = bpy.utils.preset_find(name,
self.preset_subdir,
ext=ext)
if not filepath:
- filepath = bpy.utils.preset_find(preset_active,
+ filepath = bpy.utils.preset_find(name,
self.preset_subdir,
display_name=True,
ext=ext)
@@ -194,7 +206,7 @@ class AddPresetBase:
self.name = self.as_filename(self.name.strip())
def invoke(self, context, event):
- if not self.remove_active:
+ if not (self.remove_active or self.remove_name):
wm = context.window_manager
return wm.invoke_props_dialog(self)
else:
@@ -206,11 +218,11 @@ class ExecutePreset(Operator):
bl_idname = "script.execute_preset"
bl_label = "Execute a Python Preset"
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
options={'SKIP_SAVE'},
)
- menu_idname = StringProperty(
+ menu_idname: StringProperty(
name="Menu ID Name",
description="ID name of the menu this was called from",
options={'SKIP_SAVE'},
@@ -241,18 +253,51 @@ class ExecutePreset(Operator):
return {'FINISHED'}
+class PresetMenu(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'HEADER'
+ bl_label = "Presets"
+ path_menu: Menu.path_menu
+
+ @classmethod
+ def draw_panel_header(cls, layout):
+ layout.emboss = 'NONE'
+ layout.popover(
+ panel=cls.__name__,
+ icon='PRESET',
+ text="",
+ )
+
+ @classmethod
+ def draw_menu(cls, layout, text=None):
+ if text is None:
+ text = cls.bl_label
+
+ layout.popover(
+ panel=cls.__name__,
+ icon='PRESET',
+ text=text,
+ )
+
+ def draw(self, context):
+ layout = self.layout
+ layout.emboss = 'PULLDOWN_MENU'
+ layout.operator_context = 'EXEC_DEFAULT'
+
+ Menu.draw_preset(self, context)
+
+
class AddPresetRender(AddPresetBase, Operator):
"""Add or remove a Render Preset"""
bl_idname = "render.preset_add"
bl_label = "Add Render Preset"
- preset_menu = "RENDER_MT_presets"
+ preset_menu = "RENDER_PT_presets"
preset_defines = [
"scene = bpy.context.scene"
]
preset_values = [
- "scene.render.field_order",
"scene.render.fps",
"scene.render.fps_base",
"scene.render.pixel_aspect_x",
@@ -260,8 +305,6 @@ class AddPresetRender(AddPresetBase, Operator):
"scene.render.resolution_percentage",
"scene.render.resolution_x",
"scene.render.resolution_y",
- "scene.render.use_fields",
- "scene.render.use_fields_still",
]
preset_subdir = "render"
@@ -271,7 +314,7 @@ class AddPresetCamera(AddPresetBase, Operator):
"""Add or remove a Camera Preset"""
bl_idname = "camera.preset_add"
bl_label = "Add Camera Preset"
- preset_menu = "CAMERA_MT_presets"
+ preset_menu = "CAMERA_PT_presets"
preset_defines = [
"cam = bpy.context.camera"
@@ -279,7 +322,7 @@ class AddPresetCamera(AddPresetBase, Operator):
preset_subdir = "camera"
- use_focal_length = BoolProperty(
+ use_focal_length: BoolProperty(
name="Include Focal Length",
description="Include focal length into the preset",
options={'SKIP_SAVE'},
@@ -302,7 +345,7 @@ class AddPresetSafeAreas(AddPresetBase, Operator):
"""Add or remove a Safe Areas Preset"""
bl_idname = "safe_areas.preset_add"
bl_label = "Add Safe Area Preset"
- preset_menu = "SAFE_AREAS_MT_presets"
+ preset_menu = "SAFE_AREAS_PT_presets"
preset_defines = [
"safe_areas = bpy.context.scene.safe_areas"
@@ -318,39 +361,11 @@ class AddPresetSafeAreas(AddPresetBase, Operator):
preset_subdir = "safe_areas"
-class AddPresetSSS(AddPresetBase, Operator):
- """Add or remove a Subsurface Scattering Preset"""
- bl_idname = "material.sss_preset_add"
- bl_label = "Add SSS Preset"
- preset_menu = "MATERIAL_MT_sss_presets"
-
- preset_defines = [
- ("material = "
- "bpy.context.material.active_node_material "
- "if bpy.context.material.active_node_material "
- "else bpy.context.material")
- ]
-
- preset_values = [
- "material.subsurface_scattering.back",
- "material.subsurface_scattering.color",
- "material.subsurface_scattering.color_factor",
- "material.subsurface_scattering.error_threshold",
- "material.subsurface_scattering.front",
- "material.subsurface_scattering.ior",
- "material.subsurface_scattering.radius",
- "material.subsurface_scattering.scale",
- "material.subsurface_scattering.texture_factor",
- ]
-
- preset_subdir = "sss"
-
-
class AddPresetCloth(AddPresetBase, Operator):
"""Add or remove a Cloth Preset"""
bl_idname = "cloth.preset_add"
bl_label = "Add Cloth Preset"
- preset_menu = "CLOTH_MT_presets"
+ preset_menu = "CLOTH_PT_presets"
preset_defines = [
"cloth = bpy.context.cloth"
@@ -372,7 +387,7 @@ class AddPresetFluid(AddPresetBase, Operator):
"""Add or remove a Fluid Preset"""
bl_idname = "fluid.preset_add"
bl_label = "Add Fluid Preset"
- preset_menu = "FLUID_MT_presets"
+ preset_menu = "FLUID_PT_presets"
preset_defines = [
"fluid = bpy.context.fluid"
@@ -390,7 +405,7 @@ class AddPresetHairDynamics(AddPresetBase, Operator):
"""Add or remove a Hair Dynamics Preset"""
bl_idname = "particle.hair_dynamics_preset_add"
bl_label = "Add Hair Dynamics Preset"
- preset_menu = "PARTICLE_MT_hair_dynamics_presets"
+ preset_menu = "PARTICLE_PT_hair_dynamics_presets"
preset_defines = [
"psys = bpy.context.particle_system",
@@ -416,35 +431,6 @@ class AddPresetHairDynamics(AddPresetBase, Operator):
]
-class AddPresetSunSky(AddPresetBase, Operator):
- """Add or remove a Sky & Atmosphere Preset"""
- bl_idname = "lamp.sunsky_preset_add"
- bl_label = "Add Sunsky Preset"
- preset_menu = "LAMP_MT_sunsky_presets"
-
- preset_defines = [
- "sky = bpy.context.lamp.sky"
- ]
-
- preset_values = [
- "sky.atmosphere_extinction",
- "sky.atmosphere_inscattering",
- "sky.atmosphere_turbidity",
- "sky.backscattered_light",
- "sky.horizon_brightness",
- "sky.spread",
- "sky.sun_brightness",
- "sky.sun_intensity",
- "sky.sun_size",
- "sky.sky_blend",
- "sky.sky_blend_type",
- "sky.sky_color_space",
- "sky.sky_exposure",
- ]
-
- preset_subdir = "sunsky"
-
-
class AddPresetInteraction(AddPresetBase, Operator):
"""Add or remove an Application Interaction Preset"""
bl_idname = "wm.interaction_preset_add"
@@ -475,7 +461,7 @@ class AddPresetTrackingCamera(AddPresetBase, Operator):
"""Add or remove a Tracking Camera Intrinsics Preset"""
bl_idname = "clip.camera_preset_add"
bl_label = "Add Camera Preset"
- preset_menu = "CLIP_MT_camera_presets"
+ preset_menu = "CLIP_PT_camera_presets"
preset_defines = [
"camera = bpy.context.edit_movieclip.tracking.camera"
@@ -483,7 +469,7 @@ class AddPresetTrackingCamera(AddPresetBase, Operator):
preset_subdir = "tracking_camera"
- use_focal_length = BoolProperty(
+ use_focal_length: BoolProperty(
name="Include Focal Length",
description="Include focal length into the preset",
options={'SKIP_SAVE'},
@@ -509,7 +495,7 @@ class AddPresetTrackingTrackColor(AddPresetBase, Operator):
"""Add or remove a Clip Track Color Preset"""
bl_idname = "clip.track_color_preset_add"
bl_label = "Add Track Color Preset"
- preset_menu = "CLIP_MT_track_color_presets"
+ preset_menu = "CLIP_PT_track_color_presets"
preset_defines = [
"track = bpy.context.edit_movieclip.tracking.tracks.active"
@@ -527,7 +513,7 @@ class AddPresetTrackingSettings(AddPresetBase, Operator):
"""Add or remove a motion tracking settings preset"""
bl_idname = "clip.tracking_settings_preset_add"
bl_label = "Add Tracking Settings Preset"
- preset_menu = "CLIP_MT_tracking_settings_presets"
+ preset_menu = "CLIP_PT_tracking_settings_presets"
preset_defines = [
"settings = bpy.context.edit_movieclip.tracking.settings"
@@ -557,7 +543,7 @@ class AddPresetNodeColor(AddPresetBase, Operator):
"""Add or remove a Node Color Preset"""
bl_idname = "node.node_color_preset_add"
bl_label = "Add Node Color Preset"
- preset_menu = "NODE_MT_node_color_presets"
+ preset_menu = "NODE_PT_node_color_presets"
preset_defines = [
"node = bpy.context.active_node"
@@ -608,7 +594,7 @@ class AddPresetOperator(AddPresetBase, Operator):
bl_label = "Operator Preset"
preset_menu = "WM_MT_operator_presets"
- operator = StringProperty(
+ operator: StringProperty(
name="Operator",
maxlen=64,
options={'HIDDEN', 'SKIP_SAVE'},
@@ -670,7 +656,7 @@ class AddPresetUnitsLength(AddPresetBase, Operator):
"""Add or remove length units preset"""
bl_idname = "scene.units_length_preset_add"
bl_label = "Add Length Units Preset"
- preset_menu = "SCENE_MT_units_length_presets"
+ preset_menu = "SCENE_PT_units_length_presets"
preset_defines = [
"scene = bpy.context.scene"
@@ -695,9 +681,7 @@ classes = (
AddPresetNodeColor,
AddPresetOperator,
AddPresetRender,
- AddPresetSSS,
AddPresetSafeAreas,
- AddPresetSunSky,
AddPresetTrackingCamera,
AddPresetTrackingSettings,
AddPresetTrackingTrackColor,
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 8fbc9b29b46..36150a63895 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -65,7 +65,7 @@ class CopyRigidbodySettings(Operator):
# deselect all but mesh objects
for o in context.selected_objects:
if o.type != 'MESH':
- o.select = False
+ o.select_set(action='DESELECT')
elif o.rigid_body is None:
# Add rigidbody to object!
scene.objects.active = o
@@ -92,19 +92,19 @@ class BakeToKeyframes(Operator):
bl_label = "Bake To Keyframes"
bl_options = {'REGISTER', 'UNDO'}
- frame_start = IntProperty(
+ frame_start: IntProperty(
name="Start Frame",
description="Start frame for baking",
min=0, max=300000,
default=1,
)
- frame_end = IntProperty(
+ frame_end: IntProperty(
name="End Frame",
description="End frame for baking",
min=1, max=300000,
default=250,
)
- step = IntProperty(
+ step: IntProperty(
name="Frame Step",
description="Frame Step",
min=1, max=120,
@@ -127,7 +127,7 @@ class BakeToKeyframes(Operator):
# filter objects selection
for obj in context.selected_objects:
if not obj.rigid_body or obj.rigid_body.type != 'ACTIVE':
- obj.select = False
+ obj.select_set(action='DESELECT')
objects = context.selected_objects
@@ -216,7 +216,7 @@ class ConnectRigidBodies(Operator):
bl_label = "Connect Rigid Bodies"
bl_options = {'REGISTER', 'UNDO'}
- con_type = EnumProperty(
+ con_type: EnumProperty(
name="Type",
description="Type of generated constraint",
# XXX Would be nice to get icons too, but currently not possible ;)
@@ -226,7 +226,7 @@ class ConnectRigidBodies(Operator):
),
default='FIXED',
)
- pivot_type = EnumProperty(
+ pivot_type: EnumProperty(
name="Location",
description="Constraint pivot location",
items=(
@@ -236,7 +236,7 @@ class ConnectRigidBodies(Operator):
),
default='CENTER',
)
- connection_pattern = EnumProperty(
+ connection_pattern: EnumProperty(
name="Connection Pattern",
description="Pattern used to connect objects",
items=(
@@ -266,7 +266,7 @@ class ConnectRigidBodies(Operator):
ob.location = loc
context.scene.objects.link(ob)
context.scene.objects.active = ob
- ob.select = True
+ ob.select_set(action='SELECT')
bpy.ops.rigidbody.constraint_add()
con_obj = context.active_object
@@ -311,7 +311,7 @@ class ConnectRigidBodies(Operator):
# restore selection
bpy.ops.object.select_all(action='DESELECT')
for obj in objects:
- obj.select = True
+ obj.select_set(action='SELECT')
scene.objects.active = obj_act
return {'FINISHED'}
else:
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index c9a7aa93805..b1152157cf8 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -82,7 +82,7 @@ class SequencerCutMulticam(Operator):
bl_label = "Cut multicam"
bl_options = {'REGISTER', 'UNDO'}
- camera = IntProperty(
+ camera: IntProperty(
name="Camera",
min=1, max=32,
soft_min=1, soft_max=32,
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index 72445be6950..5c870849cc5 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -30,8 +30,8 @@ def extend(obj, operator, EXTEND_MODE):
import bmesh
me = obj.data
# script will fail without UVs
- if not me.uv_textures:
- me.uv_textures.new()
+ if not me.uv_layers:
+ me.uv_layers.new()
bm = bmesh.from_edit_mesh(me)
@@ -226,7 +226,7 @@ class FollowActiveQuads(Operator):
bl_label = "Follow Active Quads"
bl_options = {'REGISTER', 'UNDO'}
- mode = bpy.props.EnumProperty(
+ mode: bpy.props.EnumProperty(
name="Edge Length Mode",
description="Method to space UV edge loops",
items=(('EVEN', "Even", "Space all UVs evenly"),
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index 0b0dd58e80f..95a3d18304b 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -275,12 +275,12 @@ def lightmap_uvpack(meshes,
face_groups.append(faces)
if PREF_NEW_UVLAYER:
- me.uv_textures.new()
+ me.uv_layers.new()
# Add face UV if it does not exist.
# All new faces are selected.
- if not me.uv_textures:
- me.uv_textures.new()
+ if not me.uv_layers:
+ me.uv_layers.new()
for face_sel in face_groups:
print("\nStarting unwrap")
@@ -538,6 +538,9 @@ def lightmap_uvpack(meshes,
print("done")
if PREF_APPLY_IMAGE:
+ pass
+ # removed with texface
+ '''
if not PREF_PACK_IN_ONE:
image = bpy.data.images.new(name="lightmap",
width=PREF_IMG_PX_SIZE,
@@ -545,8 +548,8 @@ def lightmap_uvpack(meshes,
)
for f in face_sel:
- # f.image = image
- f.id_data.uv_textures.active.data[f.index].image = image # XXX25
+ f.image = image
+ '''
for me in meshes:
me.update()
@@ -613,7 +616,7 @@ class LightMapPack(Operator):
# This fixes infinite image creation reported there [#30968] (sergey)
bl_options = {'UNDO'}
- PREF_CONTEXT = bpy.props.EnumProperty(
+ PREF_CONTEXT: bpy.props.EnumProperty(
name="Selection",
items=(
('SEL_FACES', "Selected Faces", "Space all UVs evenly"),
@@ -623,7 +626,7 @@ class LightMapPack(Operator):
)
# Image & UVs...
- PREF_PACK_IN_ONE = BoolProperty(
+ PREF_PACK_IN_ONE: BoolProperty(
name="Share Tex Space",
description=(
"Objects Share texture space, map all objects "
@@ -631,12 +634,12 @@ class LightMapPack(Operator):
),
default=True,
)
- PREF_NEW_UVLAYER = BoolProperty(
+ PREF_NEW_UVLAYER: BoolProperty(
name="New UV Map",
description="Create a new UV map for every mesh packed",
default=False,
)
- PREF_APPLY_IMAGE = BoolProperty(
+ PREF_APPLY_IMAGE: BoolProperty(
name="New Image",
description=(
"Assign new images for every mesh (only one if "
@@ -644,20 +647,20 @@ class LightMapPack(Operator):
),
default=False,
)
- PREF_IMG_PX_SIZE = IntProperty(
+ PREF_IMG_PX_SIZE: IntProperty(
name="Image Size",
description="Width and Height for the new image",
min=64, max=5000,
default=512,
)
# UV Packing...
- PREF_BOX_DIV = IntProperty(
+ PREF_BOX_DIV: IntProperty(
name="Pack Quality",
description="Pre Packing before the complex boxpack",
min=1, max=48,
default=12,
)
- PREF_MARGIN_DIV = FloatProperty(
+ PREF_MARGIN_DIV: FloatProperty(
name="Margin",
description="Size of the margin as a division of the UV",
min=0.001, max=1.0,
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index f0b1f934e38..fe15b9fa345 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -816,8 +816,8 @@ def main(context,
# Tag as used
me.tag = True
- if not me.uv_textures: # Mesh has no UV Coords, don't bother.
- me.uv_textures.new()
+ if not me.uv_layers: # Mesh has no UV Coords, don't bother.
+ me.uv_layers.new()
uv_layer = me.uv_layers.active.data
me_verts = list(me.vertices)
@@ -1055,31 +1055,31 @@ class SmartProject(Operator):
bl_label = "Smart UV Project"
bl_options = {'REGISTER', 'UNDO'}
- angle_limit = FloatProperty(
+ angle_limit: FloatProperty(
name="Angle Limit",
description="Lower for more projection groups, higher for less distortion",
min=1.0, max=89.0,
default=66.0,
)
- island_margin = FloatProperty(
+ island_margin: FloatProperty(
name="Island Margin",
description="Margin to reduce bleed from adjacent islands",
unit='LENGTH', subtype='DISTANCE',
min=0.0, max=1.0,
default=0.0,
)
- user_area_weight = FloatProperty(
+ user_area_weight: FloatProperty(
name="Area Weight",
description="Weight projections vector by faces with larger areas",
min=0.0, max=1.0,
default=0.0,
)
- use_aspect = BoolProperty(
+ use_aspect: BoolProperty(
name="Correct Aspect",
description="Map UVs taking image aspect ratio into account",
default=True
)
- stretch_to_bounds = BoolProperty(
+ stretch_to_bounds: BoolProperty(
name="Stretch to UV Bounds",
description="Stretch the final output to texture bounds",
default=True,
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 1173e0047bb..335c3d8bbda 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -138,33 +138,33 @@ class VertexPaintDirt(Operator):
bl_label = "Dirty Vertex Colors"
bl_options = {'REGISTER', 'UNDO'}
- blur_strength = FloatProperty(
+ blur_strength: FloatProperty(
name="Blur Strength",
description="Blur strength per iteration",
min=0.01, max=1.0,
default=1.0,
)
- blur_iterations = IntProperty(
+ blur_iterations: IntProperty(
name="Blur Iterations",
description="Number of times to blur the colors (higher blurs more)",
min=0, max=40,
default=1,
)
- clean_angle = FloatProperty(
+ clean_angle: FloatProperty(
name="Highlight Angle",
description="Less than 90 limits the angle used in the tonal range",
min=0.0, max=pi,
default=pi,
unit="ROTATION",
)
- dirt_angle = FloatProperty(
+ dirt_angle: FloatProperty(
name="Dirt Angle",
description="Less than 90 limits the angle used in the tonal range",
min=0.0, max=pi,
default=0.0,
unit="ROTATION",
)
- dirt_only = BoolProperty(
+ dirt_only: BoolProperty(
name="Dirt Only",
description="Don't calculate cleans for convex areas",
default=False,
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index f56c83be7d1..b43f4446802 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -143,37 +143,37 @@ class VIEW3D_OT_select_or_deselect_all(Operator):
bl_idname = "view3d.select_or_deselect_all"
bl_options = {'UNDO'}
- extend = BoolProperty(
+ extend: BoolProperty(
name="Extend",
description="Extend selection instead of deselecting everything first",
default=False,
)
- toggle = BoolProperty(
+ toggle: BoolProperty(
name="Toggle",
description="Toggle the selection",
default=False,
)
- deselect = BoolProperty(
+ deselect: BoolProperty(
name="Deselect",
description="Remove from selection",
default=False,
)
- center = BoolProperty(
+ center: BoolProperty(
name="Center",
description="Use the object center when selecting, in editmode used to extend object selection",
default=False,
)
- enumerate = BoolProperty(
+ enumerate: BoolProperty(
name="Enumerate",
description="List objects under the mouse (object mode only)",
default=False,
)
- object = BoolProperty(
+ object: BoolProperty(
name="Object",
description="Use object selection (editmode only)",
default=False,
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 5b12f6196a4..fe367973323 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -19,13 +19,17 @@
# <pep8 compliant>
import bpy
-from bpy.types import Operator
+from bpy.types import (
+ Operator,
+ OperatorFileListElement
+)
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
StringProperty,
+ CollectionProperty,
)
from bpy.app.translations import pgettext_tip as tip_
@@ -55,6 +59,15 @@ rna_relative_prop = BoolProperty(
default=False,
)
+rna_space_type_prop = EnumProperty(
+ name="Type",
+ items=tuple(
+ (e.identifier, e.name, "", e. value)
+ for e in bpy.types.Space.bl_rna.properties["type"].enum_items
+ ),
+ default='EMPTY',
+)
+
def context_path_validate(context, data_path):
try:
@@ -149,12 +162,12 @@ class BRUSH_OT_active_index_set(Operator):
bl_idname = "brush.active_index_set"
bl_label = "Set Brush Number"
- mode = StringProperty(
+ mode: StringProperty(
name="Mode",
description="Paint mode to set brush for",
maxlen=1024,
)
- index = IntProperty(
+ index: IntProperty(
name="Number",
description="Brush number",
)
@@ -186,8 +199,8 @@ class WM_OT_context_set_boolean(Operator):
bl_label = "Context Set Boolean"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = BoolProperty(
+ data_path: rna_path_prop
+ value: BoolProperty(
name="Value",
description="Assignment value",
default=True,
@@ -202,13 +215,13 @@ class WM_OT_context_set_int(Operator): # same as enum
bl_label = "Context Set"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = IntProperty(
+ data_path: rna_path_prop
+ value: IntProperty(
name="Value",
description="Assign value",
default=0,
)
- relative = rna_relative_prop
+ relative: rna_relative_prop
execute = execute_context_assign
@@ -219,8 +232,8 @@ class WM_OT_context_scale_float(Operator):
bl_label = "Context Scale Float"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = FloatProperty(
+ data_path: rna_path_prop
+ value: FloatProperty(
name="Value",
description="Assign value",
default=1.0,
@@ -247,13 +260,13 @@ class WM_OT_context_scale_int(Operator):
bl_label = "Context Scale Int"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = FloatProperty(
+ data_path: rna_path_prop
+ value: FloatProperty(
name="Value",
description="Assign value",
default=1.0,
)
- always_step = BoolProperty(
+ always_step: BoolProperty(
name="Always Step",
description="Always adjust the value by a minimum of 1 when 'value' is not 1.0",
default=True,
@@ -290,13 +303,13 @@ class WM_OT_context_set_float(Operator): # same as enum
bl_label = "Context Set Float"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = FloatProperty(
+ data_path: rna_path_prop
+ value: FloatProperty(
name="Value",
description="Assignment value",
default=0.0,
)
- relative = rna_relative_prop
+ relative: rna_relative_prop
execute = execute_context_assign
@@ -307,8 +320,8 @@ class WM_OT_context_set_string(Operator): # same as enum
bl_label = "Context Set String"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = StringProperty(
+ data_path: rna_path_prop
+ value: StringProperty(
name="Value",
description="Assign value",
maxlen=1024,
@@ -323,8 +336,8 @@ class WM_OT_context_set_enum(Operator):
bl_label = "Context Set Enum"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = StringProperty(
+ data_path: rna_path_prop
+ value: StringProperty(
name="Value",
description="Assignment value (as a string)",
maxlen=1024,
@@ -339,8 +352,8 @@ class WM_OT_context_set_value(Operator):
bl_label = "Context Set Value"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = StringProperty(
+ data_path: rna_path_prop
+ value: StringProperty(
name="Value",
description="Assignment value (as a string)",
maxlen=1024,
@@ -360,7 +373,7 @@ class WM_OT_context_toggle(Operator):
bl_label = "Context Toggle"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
+ data_path: rna_path_prop
def execute(self, context):
data_path = self.data_path
@@ -379,13 +392,13 @@ class WM_OT_context_toggle_enum(Operator):
bl_label = "Context Toggle Values"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value_1 = StringProperty(
+ data_path: rna_path_prop
+ value_1: StringProperty(
name="Value",
description="Toggle enum",
maxlen=1024,
)
- value_2 = StringProperty(
+ value_2: StringProperty(
name="Value",
description="Toggle enum",
maxlen=1024,
@@ -418,9 +431,9 @@ class WM_OT_context_cycle_int(Operator):
bl_label = "Context Int Cycle"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- reverse = rna_reverse_prop
- wrap = rna_wrap_prop
+ data_path: rna_path_prop
+ reverse: rna_reverse_prop
+ wrap: rna_wrap_prop
def execute(self, context):
data_path = self.data_path
@@ -454,9 +467,9 @@ class WM_OT_context_cycle_enum(Operator):
bl_label = "Context Enum Cycle"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- reverse = rna_reverse_prop
- wrap = rna_wrap_prop
+ data_path: rna_path_prop
+ reverse: rna_reverse_prop
+ wrap: rna_wrap_prop
def execute(self, context):
data_path = self.data_path
@@ -511,8 +524,8 @@ class WM_OT_context_cycle_array(Operator):
bl_label = "Context Array Cycle"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- reverse = rna_reverse_prop
+ data_path: rna_path_prop
+ reverse: rna_reverse_prop
def execute(self, context):
data_path = self.data_path
@@ -536,7 +549,8 @@ class WM_OT_context_menu_enum(Operator):
bl_idname = "wm.context_menu_enum"
bl_label = "Context Enum Menu"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
+
+ data_path: rna_path_prop
def execute(self, context):
data_path = self.data_path
@@ -562,7 +576,8 @@ class WM_OT_context_pie_enum(Operator):
bl_idname = "wm.context_pie_enum"
bl_label = "Context Enum Pie"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
+
+ data_path: rna_path_prop
def invoke(self, context, event):
wm = context.window_manager
@@ -589,12 +604,13 @@ class WM_OT_operator_pie_enum(Operator):
bl_idname = "wm.operator_pie_enum"
bl_label = "Operator Enum Pie"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = StringProperty(
+
+ data_path: StringProperty(
name="Operator",
description="Operator name (in python as string)",
maxlen=1024,
)
- prop_string = StringProperty(
+ prop_string: StringProperty(
name="Property",
description="Property name (as a string)",
maxlen=1024,
@@ -633,8 +649,8 @@ class WM_OT_context_set_id(Operator):
bl_label = "Set Library ID"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path_prop
- value = StringProperty(
+ data_path: rna_path_prop
+ value: StringProperty(
name="Value",
description="Assign value",
maxlen=1024,
@@ -684,10 +700,10 @@ class WM_OT_context_collection_boolean_set(Operator):
bl_label = "Context Collection Boolean Set"
bl_options = {'UNDO', 'REGISTER', 'INTERNAL'}
- data_path_iter = data_path_iter
- data_path_item = data_path_item
+ data_path_iter: data_path_iter
+ data_path_item: data_path_item
- type = EnumProperty(
+ type: EnumProperty(
name="Type",
items=(('TOGGLE', "Toggle", ""),
('ENABLE', "Enable", ""),
@@ -743,22 +759,22 @@ class WM_OT_context_modal_mouse(Operator):
bl_label = "Context Modal Mouse"
bl_options = {'GRAB_CURSOR', 'BLOCKING', 'UNDO', 'INTERNAL'}
- data_path_iter = data_path_iter
- data_path_item = data_path_item
- header_text = StringProperty(
+ data_path_iter: data_path_iter
+ data_path_item: data_path_item
+ header_text: StringProperty(
name="Header Text",
description="Text to display in header during scale",
)
- input_scale = FloatProperty(
+ input_scale: FloatProperty(
description="Scale the mouse movement by this value before applying the delta",
default=0.01,
)
- invert = BoolProperty(
+ invert: BoolProperty(
description="Invert the mouse input",
default=False,
)
- initial_x = IntProperty(options={'HIDDEN'})
+ initial_x: IntProperty(options={'HIDDEN'})
def _values_store(self, context):
data_path_iter = self.data_path_iter
@@ -851,7 +867,7 @@ class WM_OT_url_open(Operator):
bl_label = ""
bl_options = {'INTERNAL'}
- url = StringProperty(
+ url: StringProperty(
name="URL",
description="URL to open",
)
@@ -868,7 +884,7 @@ class WM_OT_path_open(Operator):
bl_label = ""
bl_options = {'INTERNAL'}
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
options={'SKIP_SAVE'},
)
@@ -983,7 +999,7 @@ class WM_OT_doc_view_manual(Operator):
bl_idname = "wm.doc_view_manual"
bl_label = "View Manual"
- doc_id = doc_id
+ doc_id: doc_id
@staticmethod
def _find_reference(rna_id, url_mapping, verbose=True):
@@ -1037,7 +1053,7 @@ class WM_OT_doc_view(Operator):
bl_idname = "wm.doc_view"
bl_label = "View Documentation"
- doc_id = doc_id
+ doc_id: doc_id
if bpy.app.version_cycle == "release":
_prefix = ("https://docs.blender.org/api/blender_python_api_current")
else:
@@ -1089,6 +1105,11 @@ rna_use_soft_limits = BoolProperty(
name="Use Soft Limits",
)
+rna_is_overridable_static = BoolProperty(
+ name="Is Statically Overridable",
+ default=False,
+)
+
class WM_OT_properties_edit(Operator):
bl_idname = "wm.properties_edit"
@@ -1096,15 +1117,16 @@ class WM_OT_properties_edit(Operator):
# register only because invoke_props_popup requires.
bl_options = {'REGISTER', 'INTERNAL'}
- data_path = rna_path
- property = rna_property
- value = rna_value
- min = rna_min
- max = rna_max
- use_soft_limits = rna_use_soft_limits
- soft_min = rna_min
- soft_max = rna_max
- description = StringProperty(
+ data_path: rna_path
+ property: rna_property
+ value: rna_value
+ min: rna_min
+ max: rna_max
+ use_soft_limits: rna_use_soft_limits
+ is_overridable_static: rna_is_overridable_static
+ soft_min: rna_min
+ soft_max: rna_max
+ description: StringProperty(
name="Tooltip",
)
@@ -1154,6 +1176,9 @@ class WM_OT_properties_edit(Operator):
# print(exec_str)
exec(exec_str)
+ exec_str = "item.property_overridable_static_set('[\"%s\"]', %s)" % (prop, self.is_overridable_static)
+ exec(exec_str)
+
rna_idprop_ui_prop_update(item, prop)
self._last_prop[:] = [prop]
@@ -1281,7 +1306,9 @@ class WM_OT_properties_edit(Operator):
row.prop(self, "min")
row.prop(self, "max")
- layout.prop(self, "use_soft_limits")
+ row = layout.row()
+ row.prop(self, "use_soft_limits")
+ row.prop(self, "is_overridable_static")
row = layout.row(align=True)
row.enabled = self.use_soft_limits
@@ -1295,7 +1322,7 @@ class WM_OT_properties_add(Operator):
bl_label = "Add Property"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path
+ data_path: rna_path
def execute(self, context):
from rna_prop_ui import (
@@ -1338,7 +1365,7 @@ class WM_OT_properties_context_change(Operator):
bl_label = ""
bl_options = {'INTERNAL'}
- context = StringProperty(
+ context: StringProperty(
name="Context",
maxlen=64,
)
@@ -1354,8 +1381,8 @@ class WM_OT_properties_remove(Operator):
bl_label = "Remove Property"
bl_options = {'UNDO', 'INTERNAL'}
- data_path = rna_path
- property = rna_property
+ data_path: rna_path
+ property: rna_property
def execute(self, context):
from rna_prop_ui import (
@@ -1376,7 +1403,7 @@ class WM_OT_keyconfig_activate(Operator):
bl_idname = "wm.keyconfig_activate"
bl_label = "Activate Keyconfig"
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
@@ -1411,7 +1438,7 @@ class WM_OT_appconfig_activate(Operator):
bl_idname = "wm.appconfig_activate"
bl_label = "Activate Application Configuration"
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
@@ -1436,7 +1463,7 @@ class WM_OT_sysinfo(Operator):
bl_idname = "wm.sysinfo"
bl_label = "Save System Info"
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
options={'SKIP_SAVE'},
)
@@ -1492,54 +1519,6 @@ class WM_OT_copy_prev_settings(Operator):
return {'CANCELLED'}
-class WM_OT_blenderplayer_start(Operator):
- """Launch the blender-player with the current blend-file"""
- bl_idname = "wm.blenderplayer_start"
- bl_label = "Start Game In Player"
-
- def execute(self, context):
- import os
- import sys
- import subprocess
-
- gs = context.scene.game_settings
-
- # these remain the same every execution
- blender_bin_path = bpy.app.binary_path
- blender_bin_dir = os.path.dirname(blender_bin_path)
- ext = os.path.splitext(blender_bin_path)[-1]
- player_path = os.path.join(blender_bin_dir, "blenderplayer" + ext)
- # done static vars
-
- if sys.platform == "darwin":
- player_path = os.path.join(blender_bin_dir, "../../../blenderplayer.app/Contents/MacOS/blenderplayer")
-
- if not os.path.exists(player_path):
- self.report({'ERROR'}, "Player path: %r not found" % player_path)
- return {'CANCELLED'}
-
- filepath = bpy.data.filepath + '~' if bpy.data.is_saved else os.path.join(bpy.app.tempdir, "game.blend")
- bpy.ops.wm.save_as_mainfile('EXEC_DEFAULT', filepath=filepath, copy=True)
-
- # start the command line call with the player path
- args = [player_path]
-
- # handle some UI options as command line arguments
- args.extend([
- "-g", "show_framerate", "=", "%d" % gs.show_framerate_profile,
- "-g", "show_profile", "=", "%d" % gs.show_framerate_profile,
- "-g", "show_properties", "=", "%d" % gs.show_debug_properties,
- "-g", "ignore_deprecation_warnings", "=", "%d" % (not gs.use_deprecation_warnings),
- ])
-
- # finish the call with the path to the blend file
- args.append(filepath)
-
- subprocess.call(args)
- os.remove(filepath)
- return {'FINISHED'}
-
-
class WM_OT_keyconfig_test(Operator):
"""Test key-config for conflicts"""
bl_idname = "wm.keyconfig_test"
@@ -1562,26 +1541,26 @@ class WM_OT_keyconfig_import(Operator):
bl_idname = "wm.keyconfig_import"
bl_label = "Import Key Configuration..."
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
default="keymap.py",
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
name="Filter folders",
default=True,
options={'HIDDEN'},
)
- filter_text = BoolProperty(
+ filter_text: BoolProperty(
name="Filter text",
default=True,
options={'HIDDEN'},
)
- filter_python = BoolProperty(
+ filter_python: BoolProperty(
name="Filter python",
default=True,
options={'HIDDEN'},
)
- keep_original = BoolProperty(
+ keep_original: BoolProperty(
name="Keep original",
description="Keep original file after copying to configuration folder",
default=True,
@@ -1629,21 +1608,21 @@ class WM_OT_keyconfig_export(Operator):
bl_idname = "wm.keyconfig_export"
bl_label = "Export Key Configuration..."
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
default="keymap.py",
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
name="Filter folders",
default=True,
options={'HIDDEN'},
)
- filter_text = BoolProperty(
+ filter_text: BoolProperty(
name="Filter text",
default=True,
options={'HIDDEN'},
)
- filter_python = BoolProperty(
+ filter_python: BoolProperty(
name="Filter python",
default=True,
options={'HIDDEN'},
@@ -1660,7 +1639,7 @@ class WM_OT_keyconfig_export(Operator):
wm = context.window_manager
- keyconfig_utils.keyconfig_export(
+ keyconfig_utils.keyconfig_export_as_data(
wm,
wm.keyconfigs.active,
self.filepath,
@@ -1679,7 +1658,7 @@ class WM_OT_keymap_restore(Operator):
bl_idname = "wm.keymap_restore"
bl_label = "Restore Key Map(s)"
- all = BoolProperty(
+ all: BoolProperty(
name="All Keymaps",
description="Restore all keymaps to default",
)
@@ -1702,7 +1681,7 @@ class WM_OT_keyitem_restore(Operator):
bl_idname = "wm.keyitem_restore"
bl_label = "Restore Key Map Item"
- item_id = IntProperty(
+ item_id: IntProperty(
name="Item Identifier",
description="Identifier of the item to remove",
)
@@ -1749,7 +1728,7 @@ class WM_OT_keyitem_remove(Operator):
bl_idname = "wm.keyitem_remove"
bl_label = "Remove Key Map Item"
- item_id = IntProperty(
+ item_id: IntProperty(
name="Item Identifier",
description="Identifier of the item to remove",
)
@@ -1817,7 +1796,7 @@ class WM_OT_addon_enable(Operator):
bl_idname = "wm.addon_enable"
bl_label = "Enable Add-on"
- module = StringProperty(
+ module: StringProperty(
name="Module",
description="Module name of the add-on to enable",
)
@@ -1863,7 +1842,7 @@ class WM_OT_addon_disable(Operator):
bl_idname = "wm.addon_disable"
bl_label = "Disable Add-on"
- module = StringProperty(
+ module: StringProperty(
name="Module",
description="Module name of the add-on to disable",
)
@@ -1887,25 +1866,56 @@ class WM_OT_addon_disable(Operator):
return {'FINISHED'}
+class WM_OT_owner_enable(Operator):
+ """Enable workspace owner ID"""
+ bl_idname = "wm.owner_enable"
+ bl_label = "Enable Add-on"
+
+ owner_id: StringProperty(
+ name="UI Tag",
+ )
+
+ def execute(self, context):
+ workspace = context.workspace
+ workspace.owner_ids.new(self.owner_id)
+ return {'FINISHED'}
+
+
+class WM_OT_owner_disable(Operator):
+ """Enable workspace owner ID"""
+ bl_idname = "wm.owner_disable"
+ bl_label = "Disable UI Tag"
+
+ owner_id: StringProperty(
+ name="UI Tag",
+ )
+
+ def execute(self, context):
+ workspace = context.workspace
+ owner_id = workspace.owner_ids[self.owner_id]
+ workspace.owner_ids.remove(owner_id)
+ return {'FINISHED'}
+
+
class WM_OT_theme_install(Operator):
"""Load and apply a Blender XML theme file"""
bl_idname = "wm.theme_install"
bl_label = "Install Theme..."
- overwrite = BoolProperty(
+ overwrite: BoolProperty(
name="Overwrite",
description="Remove existing theme file if exists",
default=True,
)
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
name="Filter folders",
default=True,
options={'HIDDEN'},
)
- filter_glob = StringProperty(
+ filter_glob: StringProperty(
default="*.xml",
options={'HIDDEN'},
)
@@ -1969,31 +1979,31 @@ class WM_OT_addon_install(Operator):
bl_idname = "wm.addon_install"
bl_label = "Install Add-on from File..."
- overwrite = BoolProperty(
+ overwrite: BoolProperty(
name="Overwrite",
description="Remove existing add-ons with the same ID",
default=True,
)
- target = EnumProperty(
+ target: EnumProperty(
name="Target Path",
items=(('DEFAULT', "Default", ""),
('PREFS', "User Prefs", "")),
)
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
name="Filter folders",
default=True,
options={'HIDDEN'},
)
- filter_python = BoolProperty(
+ filter_python: BoolProperty(
name="Filter python",
default=True,
options={'HIDDEN'},
)
- filter_glob = StringProperty(
+ filter_glob: StringProperty(
default="*.py;*.zip",
options={'HIDDEN'},
)
@@ -2123,7 +2133,7 @@ class WM_OT_addon_remove(Operator):
bl_idname = "wm.addon_remove"
bl_label = "Remove Add-on"
- module = StringProperty(
+ module: StringProperty(
name="Module",
description="Module name of the add-on to remove",
)
@@ -2183,7 +2193,7 @@ class WM_OT_addon_expand(Operator):
bl_label = ""
bl_options = {'INTERNAL'}
- module = StringProperty(
+ module: StringProperty(
name="Module",
description="Module name of the add-on to expand",
)
@@ -2207,7 +2217,7 @@ class WM_OT_addon_userpref_show(Operator):
bl_label = ""
bl_options = {'INTERNAL'}
- module = StringProperty(
+ module: StringProperty(
name="Module",
description="Module name of the add-on to expand",
)
@@ -2238,21 +2248,21 @@ class WM_OT_app_template_install(Operator):
bl_idname = "wm.app_template_install"
bl_label = "Install Template from File..."
- overwrite = BoolProperty(
+ overwrite: BoolProperty(
name="Overwrite",
description="Remove existing template with the same ID",
default=True,
)
- filepath = StringProperty(
+ filepath: StringProperty(
subtype='FILE_PATH',
)
- filter_folder = BoolProperty(
+ filter_folder: BoolProperty(
name="Filter folders",
default=True,
options={'HIDDEN'},
)
- filter_glob = StringProperty(
+ filter_glob: StringProperty(
default="*.zip",
options={'HIDDEN'},
)
@@ -2332,6 +2342,177 @@ class WM_OT_app_template_install(Operator):
return {'RUNNING_MODAL'}
+class WM_OT_tool_set_by_name(Operator):
+ """Set the tool by name (for keymaps)"""
+ bl_idname = "wm.tool_set_by_name"
+ bl_label = "Set Tool By Name"
+
+ name: StringProperty(
+ name="Text",
+ description="Display name of the tool",
+ )
+ cycle: BoolProperty(
+ name="Cycle",
+ description="Cycle through tools in this group",
+ default=False,
+ options={'SKIP_SAVE'},
+ )
+
+ space_type: rna_space_type_prop
+
+ def execute(self, context):
+ from bl_ui.space_toolsystem_common import (
+ activate_by_name,
+ activate_by_name_or_cycle,
+ )
+
+ if self.properties.is_property_set("space_type"):
+ space_type = self.space_type
+ else:
+ space_type = context.space_data.type
+
+ fn = activate_by_name_or_cycle if self.cycle else activate_by_name
+ if fn(context, space_type, self.name):
+ return {'FINISHED'}
+ else:
+ self.report({'WARNING'}, f"Tool {self.name!r} not found.")
+ return {'CANCELLED'}
+
+
+class WM_OT_toolbar(Operator):
+ bl_idname = "wm.toolbar"
+ bl_label = "Toolbar"
+
+ def execute(self, context):
+ from bl_ui.space_toolsystem_common import (
+ ToolSelectPanelHelper,
+ keymap_from_context,
+ )
+ space_type = context.space_data.type
+
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is None:
+ self.report({'WARNING'}, f"Toolbar not found for {space_type!r}")
+ return {'CANCELLED'}
+
+ wm = context.window_manager
+ keymap = keymap_from_context(context, space_type)
+
+ def draw_menu(popover, context):
+ layout = popover.layout
+
+ layout.operator_context = 'INVOKE_DEFAULT'
+ layout.operator("wm.search_menu", text="Search Commands...", icon='VIEWZOOM')
+
+ cls.draw_cls(layout, context, detect_layout=False, scale_y=1.0)
+
+ wm.popover(draw_menu, ui_units_x=8, keymap=keymap)
+ return {'FINISHED'}
+
+
+# Studio Light operations
+class WM_OT_studiolight_install(Operator):
+ """Install a user defined studio light"""
+ bl_idname = "wm.studiolight_install"
+ bl_label = "Install Custom Studio Light"
+
+ files: CollectionProperty(
+ name="File Path",
+ type=OperatorFileListElement,
+ )
+ directory: StringProperty(
+ subtype='DIR_PATH',
+ )
+ filter_folder: BoolProperty(
+ name="Filter folders",
+ default=True,
+ options={'HIDDEN'},
+ )
+ filter_glob: StringProperty(
+ default="*.png;*.jpg;*.hdr;*.exr",
+ options={'HIDDEN'},
+ )
+ orientation: EnumProperty(
+ items=(
+ ("MATCAP", "MatCap", ""),
+ ("WORLD", "World", ""),
+ ("CAMERA", "Camera", ""),
+ )
+ )
+
+ def execute(self, context):
+ import traceback
+ import shutil
+ import pathlib
+ userpref = context.user_preferences
+
+ filepaths = [pathlib.Path(self.directory, e.name) for e in self.files]
+ path_studiolights = bpy.utils.user_resource('DATAFILES')
+
+ if not path_studiolights:
+ self.report({'ERROR'}, "Failed to get Studio Light path")
+ return {'CANCELLED'}
+
+ path_studiolights = pathlib.Path(path_studiolights, "studiolights", self.orientation.lower())
+ if not path_studiolights.exists():
+ try:
+ path_studiolights.mkdir(parents=True, exist_ok=True)
+ except:
+ traceback.print_exc()
+
+ for filepath in filepaths:
+ shutil.copy(str(filepath), str(path_studiolights))
+ userpref.studio_lights.new(str(path_studiolights.joinpath(filepath.name)), self.orientation)
+
+ # print message
+ msg = (
+ tip_("StudioLight Installed %r into %r") %
+ (", ".join(str(x.name) for x in self.files), str(path_studiolights))
+ )
+ print(msg)
+ self.report({'INFO'}, msg)
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ wm.fileselect_add(self)
+ return {'RUNNING_MODAL'}
+
+
+class WM_OT_studiolight_uninstall(Operator):
+ bl_idname = 'wm.studiolight_uninstall'
+ bl_label = "Uninstall Studio Light"
+ index: bpy.props.IntProperty()
+
+ def _remove_path(self, path):
+ if path.exists():
+ path.unlink()
+
+ def execute(self, context):
+ import pathlib
+ userpref = context.user_preferences
+ for studio_light in userpref.studio_lights:
+ if studio_light.index == self.index:
+ self._remove_path(pathlib.Path(studio_light.path))
+ self._remove_path(pathlib.Path(studio_light.path_irr_cache))
+ self._remove_path(pathlib.Path(studio_light.path_sh_cache))
+ userpref.studio_lights.remove(studio_light)
+ return {'FINISHED'}
+ return {'CANCELLED'}
+
+
+class WM_OT_studiolight_userpref_show(Operator):
+ """Show light user preferences"""
+ bl_idname = "wm.studiolight_userpref_show"
+ bl_label = ""
+ bl_options = {'INTERNAL'}
+
+ def execute(self, context):
+ context.user_preferences.active_section = 'LIGHTS'
+ bpy.ops.screen.userpref_show('INVOKE_DEFAULT')
+ return {'FINISHED'}
+
+
classes = (
BRUSH_OT_active_index_set,
WM_OT_addon_disable,
@@ -2344,7 +2525,6 @@ classes = (
WM_OT_app_template_install,
WM_OT_appconfig_activate,
WM_OT_appconfig_default,
- WM_OT_blenderplayer_start,
WM_OT_context_collection_boolean_set,
WM_OT_context_cycle_array,
WM_OT_context_cycle_enum,
@@ -2384,5 +2564,12 @@ classes = (
WM_OT_properties_remove,
WM_OT_sysinfo,
WM_OT_theme_install,
+ WM_OT_owner_disable,
+ WM_OT_owner_enable,
WM_OT_url_open,
+ WM_OT_studiolight_install,
+ WM_OT_studiolight_uninstall,
+ WM_OT_studiolight_userpref_show,
+ WM_OT_tool_set_by_name,
+ WM_OT_toolbar,
)
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index f98074cdf0b..51ba45cdcd7 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -34,13 +34,14 @@ _modules = [
"properties_data_camera",
"properties_data_curve",
"properties_data_empty",
- "properties_data_lamp",
+ "properties_data_light",
"properties_data_lattice",
"properties_data_mesh",
"properties_data_metaball",
"properties_data_modifier",
+ "properties_data_lightprobe",
"properties_data_speaker",
- "properties_game",
+ "properties_data_workspace",
"properties_mask_common",
"properties_material",
"properties_object",
@@ -57,10 +58,17 @@ _modules = [
"properties_physics_smoke",
"properties_physics_softbody",
"properties_render",
- "properties_render_layer",
+ "properties_view_layer",
"properties_scene",
"properties_texture",
"properties_world",
+
+ # Generic Space Modules
+ #
+ # Depends on DNA_WORKSPACE_TOOL (C define).
+ "space_toolsystem_common",
+ "space_toolsystem_toolbar",
+
"space_clip",
"space_console",
"space_dopesheet",
@@ -68,14 +76,15 @@ _modules = [
"space_graph",
"space_image",
"space_info",
- "space_logic",
"space_nla",
"space_node",
"space_outliner",
"space_properties",
"space_sequencer",
+ "space_statusbar",
"space_text",
"space_time",
+ "space_topbar",
"space_userpref",
"space_view3d",
"space_view3d_toolbar",
diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py
index 9782d5a072c..901e15c181a 100644
--- a/release/scripts/startup/bl_ui/properties_animviz.py
+++ b/release/scripts/startup/bl_ui/properties_animviz.py
@@ -37,27 +37,26 @@ class MotionPathButtonsPanel:
mps = avs.motion_path
# Display Range
- layout.row().prop(mps, "type", expand=True)
+ layout.use_property_split = True
+ layout.row().prop(mps, "type")
- split = layout.split()
+ col = layout.column()
- col = split.column()
- col.label(text="Display Range:")
sub = col.column(align=True)
if mps.type == 'CURRENT_FRAME':
- sub.prop(mps, "frame_before", text="Before")
+ sub.prop(mps, "frame_before", text="Frame Range Before")
sub.prop(mps, "frame_after", text="After")
elif mps.type == 'RANGE':
- sub.prop(mps, "frame_start", text="Start")
+ sub.prop(mps, "frame_start", text="Frame Range Start")
sub.prop(mps, "frame_end", text="End")
sub.prop(mps, "frame_step", text="Step")
- col = split.column()
+ col = layout.column(align=True)
if bones:
col.label(text="Cache for Bone:")
else:
- col.label(text="Cache:")
+ col.label(text="Cache")
if mpath:
sub = col.column(align=True)
@@ -81,17 +80,15 @@ class MotionPathButtonsPanel:
sub.operator("object.paths_calculate", text="Calculate...", icon='OBJECT_DATA')
# Display Settings
- split = layout.split()
- col = split.column()
- col.label(text="Show:")
+ layout.label(text="Display")
+
+ col = layout.column()
col.prop(mps, "show_frame_numbers", text="Frame Numbers")
if mpath is not None:
col.prop(mpath, "lines", text="Lines")
col.prop(mpath, "line_thickness", text="Thickness")
- col = split.column()
- col.label("")
col.prop(mps, "show_keyframe_highlight", text="Keyframes")
sub = col.column()
sub.enabled = mps.show_keyframe_highlight
@@ -101,11 +98,11 @@ class MotionPathButtonsPanel:
# Customize path
if mpath is not None:
- row = layout.row(align=True)
- row.prop(mpath, "use_custom_color", text="", toggle=True, icon='COLOR')
- sub = row.row(align=True)
+
+ col.prop(mpath, "use_custom_color", text="Custom Color")
+ sub = col.column()
sub.enabled = mpath.use_custom_color
- sub.prop(mpath, "color", text="")
+ sub.prop(mpath, "color")
# FIXME: this panel still needs to be ported so that it will work correctly with animviz
diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py
index c0fa82946e1..6cfc4b6ea3f 100644
--- a/release/scripts/startup/bl_ui/properties_data_armature.py
+++ b/release/scripts/startup/bl_ui/properties_data_armature.py
@@ -65,11 +65,6 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, Panel):
col.label(text="Protected Layers:")
col.prop(arm, "layers_protected", text="")
- if context.scene.render.engine == 'BLENDER_GAME':
- col = layout.column()
- col.label(text="Deform:")
- col.prop(arm, "deform_method", expand=True)
-
class DATA_PT_display(ArmatureButtonsPanel, Panel):
bl_label = "Display"
@@ -82,15 +77,13 @@ class DATA_PT_display(ArmatureButtonsPanel, Panel):
layout.row().prop(arm, "draw_type", expand=True)
- split = layout.split()
+ layout.use_property_split = True
- col = split.column()
+ col = layout.column()
col.prop(arm, "show_names", text="Names")
col.prop(arm, "show_axes", text="Axes")
col.prop(arm, "show_bone_custom_shapes", text="Shapes")
-
- col = split.column()
- col.prop(arm, "show_group_colors", text="Colors")
+ col.prop(arm, "show_group_colors", text="Group Colors")
if ob:
col.prop(ob, "show_x_ray", text="X-Ray")
col.prop(arm, "use_deform_delay", text="Delay Refresh")
@@ -154,7 +147,8 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
sub = row.row(align=True)
sub.operator("pose.group_assign", text="Assign")
- sub.operator("pose.group_unassign", text="Remove") # row.operator("pose.bone_group_remove_from", text="Remove")
+ # row.operator("pose.bone_group_remove_from", text="Remove")
+ sub.operator("pose.group_unassign", text="Remove")
sub = row.row(align=True)
sub.operator("pose.group_select", text="Select")
@@ -201,7 +195,11 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
if pose_marker_active is not None:
col.operator("poselib.pose_remove", icon='ZOOMOUT', text="")
- col.operator("poselib.apply_pose", icon='ZOOM_SELECTED', text="").pose_index = poselib.pose_markers.active_index
+ col.operator(
+ "poselib.apply_pose",
+ icon='ZOOM_SELECTED',
+ text="",
+ ).pose_index = poselib.pose_markers.active_index
col.operator("poselib.action_sanitize", icon='HELP', text="") # XXX: put in menu?
@@ -221,21 +219,19 @@ class DATA_PT_ghost(ArmatureButtonsPanel, Panel):
layout.row().prop(arm, "ghost_type", expand=True)
- split = layout.split()
+ layout.use_property_split = True
- col = split.column(align=True)
+ col = layout.column(align=True)
if arm.ghost_type == 'RANGE':
- col.prop(arm, "ghost_frame_start", text="Start")
+ col.prop(arm, "ghost_frame_start", text="Frame Start")
col.prop(arm, "ghost_frame_end", text="End")
col.prop(arm, "ghost_size", text="Step")
elif arm.ghost_type == 'CURRENT_FRAME':
- col.prop(arm, "ghost_step", text="Range")
+ col.prop(arm, "ghost_step", text="Frame Range")
col.prop(arm, "ghost_size", text="Step")
- col = split.column()
- col.label(text="Display:")
- col.prop(arm, "show_only_ghost_selected", text="Selected Only")
+ col.prop(arm, "show_only_ghost_selected", text="Display Selected Only")
class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
@@ -249,6 +245,7 @@ class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
itasc = ob.pose.ik_param
@@ -256,34 +253,36 @@ class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
layout.prop(ob.pose, "ik_solver")
if itasc:
+ layout.use_property_split = False
layout.row().prop(itasc, "mode", expand=True)
+ layout.use_property_split = True
simulation = (itasc.mode == 'SIMULATION')
if simulation:
- layout.label(text="Reiteration:")
- layout.row().prop(itasc, "reiteration_method", expand=True)
+ layout.prop(itasc, "reiteration_method", expand=False)
- row = layout.row()
- row.active = not simulation or itasc.reiteration_method != 'NEVER'
- row.prop(itasc, "precision")
- row.prop(itasc, "iterations")
+ col = layout.column()
+ col.active = not simulation or itasc.reiteration_method != 'NEVER'
+ col.prop(itasc, "precision")
+ col.prop(itasc, "iterations")
if simulation:
layout.prop(itasc, "use_auto_step")
- row = layout.row()
+ col = layout.column(align=True)
if itasc.use_auto_step:
- row.prop(itasc, "step_min", text="Min")
- row.prop(itasc, "step_max", text="Max")
+ col.prop(itasc, "step_min", text="Steps Min")
+ col.prop(itasc, "step_max", text="Max")
else:
- row.prop(itasc, "step_count")
+ col.prop(itasc, "step_count", text="Steps")
layout.prop(itasc, "solver")
if simulation:
layout.prop(itasc, "feedback")
layout.prop(itasc, "velocity_max")
if itasc.solver == 'DLS':
- row = layout.row()
- row.prop(itasc, "damping_max", text="Damp", slider=True)
- row.prop(itasc, "damping_epsilon", text="Eps", slider=True)
+ col = layout.column()
+ col.separator()
+ col.prop(itasc, "damping_max", text="Damping Max", slider=True)
+ col.prop(itasc, "damping_epsilon", text="Damping Epsilon", slider=True)
from .properties_animviz import (
@@ -329,7 +328,7 @@ class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , Panel): # inherit from
class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Armature
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 63b5d4f96fc..cc593fbb0a2 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -62,88 +62,63 @@ class BONE_PT_transform(BoneButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
bone = context.bone
+ col = layout.column()
+
if bone and ob:
pchan = ob.pose.bones[bone.name]
-
- row = layout.row()
- col = row.column()
- col.prop(pchan, "location")
col.active = not (bone.parent and bone.use_connect)
- col = row.column()
+ sub = col.row(align=True)
+ sub.prop(pchan, "location")
+ sub.prop(pchan, "lock_location", text="")
+
+ col = layout.column()
if pchan.rotation_mode == 'QUATERNION':
- col.prop(pchan, "rotation_quaternion", text="Rotation")
+ sub = col.row(align=True)
+ sub.prop(pchan, "rotation_quaternion", text="Rotation")
+ subsub = sub.column(align=True)
+ subsub.prop(pchan, "lock_rotation_w", text="")
+ subsub.prop(pchan, "lock_rotation", text="")
elif pchan.rotation_mode == 'AXIS_ANGLE':
# col.label(text="Rotation")
#col.prop(pchan, "rotation_angle", text="Angle")
#col.prop(pchan, "rotation_axis", text="Axis")
- col.prop(pchan, "rotation_axis_angle", text="Rotation")
+ sub = col.row(align=True)
+ sub.prop(pchan, "rotation_axis_angle", text="Rotation")
+ subsub = sub.column(align=True)
+ subsub.prop(pchan, "lock_rotation_w", text="")
+ subsub.prop(pchan, "lock_rotation", text="")
else:
- col.prop(pchan, "rotation_euler", text="Rotation")
+ sub = col.row(align=True)
+ sub.prop(pchan, "rotation_euler", text="Rotation")
+ sub.prop(pchan, "lock_rotation", text="")
- row.column().prop(pchan, "scale")
+ col = layout.column()
+ sub = col.row(align=True)
+ sub.prop(pchan, "scale")
+ sub.prop(pchan, "lock_scale", text="")
- layout.prop(pchan, "rotation_mode")
+ col = layout.column()
+ col.prop(pchan, "rotation_mode")
elif context.edit_bone:
bone = context.edit_bone
- row = layout.row()
- row.column().prop(bone, "head")
- row.column().prop(bone, "tail")
-
- col = row.column()
- sub = col.column(align=True)
- sub.label(text="Roll:")
- sub.prop(bone, "roll", text="")
- sub.label()
- sub.prop(bone, "lock")
-
-
-class BONE_PT_transform_locks(BoneButtonsPanel, Panel):
- bl_label = "Transform Locks"
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- ob = context.object
- return ob and ob.mode == 'POSE' and context.bone
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.object
- bone = context.bone
- pchan = ob.pose.bones[bone.name]
-
- split = layout.split(percentage=0.1)
-
- col = split.column(align=True)
- col.label(text="")
- col.label(text="X:")
- col.label(text="Y:")
- col.label(text="Z:")
-
- col = split.column()
- col.active = not (bone.parent and bone.use_connect)
- col.prop(pchan, "lock_location", text="Location")
-
- col = split.column()
- col.prop(pchan, "lock_rotation", text="Rotation")
-
- col = split.column()
- col.prop(pchan, "lock_scale", text="Scale")
+ col = layout.column()
+ col.prop(bone, "head")
+ col.prop(bone, "tail")
- if pchan.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
- row = layout.row()
- row.prop(pchan, "lock_rotations_4d", text="Lock Rotation")
+ col = layout.column()
+ col.prop(bone, "roll")
+ col.prop(bone, "lock")
- sub = row.row()
- sub.active = pchan.lock_rotations_4d
- sub.prop(pchan, "lock_rotation_w", text="W")
+ col = layout.column()
+ col.prop(bone, "tail_radius")
+ col.prop(bone, "envelope_distance")
class BONE_PT_curved(BoneButtonsPanel, Panel):
@@ -166,54 +141,52 @@ class BONE_PT_curved(BoneButtonsPanel, Panel):
bbone = bone
layout = self.layout
+ layout.use_property_split = True
+
layout.prop(bone, "bbone_segments", text="Segments")
col = layout.column()
col.active = bone.bbone_segments > 1
- row = col.row()
- sub = row.column(align=True)
- sub.label(text="Curve XY Offsets:")
- sub.prop(bbone, "bbone_curveinx", text="In X")
- sub.prop(bbone, "bbone_curveoutx", text="Out X")
- sub.prop(bbone, "bbone_curveiny", text="In Y")
- sub.prop(bbone, "bbone_curveouty", text="Out Y")
-
- sub = row.column(align=True)
- sub.label("Roll:")
- sub.prop(bbone, "bbone_rollin", text="In")
- sub.prop(bbone, "bbone_rollout", text="Out")
- sub.prop(bone, "use_endroll_as_inroll")
-
- row = col.row()
- sub = row.column(align=True)
- sub.label(text="Scale:")
- sub.prop(bbone, "bbone_scalein", text="In")
- sub.prop(bbone, "bbone_scaleout", text="Out")
-
- sub = row.column(align=True)
- sub.label("Easing:")
- sub.prop(bbone, "bbone_easein", text="In")
- sub.prop(bbone, "bbone_easeout", text="Out")
+ col = layout.column(align=True)
+ col.prop(bbone, "bbone_curveinx", text="Curve In X")
+ col.prop(bbone, "bbone_curveiny", text="In Y")
+
+ col = layout.column(align=True)
+ col.prop(bbone, "bbone_curveoutx", text="Curve Out X")
+ col.prop(bbone, "bbone_curveouty", text="Out Y")
+
+ col = layout.column(align=True)
+ col.prop(bbone, "bbone_rollin", text="Roll In")
+ col.prop(bbone, "bbone_rollout", text="Out")
+ col.prop(bone, "use_endroll_as_inroll")
+
+ col = layout.column(align=True)
+ col.prop(bbone, "bbone_scalein", text="Scale In")
+ col.prop(bbone, "bbone_scaleout", text="Out")
+
+ col = layout.column(align=True)
+ col.prop(bbone, "bbone_easein", text="Ease In")
+ col.prop(bbone, "bbone_easeout", text="Out")
if pchan:
layout.separator()
col = layout.column()
+ col.use_property_split = False
col.prop(pchan, "use_bbone_custom_handles")
- row = col.row()
- row.active = pchan.use_bbone_custom_handles
+ col = layout.column(align=True)
+ col.active = pchan.use_bbone_custom_handles
+ col.use_property_split = True
- sub = row.column(align=True)
- sub.label(text="In:")
- sub.prop_search(pchan, "bbone_custom_handle_start", ob.pose, "bones", text="")
- sub.prop(pchan, "use_bbone_relative_start_handle", text="Relative")
+ sub = col.column()
+ sub.prop_search(pchan, "bbone_custom_handle_start", ob.pose, "bones", text="Custom Handle Start")
+ sub.prop_search(pchan, "bbone_custom_handle_end", ob.pose, "bones", text="End")
- sub = row.column(align=True)
- sub.label(text="Out:")
- sub.prop_search(pchan, "bbone_custom_handle_end", ob.pose, "bones", text="")
- sub.prop(pchan, "use_bbone_relative_end_handle", text="Relative")
+ sub = col.column(align=True)
+ sub.prop(pchan, "use_bbone_relative_start_handle", text="Relative Handle Start")
+ sub.prop(pchan, "use_bbone_relative_end_handle", text="End")
class BONE_PT_relations(BoneButtonsPanel, Panel):
@@ -221,6 +194,7 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
bone = context.bone
@@ -232,26 +206,22 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
elif bone is None:
bone = context.edit_bone
- split = layout.split()
-
- col = split.column()
- col.label(text="Layers:")
+ col = layout.column()
+ col.use_property_split = False
col.prop(bone, "layers", text="")
+ col.use_property_split = True
+ col = layout.column()
col.separator()
- if ob and pchan:
- col.label(text="Bone Group:")
- col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="")
- col.label(text="Object Children:")
- col.prop(bone, "use_relative_parent")
-
- col = split.column()
- col.label(text="Parent:")
if context.bone:
- col.prop(bone, "parent", text="")
+ col.prop(bone, "parent")
else:
- col.prop_search(bone, "parent", arm, "edit_bones", text="")
+ col.prop_search(bone, "parent", arm, "edit_bones")
+
+ if ob and pchan:
+ col.prop(bone, "use_relative_parent")
+ col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="Bone Group")
sub = col.column()
sub.active = (bone.parent is not None)
@@ -274,6 +244,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
# note. this works ok in edit-mode but isn't
# all that useful so disabling for now.
layout = self.layout
+ layout.use_property_split = True
ob = context.object
bone = context.bone
@@ -285,23 +256,20 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
bone = context.edit_bone
if bone:
- split = layout.split()
- col = split.column()
+ col = layout.column()
col.prop(bone, "hide", text="Hide")
sub = col.column()
sub.active = bool(pchan and pchan.custom_shape)
sub.prop(bone, "show_wire", text="Wireframe")
if pchan:
- col = split.column()
-
- col.label(text="Custom Shape:")
- col.prop(pchan, "custom_shape", text="")
+ col = layout.column()
+ col.prop(pchan, "custom_shape")
if pchan.custom_shape:
col.prop(pchan, "use_custom_shape_bone_size", text="Bone Size")
col.prop(pchan, "custom_shape_scale", text="Scale")
- col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
+ col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones")
class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel):
@@ -315,80 +283,82 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
bone = context.bone
pchan = ob.pose.bones[bone.name]
- row = layout.row()
-
active = pchan.is_in_ik_chain
- split = layout.split(percentage=0.25)
- split.prop(pchan, "lock_ik_x", text="X")
- split.active = active
- row = split.row()
- row.prop(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
- row.active = pchan.lock_ik_x is False and active
+ col = layout.column()
+ col.prop(pchan, "ik_stretch", slider=True)
+ col.active = active
+
+ layout.separator()
+
+ col = layout.column(align=True)
- split = layout.split(percentage=0.25)
- sub = split.row()
+ col.prop(pchan, "lock_ik_x", text="Lock IK X")
+ col.prop(pchan, "lock_ik_y", text="Y")
+ col.prop(pchan, "lock_ik_z", text="Z")
- sub.prop(pchan, "use_ik_limit_x", text="Limit")
+ col = layout.column(align=True)
+
+ sub = col.column(align=True)
sub.active = pchan.lock_ik_x is False and active
- sub = split.row(align=True)
- sub.prop(pchan, "ik_min_x", text="")
- sub.prop(pchan, "ik_max_x", text="")
- sub.active = pchan.lock_ik_x is False and pchan.use_ik_limit_x and active
+ sub.prop(pchan, "ik_stiffness_x", text="Stiffness X", slider=True)
+ sub = col.column(align=True)
+ sub.active = pchan.lock_ik_y is False and active
+ sub.prop(pchan, "ik_stiffness_y", text="Y", slider=True)
+ sub = col.column(align=True)
+ sub.active = pchan.lock_ik_z is False and active
+ sub.prop(pchan, "ik_stiffness_z", text="Z", slider=True)
+
+ col = layout.column(align=True)
- split = layout.split(percentage=0.25)
- split.prop(pchan, "lock_ik_y", text="Y")
- split.active = active
- row = split.row()
- row.prop(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
- row.active = pchan.lock_ik_y is False and active
+ sub = col.column()
+ sub.active = pchan.lock_ik_x is False and active
+ sub.prop(pchan, "use_ik_limit_x", text="Limit X")
- split = layout.split(percentage=0.25)
- sub = split.row()
+ sub = col.column(align=True)
+ sub.active = pchan.lock_ik_x is False and pchan.use_ik_limit_x and active
+ sub.prop(pchan, "ik_min_x", text="Min")
+ sub.prop(pchan, "ik_max_x", text="Max")
+
+ col.separator()
- sub.prop(pchan, "use_ik_limit_y", text="Limit")
+ sub = col.column()
sub.active = pchan.lock_ik_y is False and active
+ sub.prop(pchan, "use_ik_limit_y", text="Limit Y")
- sub = split.row(align=True)
- sub.prop(pchan, "ik_min_y", text="")
- sub.prop(pchan, "ik_max_y", text="")
+ sub = col.column(align=True)
sub.active = pchan.lock_ik_y is False and pchan.use_ik_limit_y and active
+ sub.prop(pchan, "ik_min_y", text="Min")
+ sub.prop(pchan, "ik_max_y", text="Max")
- split = layout.split(percentage=0.25)
- split.prop(pchan, "lock_ik_z", text="Z")
- split.active = active
- sub = split.row()
- sub.prop(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
- sub.active = pchan.lock_ik_z is False and active
-
- split = layout.split(percentage=0.25)
- sub = split.row()
+ col.separator()
- sub.prop(pchan, "use_ik_limit_z", text="Limit")
+ sub = col.column()
sub.active = pchan.lock_ik_z is False and active
- sub = split.row(align=True)
- sub.prop(pchan, "ik_min_z", text="")
- sub.prop(pchan, "ik_max_z", text="")
+ sub.prop(pchan, "use_ik_limit_z", text="Limit Z")
+
+ sub = col.column(align=True)
sub.active = pchan.lock_ik_z is False and pchan.use_ik_limit_z and active
+ sub.prop(pchan, "ik_min_z", text="Min")
+ sub.prop(pchan, "ik_max_z", text="Max")
- split = layout.split(percentage=0.25)
- split.label(text="Stretch:")
- sub = split.row()
- sub.prop(pchan, "ik_stretch", text="", slider=True)
- sub.active = active
+ col.separator()
if ob.pose.ik_solver == 'ITASC':
- split = layout.split()
- col = split.column()
+
+ col = layout.column()
col.prop(pchan, "use_ik_rotation_control", text="Control Rotation")
col.active = active
- col = split.column()
- col.prop(pchan, "ik_rotation_weight", text="Weight", slider=True)
+
+ col = layout.column()
+
+ col.prop(pchan, "ik_rotation_weight", text="IK Rotation Weight", slider=True)
col.active = active
# not supported yet
#row = layout.row()
@@ -410,6 +380,7 @@ class BONE_PT_deform(BoneButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
bone = context.bone
@@ -418,22 +389,20 @@ class BONE_PT_deform(BoneButtonsPanel, Panel):
layout.active = bone.use_deform
- row = layout.row()
+ col = layout.column()
+ col.prop(bone, "envelope_distance", text="Envelope Distance")
+ col.prop(bone, "envelope_weight", text="Envelope Weight")
+ col.prop(bone, "use_envelope_multiply", text="Envelope Multiply")
- col = row.column(align=True)
- col.label(text="Envelope:")
- col.prop(bone, "envelope_distance", text="Distance")
- col.prop(bone, "envelope_weight", text="Weight")
- col.prop(bone, "use_envelope_multiply", text="Multiply")
+ col.separator()
- col = row.column(align=True)
- col.label(text="Envelope Radius:")
- col.prop(bone, "head_radius", text="Head")
+ col = layout.column(align=True)
+ col.prop(bone, "head_radius", text="Radius Head")
col.prop(bone, "tail_radius", text="Tail")
class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone
@property
@@ -448,7 +417,6 @@ class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
classes = (
BONE_PT_context_bone,
BONE_PT_transform,
- BONE_PT_transform_locks,
BONE_PT_curved,
BONE_PT_relations,
BONE_PT_display,
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 14286045704..3b5f21d616e 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -20,6 +20,7 @@
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
+from bl_operators.presets import PresetMenu
class CameraButtonsPanel:
@@ -29,30 +30,30 @@ class CameraButtonsPanel:
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
+ engine = context.engine
return context.camera and (engine in cls.COMPAT_ENGINES)
-class CAMERA_MT_presets(Menu):
+class CAMERA_PT_presets(PresetMenu):
bl_label = "Camera Presets"
preset_subdir = "camera"
preset_operator = "script.execute_preset"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- draw = Menu.draw_preset
+ preset_add_operator = "camera.preset_add"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
-class SAFE_AREAS_MT_presets(Menu):
+class SAFE_AREAS_PT_presets(PresetMenu):
bl_label = "Camera Presets"
preset_subdir = "safe_areas"
preset_operator = "script.execute_preset"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- draw = Menu.draw_preset
+ preset_add_operator = "safe_areas.preset_add"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
class DATA_PT_context_camera(CameraButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -72,72 +73,70 @@ class DATA_PT_context_camera(CameraButtonsPanel, Panel):
class DATA_PT_lens(CameraButtonsPanel, Panel):
bl_label = "Lens"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
cam = context.camera
- layout.row().prop(cam, "type", expand=True)
+ layout.prop(cam, "type")
- split = layout.split()
+ col = layout.column()
+ col.separator()
- col = split.column()
if cam.type == 'PERSP':
- row = col.row()
+ col = layout.column()
if cam.lens_unit == 'MILLIMETERS':
- row.prop(cam, "lens")
+ col.prop(cam, "lens")
elif cam.lens_unit == 'FOV':
row.prop(cam, "angle")
- row.prop(cam, "lens_unit", text="")
+ col.prop(cam, "lens_unit")
elif cam.type == 'ORTHO':
col.prop(cam, "ortho_scale")
elif cam.type == 'PANO':
- engine = context.scene.render.engine
+ engine = context.engine
if engine == 'CYCLES':
ccam = cam.cycles
- col.prop(ccam, "panorama_type", text="Type")
+ col.prop(ccam, "panorama_type")
if ccam.panorama_type == 'FISHEYE_EQUIDISTANT':
col.prop(ccam, "fisheye_fov")
elif ccam.panorama_type == 'FISHEYE_EQUISOLID':
- row = layout.row()
- row.prop(ccam, "fisheye_lens", text="Lens")
- row.prop(ccam, "fisheye_fov")
+ col.prop(ccam, "fisheye_lens", text="Lens")
+ col.prop(ccam, "fisheye_fov")
elif ccam.panorama_type == 'EQUIRECTANGULAR':
- row = layout.row()
- sub = row.column(align=True)
- sub.prop(ccam, "latitude_min")
- sub.prop(ccam, "latitude_max")
- sub = row.column(align=True)
- sub.prop(ccam, "longitude_min")
- sub.prop(ccam, "longitude_max")
- elif engine == 'BLENDER_RENDER':
- row = col.row()
+ sub = col.column(align=True)
+ sub.prop(ccam, "latitude_min", text="Latitute Min")
+ sub.prop(ccam, "latitude_max", text="Max")
+ sub = col.column(align=True)
+ sub.prop(ccam, "longitude_min", text="Longiture Min")
+ sub.prop(ccam, "longitude_max", text="Max")
+ elif engine in {'BLENDER_RENDER', 'BLENDER_EEVEE'}:
if cam.lens_unit == 'MILLIMETERS':
- row.prop(cam, "lens")
+ col.prop(cam, "lens")
elif cam.lens_unit == 'FOV':
- row.prop(cam, "angle")
- row.prop(cam, "lens_unit", text="")
+ col.prop(cam, "angle")
+ col.prop(cam, "lens_unit")
- split = layout.split()
+ col = layout.column()
+ col.separator()
- col = split.column(align=True)
- col.label(text="Shift:")
- col.prop(cam, "shift_x", text="X")
- col.prop(cam, "shift_y", text="Y")
+ sub = col.column(align=True)
+ sub.prop(cam, "shift_x", text="Shift X")
+ sub.prop(cam, "shift_y", text="Y")
- col = split.column(align=True)
- col.label(text="Clipping:")
- col.prop(cam, "clip_start", text="Start")
- col.prop(cam, "clip_end", text="End")
+ col.separator()
+ sub = col.column(align=True)
+ sub.prop(cam, "clip_start", text="Clip Start")
+ sub.prop(cam, "clip_end", text="End")
class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
bl_label = "Stereoscopy"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -147,6 +146,8 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
render = context.scene.render
st = context.camera.stereo
cam = context.camera
@@ -154,9 +155,9 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
is_spherical_stereo = cam.type != 'ORTHO' and render.use_spherical_stereo
use_spherical_stereo = is_spherical_stereo and st.use_spherical_stereo
- col = layout.column()
- col.row().prop(st, "convergence_mode", expand=True)
+ layout.prop(st, "convergence_mode")
+ col = layout.column()
sub = col.column()
sub.active = st.convergence_mode != 'PARALLEL'
sub.prop(st, "convergence_distance")
@@ -165,106 +166,222 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
if is_spherical_stereo:
col.separator()
- row = col.row()
- row.prop(st, "use_spherical_stereo")
- sub = row.row()
+ col.prop(st, "use_spherical_stereo")
+ sub = col.column()
sub.active = st.use_spherical_stereo
sub.prop(st, "use_pole_merge")
- row = col.row(align=True)
- row.active = st.use_pole_merge
- row.prop(st, "pole_merge_angle_from")
- row.prop(st, "pole_merge_angle_to")
- col.label(text="Pivot:")
- row = col.row()
- row.active = not use_spherical_stereo
- row.prop(st, "pivot", expand=True)
+ sub = col.column(align=True)
+ sub.active = st.use_pole_merge
+ sub.prop(st, "pole_merge_angle_from", text="Pole Merge Angle Start")
+ sub.prop(st, "pole_merge_angle_to", text="End")
+
+ col = layout.column()
+ col.active = not use_spherical_stereo
+ col.separator()
+ col.prop(st, "pivot")
class DATA_PT_camera(CameraButtonsPanel, Panel):
bl_label = "Camera"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header_preset(self, context):
+ CAMERA_PT_presets.draw_panel_header(self.layout)
def draw(self, context):
layout = self.layout
cam = context.camera
- row = layout.row(align=True)
-
- row.menu("CAMERA_MT_presets", text=bpy.types.CAMERA_MT_presets.bl_label)
- row.operator("camera.preset_add", text="", icon='ZOOMIN')
- row.operator("camera.preset_add", text="", icon='ZOOMOUT').remove_active = True
+ layout.use_property_split = True
- layout.label(text="Sensor:")
-
- split = layout.split()
+ col = layout.column()
+ col.prop(cam, "sensor_fit")
- col = split.column(align=True)
if cam.sensor_fit == 'AUTO':
- col.prop(cam, "sensor_width", text="Size")
+ col.prop(cam, "sensor_width")
else:
sub = col.column(align=True)
sub.active = cam.sensor_fit == 'HORIZONTAL'
sub.prop(cam, "sensor_width", text="Width")
+
sub = col.column(align=True)
sub.active = cam.sensor_fit == 'VERTICAL'
sub.prop(cam, "sensor_height", text="Height")
- col = split.column(align=True)
- col.prop(cam, "sensor_fit", text="")
-
class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
bl_label = "Depth of Field"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
cam = context.camera
dof_options = cam.gpu_dof
- split = layout.split()
-
- col = split.column()
- col.label(text="Focus:")
- col.prop(cam, "dof_object", text="")
+ col = layout.column()
+ col.prop(cam, "dof_object", text="Focus on Object")
sub = col.column()
sub.active = (cam.dof_object is None)
- sub.prop(cam, "dof_distance", text="Distance")
+ sub.prop(cam, "dof_distance", text="Focus Distance")
- hq_support = dof_options.is_hq_supported
- col = split.column(align=True)
- col.label("Viewport:")
- sub = col.column()
- sub.active = hq_support
- sub.prop(dof_options, "use_high_quality")
- col.prop(dof_options, "fstop")
- if dof_options.use_high_quality and hq_support:
+
+class DATA_PT_camera_dof_aperture(CameraButtonsPanel, Panel):
+ bl_label = "Aperture"
+ bl_parent_id = "DATA_PT_camera_dof"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ cam = context.camera
+ dof_options = cam.gpu_dof
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ if context.engine == 'BLENDER_EEVEE':
+ col = flow.column()
+ col.prop(dof_options, "fstop")
col.prop(dof_options, "blades")
+ col = flow.column()
+ col.prop(dof_options, "rotation")
+ col.prop(dof_options, "ratio")
+ else:
+ hq_support = dof_options.is_hq_supported
+ col = flow.column()
+ col.label("Viewport")
+ sub = col.column()
+ sub.active = hq_support
+ sub.prop(dof_options, "use_high_quality")
+ col.prop(dof_options, "fstop")
+ if dof_options.use_high_quality and hq_support:
+ col.prop(dof_options, "blades")
+
+
+class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
+ bl_label = "Background Images"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header(self, context):
+ cam = context.camera
+
+ self.layout.prop(cam, "show_background_images", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ cam = context.camera
+ use_multiview = context.scene.render.use_multiview
+
+ col = layout.column()
+ col.operator("view3d.background_image_add", text="Add Image")
+
+ for i, bg in enumerate(cam.background_images):
+ layout.active = cam.show_background_images
+ box = layout.box()
+ row = box.row(align=True)
+ row.prop(bg, "show_expanded", text="", emboss=False)
+ if bg.source == 'IMAGE' and bg.image:
+ row.prop(bg.image, "name", text="", emboss=False)
+ elif bg.source == 'MOVIE_CLIP' and bg.clip:
+ row.prop(bg.clip, "name", text="", emboss=False)
+ else:
+ row.label(text="Not Set")
+
+ if bg.show_background_image:
+ row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_OFF')
+ else:
+ row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_ON')
+
+ row.operator("view3d.background_image_remove", text="", emboss=False, icon='X').index = i
+
+ if bg.show_expanded:
+ row = box.row()
+ row.prop(bg, "source", expand=True)
+
+ has_bg = False
+ if bg.source == 'IMAGE':
+ row = box.row()
+ row.template_ID(bg, "image", open="image.open")
+ if bg.image is not None:
+ box.template_image(bg, "image", bg.image_user, compact=True)
+ has_bg = True
+
+ if use_multiview and bg.view_axis in {'CAMERA', 'ALL'}:
+ box.prop(bg.image, "use_multiview")
+
+ column = box.column()
+ column.active = bg.image.use_multiview
+
+ column.label(text="Views Format:")
+ column.row().prop(bg.image, "views_format", expand=True)
+
+ sub = column.box()
+ sub.active = bg.image.views_format == 'STEREO_3D'
+ sub.template_image_stereo_3d(bg.image.stereo_3d_format)
+
+ elif bg.source == 'MOVIE_CLIP':
+ box.prop(bg, "use_camera_clip")
+
+ column = box.column()
+ column.active = not bg.use_camera_clip
+ column.template_ID(bg, "clip", open="clip.open")
+
+ if bg.clip:
+ column.template_movieclip(bg, "clip", compact=True)
+
+ if bg.use_camera_clip or bg.clip:
+ has_bg = True
+
+ column = box.column()
+ column.active = has_bg
+ column.prop(bg.clip_user, "proxy_render_size", text="")
+ column.prop(bg.clip_user, "use_render_undistorted")
+
+ if has_bg:
+ col = box.column()
+ col.prop(bg, "alpha", slider=True)
+ col.row().prop(bg, "draw_depth", expand=True)
+
+ col.row().prop(bg, "frame_method", expand=True)
+
+ box = col.box()
+ row = box.row()
+ row.prop(bg, "offset")
+
+ row = box.row()
+ row.prop(bg, "use_flip_x")
+ row.prop(bg, "use_flip_y")
+
+ row = box.row()
+ row.prop(bg, "rotation")
+ row.prop(bg, "scale")
+
class DATA_PT_camera_display(CameraButtonsPanel, Panel):
bl_label = "Display"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
cam = context.camera
split = layout.split()
+ split.label()
+ split.prop_menu_enum(cam, "show_guide")
- col = split.column()
- col.prop(cam, "show_limits", text="Limits")
- col.prop(cam, "show_mist", text="Mist")
+ col = layout.column(align=True)
- col.prop(cam, "show_sensor", text="Sensor")
- col.prop(cam, "show_name", text="Name")
-
- col = split.column()
- col.prop_menu_enum(cam, "show_guide")
col.separator()
col.prop(cam, "draw_size", text="Size")
col.separator()
@@ -273,17 +390,27 @@ class DATA_PT_camera_display(CameraButtonsPanel, Panel):
sub.active = cam.show_passepartout
sub.prop(cam, "passepartout_alpha", text="Alpha", slider=True)
+ col.separator()
+
+ col.prop(cam, "show_limits", text="Limits")
+ col.prop(cam, "show_mist", text="Mist")
+ col.prop(cam, "show_sensor", text="Sensor")
+ col.prop(cam, "show_name", text="Name")
+
class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel):
bl_label = "Safe Areas"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
cam = context.camera
self.layout.prop(cam, "show_safe_areas", text="")
+ def draw_header_preset(self, context):
+ SAFE_AREAS_PT_presets.draw_panel_header(self.layout)
+
def draw(self, context):
layout = self.layout
safe_data = context.scene.safe_areas
@@ -293,7 +420,7 @@ class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel):
class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Camera
@@ -302,39 +429,37 @@ def draw_display_safe_settings(layout, safe_data, settings):
show_safe_areas = settings.show_safe_areas
show_safe_center = settings.show_safe_center
- split = layout.split()
+ layout.use_property_split = True
- col = split.column()
- row = col.row(align=True)
- row.menu("SAFE_AREAS_MT_presets", text=bpy.types.SAFE_AREAS_MT_presets.bl_label)
- row.operator("safe_areas.preset_add", text="", icon='ZOOMIN')
- row.operator("safe_areas.preset_add", text="", icon='ZOOMOUT').remove_active = True
+ col = layout.column()
+ col.active = show_safe_areas
- col = split.column()
- col.prop(settings, "show_safe_center", text="Center-Cut Safe Areas")
+ sub = col.column()
+ sub.prop(safe_data, "title", slider=True)
+ sub.prop(safe_data, "action", slider=True)
- split = layout.split()
- col = split.column()
- col.active = show_safe_areas
- col.prop(safe_data, "title", slider=True)
- col.prop(safe_data, "action", slider=True)
+ col.separator()
+
+ col.prop(settings, "show_safe_center", text="Center-Cut Safe Areas")
- col = split.column()
- col.active = show_safe_areas and show_safe_center
- col.prop(safe_data, "title_center", slider=True)
- col.prop(safe_data, "action_center", slider=True)
+ sub = col.column()
+ sub.active = show_safe_areas and show_safe_center
+ sub.prop(safe_data, "title_center", slider=True)
+ sub.prop(safe_data, "action_center", slider=True)
classes = (
- CAMERA_MT_presets,
- SAFE_AREAS_MT_presets,
+ CAMERA_PT_presets,
+ SAFE_AREAS_PT_presets,
DATA_PT_context_camera,
DATA_PT_lens,
DATA_PT_camera,
DATA_PT_camera_stereoscopy,
DATA_PT_camera_dof,
+ DATA_PT_camera_dof_aperture,
DATA_PT_camera_display,
DATA_PT_camera_safe_areas,
+ DATA_PT_camera_background_image,
DATA_PT_custom_props_camera,
)
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index f57156c1bae..c0ab9da949f 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -93,63 +93,63 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel):
row = layout.row()
row.prop(curve, "dimensions", expand=True)
- split = layout.split()
+ layout.use_property_split = True
+
+ col = layout.column()
+ sub = col.column(align=True)
+ sub.prop(curve, "resolution_u", text="Resolution Preview U")
+ if is_surf:
+ sub.prop(curve, "resolution_v", text="V")
- col = split.column()
- col.label(text="Resolution:")
sub = col.column(align=True)
- sub.prop(curve, "resolution_u", text="Preview U")
sub.prop(curve, "render_resolution_u", text="Render U")
+ if is_surf:
+ sub.prop(curve, "render_resolution_v", text="V")
+ col.separator()
+
if is_curve:
- col.label(text="Twisting:")
- col.prop(curve, "twist_mode", text="")
+ col.prop(curve, "twist_mode")
col.prop(curve, "twist_smooth", text="Smooth")
elif is_text:
- col.label(text="Display:")
col.prop(curve, "use_fast_edit", text="Fast Editing")
- col = split.column()
-
- if is_surf:
- sub = col.column()
- sub.label(text="")
- sub = col.column(align=True)
- sub.prop(curve, "resolution_v", text="Preview V")
- sub.prop(curve, "render_resolution_v", text="Render V")
-
if is_curve or is_text:
- col.label(text="Fill:")
+ col = layout.column()
+ col.separator()
+
sub = col.column()
sub.active = (curve.dimensions == '2D' or (curve.bevel_object is None and curve.dimensions == '3D'))
- sub.prop(curve, "fill_mode", text="")
+ sub.prop(curve, "fill_mode")
col.prop(curve, "use_fill_deform")
if is_curve:
- col.label(text="Path/Curve-Deform:")
+ col = layout.column()
+ col.separator()
+
sub = col.column()
- subsub = sub.row()
- subsub.prop(curve, "use_radius")
- subsub.prop(curve, "use_stretch")
+ sub.prop(curve, "use_radius")
+ sub.prop(curve, "use_stretch")
sub.prop(curve, "use_deform_bounds")
class DATA_PT_curve_texture_space(CurveButtonsPanel, Panel):
bl_label = "Texture Space"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
curve = context.curve
- row = layout.row()
- row.prop(curve, "use_auto_texspace")
- row.prop(curve, "use_uv_as_generated")
+ col = layout.column()
+ col.prop(curve, "use_uv_as_generated")
+ col.prop(curve, "use_auto_texspace")
- row = layout.row()
- row.column().prop(curve, "texspace_location", text="Location")
- row.column().prop(curve, "texspace_size", text="Size")
+ col = layout.column()
+ col.prop(curve, "texspace_location")
+ col.prop(curve, "texspace_size")
layout.operator("curve.match_texture_space")
@@ -163,29 +163,51 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
curve = context.curve
- split = layout.split()
-
- col = split.column()
- col.label(text="Modification:")
+ col = layout.column()
col.prop(curve, "offset")
- col.prop(curve, "extrude")
- col.label(text="Taper Object:")
- col.prop(curve, "taper_object", text="")
- col = split.column()
- col.label(text="Bevel:")
- col.prop(curve, "bevel_depth", text="Depth")
- col.prop(curve, "bevel_resolution", text="Resolution")
- col.label(text="Bevel Object:")
- col.prop(curve, "bevel_object", text="")
+ sub = col.column()
+ sub.active = (curve.bevel_object is None)
+ sub.prop(curve, "extrude")
+
+ col.prop(curve, "taper_object")
+
+ sub = col.column()
+ sub.active = curve.taper_object is not None
+ sub.prop(curve, "use_map_taper")
+
+
+class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel):
+ bl_label = "Bevel"
+ bl_parent_id = "DATA_PT_geometry_curve"
+
+ @classmethod
+ def poll(cls, context):
+ return (type(context.curve) in {Curve, TextCurve})
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ curve = context.curve
+
+ col = layout.column()
+ sub = col.column()
+ sub.active = (curve.bevel_object is None)
+ sub.prop(curve, "bevel_depth", text="Depth")
+ sub.prop(curve, "bevel_resolution", text="Resolution")
+
+ col.prop(curve, "bevel_object", text="Object")
+
+ sub = col.column()
+ sub.active = curve.bevel_object is not None
+ sub.prop(curve, "use_fill_caps")
if type(curve) is not TextCurve:
- col = layout.column(align=True)
- row = col.row()
- row.label(text="Bevel Factor:")
col = layout.column()
col.active = (
@@ -193,20 +215,13 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel):
(curve.extrude > 0.0) or
(curve.bevel_object is not None)
)
- row = col.row(align=True)
- row.prop(curve, "bevel_factor_mapping_start", text="")
- row.prop(curve, "bevel_factor_start", text="Start")
- row = col.row(align=True)
- row.prop(curve, "bevel_factor_mapping_end", text="")
- row.prop(curve, "bevel_factor_end", text="End")
+ sub = col.column(align=True)
+ sub.prop(curve, "bevel_factor_start", text="Bevel Start")
+ sub.prop(curve, "bevel_factor_end", text="End")
- row = layout.row()
- sub = row.row()
- sub.active = curve.taper_object is not None
- sub.prop(curve, "use_map_taper")
- sub = row.row()
- sub.active = curve.bevel_object is not None
- sub.prop(curve, "use_fill_caps")
+ sub = col.column(align=True)
+ sub.prop(curve, "bevel_factor_mapping_start", text="Bevel Mapping Start")
+ sub.prop(curve, "bevel_factor_mapping_end", text="End")
class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel):
@@ -219,6 +234,7 @@ class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
curve = context.curve
@@ -229,8 +245,9 @@ class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel):
col.prop(curve, "eval_time")
# these are for paths only
- row = layout.row()
- row.prop(curve, "use_path_follow")
+ col.separator()
+
+ col.prop(curve, "use_path_follow")
class DATA_PT_active_spline(CurveButtonsPanelActive, Panel):
@@ -238,65 +255,64 @@ class DATA_PT_active_spline(CurveButtonsPanelActive, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
curve = context.curve
act_spline = curve.splines.active
is_surf = type(curve) is SurfaceCurve
is_poly = (act_spline.type == 'POLY')
- split = layout.split()
+ col = layout.column()
if is_poly:
# These settings are below but its easier to have
# polys set aside since they use so few settings
- row = layout.row()
- row.label(text="Cyclic:")
- row.prop(act_spline, "use_cyclic_u", text="U")
- layout.prop(act_spline, "use_smooth")
+ col.prop(act_spline, "use_cyclic_u")
+ col.prop(act_spline, "use_smooth")
else:
- col = split.column()
- col.label(text="Cyclic:")
- if act_spline.type == 'NURBS':
- col.label(text="Bezier:")
- col.label(text="Endpoint:")
- col.label(text="Order:")
- col.label(text="Resolution:")
-
- col = split.column()
- col.prop(act_spline, "use_cyclic_u", text="U")
+ sub = col.column(align=True)
+ sub.prop(act_spline, "use_cyclic_u")
+ if is_surf:
+ sub.prop(act_spline, "use_cyclic_v", text="V")
if act_spline.type == 'NURBS':
- sub = col.column()
+ sub = col.column(align=True)
# sub.active = (not act_spline.use_cyclic_u)
- sub.prop(act_spline, "use_bezier_u", text="U")
- sub.prop(act_spline, "use_endpoint_u", text="U")
+ sub.prop(act_spline, "use_bezier_u", text="Bezier U")
- sub = col.column()
- sub.prop(act_spline, "order_u", text="U")
- col.prop(act_spline, "resolution_u", text="U")
+ if is_surf:
+ subsub = sub.column()
+ subsub.active = (not act_spline.use_cyclic_v)
+ subsub.prop(act_spline, "use_bezier_v", text="V")
- if is_surf:
- col = split.column()
- col.prop(act_spline, "use_cyclic_v", text="V")
+ sub = col.column(align=True)
+ sub.prop(act_spline, "use_endpoint_u", text="Endpoint U")
- # its a surface, assume its a nurbs
- sub = col.column()
- sub.active = (not act_spline.use_cyclic_v)
- sub.prop(act_spline, "use_bezier_v", text="V")
- sub.prop(act_spline, "use_endpoint_v", text="V")
- sub = col.column()
- sub.prop(act_spline, "order_v", text="V")
+ if is_surf:
+ subsub = sub.column()
+ subsub.active = (not act_spline.use_cyclic_v)
+ subsub.prop(act_spline, "use_endpoint_v", text="V")
+
+ sub = col.column(align=True)
+ sub.prop(act_spline, "order_u", text="Order U")
+
+ if is_surf:
+ sub.prop(act_spline, "order_v", text="V")
+
+ sub = col.column(align=True)
+ sub.prop(act_spline, "resolution_u", text="Resolution U")
+ if is_surf:
sub.prop(act_spline, "resolution_v", text="V")
if act_spline.type == 'BEZIER':
- col = layout.column()
- col.label(text="Interpolation:")
+
+ col.separator()
sub = col.column()
sub.active = (curve.dimensions == '3D')
- sub.prop(act_spline, "tilt_interpolation", text="Tilt")
+ sub.prop(act_spline, "tilt_interpolation", text="Interpolation Tilt")
col.prop(act_spline, "radius_interpolation", text="Radius")
@@ -325,42 +341,46 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
row.label(text="Bold & Italic")
row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink")
- # layout.prop(text, "font")
+ layout.separator()
- split = layout.split()
+ row = layout.row(align=True)
+ row.prop(char, "use_bold", toggle=True)
+ row.prop(char, "use_italic", toggle=True)
+ row.prop(char, "use_underline", toggle=True)
+ row.prop(char, "use_small_caps", toggle=True)
+
+
+class DATA_PT_font_transform(CurveButtonsPanelText, Panel):
+ bl_label = "Transform"
+ bl_parent_id = "DATA_PT_font"
+
+ def draw(self, context):
+ layout = self.layout
+
+ text = context.curve
+ char = context.curve.edit_format
+
+ layout.use_property_split = True
+
+ col = layout.column()
+
+ col.separator()
- col = split.column()
col.prop(text, "size", text="Size")
- col = split.column()
col.prop(text, "shear")
- split = layout.split()
-
- col = split.column()
- col.label(text="Object Font:")
- col.prop(text, "family", text="")
+ col.separator()
- col = split.column()
- col.label(text="Text on Curve:")
- col.prop(text, "follow_curve", text="")
+ col.prop(text, "family")
+ col.prop(text, "follow_curve")
- split = layout.split()
+ col.separator()
- col = split.column()
sub = col.column(align=True)
- sub.label(text="Underline:")
- sub.prop(text, "underline_position", text="Position")
- sub.prop(text, "underline_height", text="Thickness")
-
- col = split.column()
- col.label(text="Character:")
- col.prop(char, "use_bold")
- col.prop(char, "use_italic")
- col.prop(char, "use_underline")
+ sub.prop(text, "underline_position", text="Underline Position")
+ sub.prop(text, "underline_height", text="Underline Thickness")
- row = layout.row()
- row.prop(text, "small_caps_scale", text="Small Caps")
- row.prop(char, "use_small_caps")
+ col.prop(text, "small_caps_scale", text="Small Caps Scale")
class DATA_PT_paragraph(CurveButtonsPanelText, Panel):
@@ -371,23 +391,40 @@ class DATA_PT_paragraph(CurveButtonsPanelText, Panel):
text = context.curve
- layout.label(text="Horizontal Alignment:")
- layout.row().prop(text, "align_x", expand=True)
- layout.label(text="Vertical Alignment:")
+class DATA_PT_paragraph_alignment(CurveButtonsPanelText, Panel):
+ bl_parent_id = "DATA_PT_paragraph"
+ bl_label = "Alignment"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = False
+
+ text = context.curve
+
+ layout.row().prop(text, "align_x", expand=True)
layout.row().prop(text, "align_y", expand=True)
- split = layout.split()
- col = split.column(align=True)
- col.label(text="Spacing:")
- col.prop(text, "space_character", text="Letter")
- col.prop(text, "space_word", text="Word")
- col.prop(text, "space_line", text="Line")
+class DATA_PT_paragraph_spacing(CurveButtonsPanelText, Panel):
+ bl_parent_id = "DATA_PT_paragraph"
+ bl_label = "Spacing"
- col = split.column(align=True)
- col.label(text="Offset:")
- col.prop(text, "offset_x", text="X")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ text = context.curve
+
+ col = layout.column(align=True)
+ col.prop(text, "space_character", text="Character Spacing")
+ col.prop(text, "space_word", text="Word Spacing")
+ col.prop(text, "space_line", text="Line Spacing")
+
+ layout.separator()
+
+ col = layout.column(align=True)
+ col.prop(text, "offset_x", text="Offset X")
col.prop(text, "offset_y", text="Y")
@@ -399,10 +436,7 @@ class DATA_PT_text_boxes(CurveButtonsPanelText, Panel):
text = context.curve
- split = layout.split()
- col = split.column()
- col.operator("font.textbox_add", icon='ZOOMIN')
- col = split.column()
+ layout.operator("font.textbox_add", icon='ZOOMIN')
for i, box in enumerate(text.text_boxes):
@@ -410,25 +444,22 @@ class DATA_PT_text_boxes(CurveButtonsPanelText, Panel):
row = boxy.row()
- split = row.split()
-
- col = split.column(align=True)
-
- col.label(text="Dimensions:")
- col.prop(box, "width", text="Width")
- col.prop(box, "height", text="Height")
+ col = row.column()
+ col.use_property_split = True
- col = split.column(align=True)
+ sub = col.column(align=True)
+ sub.prop(box, "width", text="Size X")
+ sub.prop(box, "height", text="Y")
- col.label(text="Offset:")
- col.prop(box, "x", text="X")
- col.prop(box, "y", text="Y")
+ sub = col.column(align=True)
+ sub.prop(box, "x", text="Offset X")
+ sub.prop(box, "y", text="Y")
row.operator("font.textbox_remove", text="", icon='X', emboss=False).index = i
class DATA_PT_custom_props_curve(CurveButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Curve
@@ -438,10 +469,14 @@ classes = (
DATA_PT_shape_curve,
DATA_PT_curve_texture_space,
DATA_PT_geometry_curve,
+ DATA_PT_geometry_curve_bevel,
DATA_PT_pathanim,
DATA_PT_active_spline,
DATA_PT_font,
+ DATA_PT_font_transform,
DATA_PT_paragraph,
+ DATA_PT_paragraph_alignment,
+ DATA_PT_paragraph_spacing,
DATA_PT_text_boxes,
DATA_PT_custom_props_curve,
)
diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py
index c66ff87ecbd..ab12d0f5c5f 100644
--- a/release/scripts/startup/bl_ui/properties_data_empty.py
+++ b/release/scripts/startup/bl_ui/properties_data_empty.py
@@ -36,10 +36,11 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
- layout.prop(ob, "empty_draw_type", text="Display")
+ layout.prop(ob, "empty_draw_type", text="Display As")
if ob.empty_draw_type == 'IMAGE':
layout.template_ID(ob, "data", open="image.open", unlink="object.unlink_data")
@@ -49,9 +50,11 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
row = layout.row(align=True)
layout.prop(ob, "color", text="Transparency", index=3, slider=True)
- row = layout.row(align=True)
- row.prop(ob, "empty_image_offset", text="Offset X", index=0)
- row.prop(ob, "empty_image_offset", text="Offset Y", index=1)
+ col = layout.column(align=True)
+ col.prop(ob, "empty_image_offset", text="Offset X", index=0)
+ col.prop(ob, "empty_image_offset", text="Y", index=1)
+
+ layout.separator()
layout.prop(ob, "empty_draw_size", text="Size")
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
deleted file mode 100644
index f9394139b42..00000000000
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ /dev/null
@@ -1,414 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-import bpy
-from bpy.types import Menu, Panel
-from rna_prop_ui import PropertyPanel
-
-
-class LAMP_MT_sunsky_presets(Menu):
- bl_label = "Sun & Sky Presets"
- preset_subdir = "sunsky"
- preset_operator = "script.execute_preset"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- draw = Menu.draw_preset
-
-
-class DataButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "data"
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- return context.lamp and (engine in cls.COMPAT_ENGINES)
-
-
-class DATA_PT_context_lamp(DataButtonsPanel, Panel):
- bl_label = ""
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.object
- lamp = context.lamp
- space = context.space_data
-
- split = layout.split(percentage=0.65)
-
- texture_count = len(lamp.texture_slots.keys())
-
- if ob:
- split.template_ID(ob, "data")
- elif lamp:
- split.template_ID(space, "pin_id")
-
- if texture_count != 0:
- split.label(text=str(texture_count), icon='TEXTURE')
-
-
-class DATA_PT_preview(DataButtonsPanel, Panel):
- bl_label = "Preview"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- self.layout.template_preview(context.lamp)
-
-
-class DATA_PT_lamp(DataButtonsPanel, Panel):
- bl_label = "Lamp"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp
-
- layout.row().prop(lamp, "type", expand=True)
-
- split = layout.split()
-
- col = split.column()
- sub = col.column()
- sub.prop(lamp, "color", text="")
- sub.prop(lamp, "energy")
-
- if lamp.type in {'POINT', 'SPOT'}:
- sub.label(text="Falloff:")
- sub.prop(lamp, "falloff_type", text="")
- sub.prop(lamp, "distance")
-
- if lamp.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED':
- col.label(text="Attenuation Factors:")
- sub = col.column(align=True)
- sub.prop(lamp, "linear_attenuation", slider=True, text="Linear")
- sub.prop(lamp, "quadratic_attenuation", slider=True, text="Quadratic")
-
- elif lamp.falloff_type == 'INVERSE_COEFFICIENTS':
- col.label(text="Inverse Coefficients:")
- sub = col.column(align=True)
- sub.prop(lamp, "constant_coefficient", text="Constant")
- sub.prop(lamp, "linear_coefficient", text="Linear")
- sub.prop(lamp, "quadratic_coefficient", text="Quadratic")
-
- col.prop(lamp, "use_sphere")
-
- if lamp.type == 'AREA':
- col.prop(lamp, "distance")
- col.prop(lamp, "gamma")
-
- col = split.column()
- col.prop(lamp, "use_negative")
- col.prop(lamp, "use_own_layer", text="This Layer Only")
- col.prop(lamp, "use_specular")
- col.prop(lamp, "use_diffuse")
-
-
-class DATA_PT_sunsky(DataButtonsPanel, Panel):
- bl_label = "Sky & Atmosphere"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- lamp = context.lamp
- engine = context.scene.render.engine
- return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp.sky
-
- row = layout.row(align=True)
- row.prop(lamp, "use_sky")
- row.menu("LAMP_MT_sunsky_presets", text=bpy.types.LAMP_MT_sunsky_presets.bl_label)
- row.operator("lamp.sunsky_preset_add", text="", icon='ZOOMIN')
- row.operator("lamp.sunsky_preset_add", text="", icon='ZOOMOUT').remove_active = True
-
- row = layout.row()
- row.active = lamp.use_sky or lamp.use_atmosphere
- row.prop(lamp, "atmosphere_turbidity", text="Turbidity")
-
- split = layout.split()
-
- col = split.column()
- col.active = lamp.use_sky
- col.label(text="Blending:")
- sub = col.column()
- sub.prop(lamp, "sky_blend_type", text="")
- sub.prop(lamp, "sky_blend", text="Factor")
-
- col.label(text="Color Space:")
- sub = col.column()
- sub.row().prop(lamp, "sky_color_space", expand=True)
- sub.prop(lamp, "sky_exposure", text="Exposure")
-
- col = split.column()
- col.active = lamp.use_sky
- col.label(text="Horizon:")
- sub = col.column()
- sub.prop(lamp, "horizon_brightness", text="Brightness")
- sub.prop(lamp, "spread", text="Spread")
-
- col.label(text="Sun:")
- sub = col.column()
- sub.prop(lamp, "sun_brightness", text="Brightness")
- sub.prop(lamp, "sun_size", text="Size")
- sub.prop(lamp, "backscattered_light", slider=True, text="Back Light")
-
- layout.separator()
-
- layout.prop(lamp, "use_atmosphere")
-
- split = layout.split()
-
- col = split.column()
- col.active = lamp.use_atmosphere
- col.label(text="Intensity:")
- col.prop(lamp, "sun_intensity", text="Sun")
- col.prop(lamp, "atmosphere_distance_factor", text="Distance")
-
- col = split.column()
- col.active = lamp.use_atmosphere
- col.label(text="Scattering:")
- sub = col.column(align=True)
- sub.prop(lamp, "atmosphere_inscattering", slider=True, text="Inscattering")
- sub.prop(lamp, "atmosphere_extinction", slider=True, text="Extinction")
-
-
-class DATA_PT_shadow(DataButtonsPanel, Panel):
- bl_label = "Shadow"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- lamp = context.lamp
- engine = context.scene.render.engine
- return (lamp and lamp.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp
-
- layout.row().prop(lamp, "shadow_method", expand=True)
-
- if lamp.shadow_method == 'NOSHADOW' and lamp.type == 'AREA':
- split = layout.split()
-
- col = split.column()
- col.label(text="Form Factor Sampling:")
-
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
- sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
- if lamp.shadow_method != 'NOSHADOW':
- split = layout.split()
-
- col = split.column()
- col.prop(lamp, "shadow_color", text="")
-
- col = split.column()
- col.prop(lamp, "use_shadow_layer", text="This Layer Only")
- col.prop(lamp, "use_only_shadow")
-
- if lamp.shadow_method == 'RAY_SHADOW':
- split = layout.split()
-
- col = split.column()
- col.label(text="Sampling:")
-
- if lamp.type in {'POINT', 'SUN', 'SPOT'}:
- sub = col.row()
-
- sub.prop(lamp, "shadow_ray_samples", text="Samples")
- sub.prop(lamp, "shadow_soft_size", text="Soft Size")
-
- elif lamp.type == 'AREA':
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp, "shadow_ray_samples_x", text="Samples X")
- sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y")
-
- col.row().prop(lamp, "shadow_ray_sample_method", expand=True)
-
- if lamp.shadow_ray_sample_method == 'ADAPTIVE_QMC':
- layout.prop(lamp, "shadow_adaptive_threshold", text="Threshold")
-
- if lamp.type == 'AREA' and lamp.shadow_ray_sample_method == 'CONSTANT_JITTERED':
- row = layout.row()
- row.prop(lamp, "use_umbra")
- row.prop(lamp, "use_dither")
- row.prop(lamp, "use_jitter")
-
- elif lamp.shadow_method == 'BUFFER_SHADOW':
- col = layout.column()
- col.label(text="Buffer Type:")
- col.row().prop(lamp, "shadow_buffer_type", expand=True)
-
- if lamp.shadow_buffer_type in {'REGULAR', 'HALFWAY', 'DEEP'}:
- split = layout.split()
-
- col = split.column()
- col.label(text="Filter Type:")
- col.prop(lamp, "shadow_filter_type", text="")
- sub = col.column(align=True)
- sub.prop(lamp, "shadow_buffer_soft", text="Soft")
- sub.prop(lamp, "shadow_buffer_bias", text="Bias")
-
- col = split.column()
- col.label(text="Sample Buffers:")
- col.prop(lamp, "shadow_sample_buffers", text="")
- sub = col.column(align=True)
- sub.prop(lamp, "shadow_buffer_size", text="Size")
- sub.prop(lamp, "shadow_buffer_samples", text="Samples")
- if lamp.shadow_buffer_type == 'DEEP':
- col.prop(lamp, "compression_threshold")
-
- elif lamp.shadow_buffer_type == 'IRREGULAR':
- layout.prop(lamp, "shadow_buffer_bias", text="Bias")
-
- split = layout.split()
-
- col = split.column()
- col.prop(lamp, "use_auto_clip_start", text="Autoclip Start")
- sub = col.column()
- sub.active = not lamp.use_auto_clip_start
- sub.prop(lamp, "shadow_buffer_clip_start", text="Clip Start")
-
- col = split.column()
- col.prop(lamp, "use_auto_clip_end", text="Autoclip End")
- sub = col.column()
- sub.active = not lamp.use_auto_clip_end
- sub.prop(lamp, "shadow_buffer_clip_end", text=" Clip End")
-
-
-class DATA_PT_area(DataButtonsPanel, Panel):
- bl_label = "Area Shape"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- lamp = context.lamp
- engine = context.scene.render.engine
- return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp
-
- col = layout.column()
- col.row().prop(lamp, "shape", expand=True)
- sub = col.row(align=True)
-
- if lamp.shape == 'SQUARE':
- sub.prop(lamp, "size")
- elif lamp.shape == 'RECTANGLE':
- sub.prop(lamp, "size", text="Size X")
- sub.prop(lamp, "size_y", text="Size Y")
-
-
-class DATA_PT_spot(DataButtonsPanel, Panel):
- bl_label = "Spot Shape"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- lamp = context.lamp
- engine = context.scene.render.engine
- return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp
-
- split = layout.split()
-
- col = split.column()
- sub = col.column()
- sub.prop(lamp, "spot_size", text="Size")
- sub.prop(lamp, "spot_blend", text="Blend", slider=True)
- col.prop(lamp, "use_square")
- col.prop(lamp, "show_cone")
-
- col = split.column()
-
- col.active = (lamp.shadow_method != 'BUFFER_SHADOW' or lamp.shadow_buffer_type != 'DEEP')
- col.prop(lamp, "use_halo")
- sub = col.column(align=True)
- sub.active = lamp.use_halo
- sub.prop(lamp, "halo_intensity", text="Intensity")
- if lamp.shadow_method == 'BUFFER_SHADOW':
- sub.prop(lamp, "halo_step", text="Step")
-
-
-class DATA_PT_falloff_curve(DataButtonsPanel, Panel):
- bl_label = "Falloff Curve"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- lamp = context.lamp
- engine = context.scene.render.engine
-
- return (lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE') and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- lamp = context.lamp
-
- self.layout.template_curve_mapping(lamp, "falloff_curve", use_negative_slope=True)
-
-
-class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- _context_path = "object.data"
- _property_type = bpy.types.Lamp
-
-
-classes = (
- LAMP_MT_sunsky_presets,
- DATA_PT_context_lamp,
- DATA_PT_preview,
- DATA_PT_lamp,
- DATA_PT_sunsky,
- DATA_PT_shadow,
- DATA_PT_area,
- DATA_PT_spot,
- DATA_PT_falloff_curve,
- DATA_PT_custom_props_lamp,
-)
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py
index 4b3fd48c195..40e82bc0a52 100644
--- a/release/scripts/startup/bl_ui/properties_data_lattice.py
+++ b/release/scripts/startup/bl_ui/properties_data_lattice.py
@@ -57,28 +57,35 @@ class DATA_PT_lattice(DataButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
lat = context.lattice
- row = layout.row()
- row.prop(lat, "points_u")
- row.prop(lat, "interpolation_type_u", text="")
+ col = layout.column()
- row = layout.row()
- row.prop(lat, "points_v")
- row.prop(lat, "interpolation_type_v", text="")
+ sub = col.column(align=True)
+ sub.prop(lat, "points_u", text="Resolution U")
+ sub.prop(lat, "points_v", text="V")
+ sub.prop(lat, "points_w", text="W")
- row = layout.row()
- row.prop(lat, "points_w")
- row.prop(lat, "interpolation_type_w", text="")
+ col.separator()
- row = layout.row()
- row.prop(lat, "use_outside")
- row.prop_search(lat, "vertex_group", context.object, "vertex_groups", text="")
+ sub = col.column(align=True)
+ sub.prop(lat, "interpolation_type_u", text="Interpolation U")
+ sub.prop(lat, "interpolation_type_v", text="V")
+ sub.prop(lat, "interpolation_type_w", text="W")
+
+ col.separator()
+
+ col.prop(lat, "use_outside")
+
+ col.separator()
+
+ col.prop_search(lat, "vertex_group", context.object, "vertex_groups")
class DATA_PT_custom_props_lattice(DataButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Lattice
diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py
new file mode 100644
index 00000000000..057f7dffce0
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_data_light.py
@@ -0,0 +1,363 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Menu, Panel
+from rna_prop_ui import PropertyPanel
+
+
+class DataButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.engine
+ return context.light and (engine in cls.COMPAT_ENGINES)
+
+
+class DATA_PT_context_light(DataButtonsPanel, Panel):
+ bl_label = ""
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ light = context.light
+ space = context.space_data
+
+ split = layout.split(percentage=0.65)
+
+ if ob:
+ split.template_ID(ob, "data")
+ elif light:
+ split.template_ID(space, "pin_id")
+
+
+class DATA_PT_preview(DataButtonsPanel, Panel):
+ bl_label = "Preview"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ self.layout.template_preview(context.light)
+
+
+class DATA_PT_light(DataButtonsPanel, Panel):
+ bl_label = "Light"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.light
+
+ layout.row().prop(light, "type", expand=True)
+
+ layout.use_property_split = True
+
+ col = col.column()
+ col.prop(light, "color")
+ col.prop(light, "energy")
+
+ if light.type in {'POINT', 'SPOT'}:
+
+ col = col.column()
+ col.label(text="Falloff")
+ col.prop(light, "falloff_type")
+ col.prop(light, "distance")
+ col.prop(light, "shadow_soft_size")
+
+ if light.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED':
+ sub = col.column(align=True)
+ sub.prop(light, "linear_attenuation", slider=True, text="Linear")
+ sub.prop(light, "quadratic_attenuation", slider=True, text="Quadratic")
+
+ elif light.falloff_type == 'INVERSE_COEFFICIENTS':
+ col.label(text="Inverse Coefficients")
+ sub = col.column(align=True)
+ sub.prop(light, "constant_coefficient", text="Constant")
+ sub.prop(light, "linear_coefficient", text="Linear")
+ sub.prop(light, "quadratic_coefficient", text="Quadratic")
+
+ if light.type == 'AREA':
+ col.prop(light, "distance")
+
+ col = split.column()
+ col.label()
+
+
+class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
+ bl_label = "Light"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ light = context.light
+
+ layout.row().prop(light, "type", expand=True)
+
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(light, "color")
+ col.prop(light, "energy")
+ col.prop(light, "specular_factor", text="Specular")
+
+ col.separator()
+
+ if light.type in {'POINT', 'SPOT', 'SUN'}:
+ col.prop(light, "shadow_soft_size", text="Radius")
+ elif light.type == 'AREA':
+ col.prop(light, "shape")
+
+ sub = col.column(align=True)
+
+ if light.shape in {'SQUARE', 'DISK'}:
+ sub.prop(light, "size")
+ elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
+ sub.prop(light, "size", text="Size X")
+ sub.prop(light, "size_y", text="Y")
+
+
+class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
+ bl_label = "Shadow"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+ return (light and light.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ light = context.light
+ self.layout.prop(light, "use_shadow", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ light = context.light
+
+ layout.active = light.use_shadow
+
+ col = layout.column()
+ sub = col.column(align=True)
+ sub.prop(light, "shadow_buffer_clip_start", text="Clip Start")
+ sub.prop(light, "shadow_buffer_clip_end", text="End")
+
+ col.prop(light, "shadow_buffer_soft", text="Softness")
+
+ col.separator()
+
+ col.prop(light, "shadow_buffer_bias", text="Bias")
+ col.prop(light, "shadow_buffer_exp", text="Exponent")
+ col.prop(light, "shadow_buffer_bleed_bias", text="Bleed Bias")
+
+
+class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel):
+ bl_label = "Cascaded Shadow Map"
+ bl_parent_id = "DATA_PT_EEVEE_shadow"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+
+ return (light and light.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ light = context.light
+ layout.use_property_split = True
+
+ col = layout.column()
+
+ col.prop(light, "shadow_cascade_count", text="Count")
+ col.prop(light, "shadow_cascade_fade", text="Fade")
+
+ col.prop(light, "shadow_cascade_max_distance", text="Max Distance")
+ col.prop(light, "shadow_cascade_exponent", text="Distribution")
+
+
+class DATA_PT_EEVEE_shadow_contact(DataButtonsPanel, Panel):
+ bl_label = "Contact Shadows"
+ bl_parent_id = "DATA_PT_EEVEE_shadow"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+ return (light and light.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ light = context.light
+
+ layout = self.layout
+ layout.active = light.use_shadow
+ layout.prop(light, "use_contact_shadow", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ light = context.light
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.active = light.use_shadow and light.use_contact_shadow
+
+ col.prop(light, "contact_shadow_distance", text="Distance")
+ col.prop(light, "contact_shadow_soft_size", text="Softness")
+ col.prop(light, "contact_shadow_bias", text="Bias")
+ col.prop(light, "contact_shadow_thickness", text="Thickness")
+
+
+class DATA_PT_area(DataButtonsPanel, Panel):
+ bl_label = "Area Shape"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+ return (light and light.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.light
+
+ col = layout.column()
+ col.row().prop(light, "shape", expand=True)
+ sub = col.row(align=True)
+
+ if light.shape in {'SQUARE', 'DISK'}:
+ sub.prop(light, "size")
+ elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
+ sub.prop(light, "size", text="Size X")
+ sub.prop(light, "size_y", text="Size Y")
+
+
+class DATA_PT_spot(DataButtonsPanel, Panel):
+ bl_label = "Spot Shape"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+ return (light and light.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ light = context.light
+
+ split = layout.split()
+
+ col = split.column()
+ sub = col.column()
+ sub.prop(light, "spot_size", text="Size")
+ sub.prop(light, "spot_blend", text="Blend", slider=True)
+ col.prop(light, "use_square")
+ col.prop(light, "show_cone")
+
+ col = split.column()
+
+ col.active = (light.shadow_method != 'BUFFER_SHADOW' or light.shadow_buffer_type != 'DEEP')
+ col.prop(light, "use_halo")
+ sub = col.column(align=True)
+ sub.active = light.use_halo
+ sub.prop(light, "halo_intensity", text="Intensity")
+ if light.shadow_method == 'BUFFER_SHADOW':
+ sub.prop(light, "halo_step", text="Step")
+
+
+class DATA_PT_spot(DataButtonsPanel, Panel):
+ bl_label = "Spot Shape"
+ bl_parent_id = "DATA_PT_EEVEE_light"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+ return (light and light.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ light = context.light
+
+ col = layout.column()
+
+ col.prop(light, "spot_size", text="Size")
+ col.prop(light, "spot_blend", text="Blend", slider=True)
+
+ col.prop(light, "show_cone")
+
+
+class DATA_PT_falloff_curve(DataButtonsPanel, Panel):
+ bl_label = "Falloff Curve"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ light = context.light
+ engine = context.engine
+
+ return (light and light.type in {'POINT', 'SPOT'} and light.falloff_type == 'CUSTOM_CURVE') and (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ light = context.light
+
+ self.layout.template_curve_mapping(light, "falloff_curve", use_negative_slope=True)
+
+
+class DATA_PT_custom_props_light(DataButtonsPanel, PropertyPanel, Panel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+ _context_path = "object.data"
+ _property_type = bpy.types.Light
+
+
+classes = (
+ DATA_PT_context_light,
+ DATA_PT_preview,
+ DATA_PT_light,
+ DATA_PT_EEVEE_light,
+ DATA_PT_EEVEE_shadow,
+ DATA_PT_EEVEE_shadow_contact,
+ DATA_PT_EEVEE_shadow_cascaded_shadow_map,
+ DATA_PT_area,
+ DATA_PT_spot,
+ DATA_PT_falloff_curve,
+ DATA_PT_custom_props_light,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_data_lightprobe.py b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
new file mode 100644
index 00000000000..10b66dd0033
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
@@ -0,0 +1,185 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Panel
+
+
+class DataButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.engine
+ return context.lightprobe and (engine in cls.COMPAT_ENGINES)
+
+
+class DATA_PT_context_lightprobe(DataButtonsPanel, Panel):
+ bl_label = ""
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ probe = context.lightprobe
+ space = context.space_data
+
+ if ob:
+ layout.template_ID(ob, "data")
+ elif probe:
+ layout.template_ID(space, "pin_id")
+
+
+class DATA_PT_lightprobe(DataButtonsPanel, Panel):
+ bl_label = "Probe"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+ probe = context.lightprobe
+
+# layout.prop(probe, "type")
+
+ if probe.type == 'GRID':
+ col = layout.column()
+ col.prop(probe, "influence_distance", "Distance")
+ col.prop(probe, "falloff")
+ col.prop(probe, "intensity")
+
+ col.separator()
+
+ col.prop(probe, "grid_resolution_x", text="Resolution X")
+ col.prop(probe, "grid_resolution_y", text="Y")
+ col.prop(probe, "grid_resolution_z", text="Z")
+
+ elif probe.type == 'PLANAR':
+ col = layout.column()
+ col.prop(probe, "influence_distance", "Distance")
+ col.prop(probe, "falloff")
+ else:
+ col = layout.column()
+ col.prop(probe, "influence_type")
+
+ if probe.influence_type == 'ELIPSOID':
+ col.prop(probe, "influence_distance", "Radius")
+ else:
+ col.prop(probe, "influence_distance", "Size")
+
+ col.prop(probe, "falloff")
+ col.prop(probe, "intensity")
+
+ col = layout.column()
+ sub = col.column()
+ sub.prop(probe, "clip_start", text="Clipping Start")
+
+ if probe.type != "PLANAR":
+ sub.prop(probe, "clip_end", text="End")
+
+ if probe.type == 'GRID':
+ col.separator()
+ col.label("Visibility")
+ col.prop(probe, "visibility_buffer_bias", "Bias")
+ col.prop(probe, "visibility_bleed_bias", "Bleed Bias")
+ col.prop(probe, "visibility_blur", "Blur")
+
+ col.separator()
+
+ row = col.row(align=True)
+ row.prop(probe, "visibility_collection")
+ row.prop(probe, "invert_visibility_collection", text="", icon='ARROW_LEFTRIGHT')
+
+
+class DATA_PT_lightprobe_parallax(DataButtonsPanel, Panel):
+ bl_label = "Custom Parallax"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ engine = context.engine
+ return context.lightprobe and context.lightprobe.type == 'CUBEMAP' and (engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ probe = context.lightprobe
+ self.layout.prop(probe, "use_custom_parallax", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ probe = context.lightprobe
+
+ col = layout.column()
+ col.active = probe.use_custom_parallax
+
+ col.prop(probe, "parallax_type")
+
+ if probe.parallax_type == 'ELIPSOID':
+ col.prop(probe, "parallax_distance", "Radius")
+ else:
+ col.prop(probe, "parallax_distance", "Size")
+
+
+class DATA_PT_lightprobe_display(DataButtonsPanel, Panel):
+ bl_label = "Display"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+ probe = context.lightprobe
+
+ col = layout.column()
+
+ if probe.type != 'PLANAR':
+ col.prop(probe, "data_draw_size", text="Size")
+ else:
+ col.prop(ob, "empty_draw_size", text="Arrow Size")
+
+ col.prop(probe, "show_data")
+
+ if probe.type in {'GRID', 'CUBEMAP'}:
+ col.prop(probe, "show_influence")
+ col.prop(probe, "show_clip")
+
+ if probe.type == 'CUBEMAP':
+ sub = col.column()
+ sub.active = probe.use_custom_parallax
+ sub.prop(probe, "show_parallax")
+
+
+classes = (
+ DATA_PT_context_lightprobe,
+ DATA_PT_lightprobe,
+ DATA_PT_lightprobe_parallax,
+ DATA_PT_lightprobe_display,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 2ab9aa2e93f..e8015327c1d 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -24,7 +24,7 @@ from rna_prop_ui import PropertyPanel
class MESH_MT_vertex_group_specials(Menu):
bl_label = "Vertex Group Specials"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -48,7 +48,7 @@ class MESH_MT_vertex_group_specials(Menu):
class MESH_MT_shape_key_specials(Menu):
bl_label = "Shape Key Specials"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -76,6 +76,17 @@ class MESH_UL_vgroups(UIList):
layout.label(text="", icon_value=icon)
+class MESH_UL_fmaps(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.FaceMap))
+ fmap = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ layout.prop(fmap, "name", text="", emboss=False, icon_value=icon)
+ elif self.layout_type in {'GRID'}:
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
class MESH_UL_shape_keys(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# assert(isinstance(item, bpy.types.ShapeKey))
@@ -119,14 +130,14 @@ class MeshButtonsPanel:
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
+ engine = context.engine
return context.mesh and (engine in cls.COMPAT_ENGINES)
class DATA_PT_context_mesh(MeshButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -143,31 +154,31 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel):
class DATA_PT_normals(MeshButtonsPanel, Panel):
bl_label = "Normals"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
mesh = context.mesh
- split = layout.split()
+ col = layout.column()
+ col.prop(mesh, "show_double_sided")
- col = split.column()
col.prop(mesh, "use_auto_smooth")
sub = col.column()
sub.active = mesh.use_auto_smooth and not mesh.has_custom_normals
sub.prop(mesh, "auto_smooth_angle", text="Angle")
- split.prop(mesh, "show_double_sided")
-
class DATA_PT_texture_space(MeshButtonsPanel, Panel):
bl_label = "Texture Space"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
mesh = context.mesh
@@ -176,18 +187,18 @@ class DATA_PT_texture_space(MeshButtonsPanel, Panel):
layout.separator()
layout.prop(mesh, "use_auto_texspace")
- row = layout.row()
- row.column().prop(mesh, "texspace_location", text="Location")
- row.column().prop(mesh, "texspace_size", text="Size")
+
+ layout.prop(mesh, "texspace_location", text="Location")
+ layout.prop(mesh, "texspace_size", text="Size")
class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
bl_label = "Vertex Groups"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
+ engine = context.engine
obj = context.object
return (obj and obj.type in {'MESH', 'LATTICE'} and (engine in cls.COMPAT_ENGINES))
@@ -228,13 +239,55 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
+class DATA_PT_face_maps(MeshButtonsPanel, Panel):
+ bl_label = "Face Maps"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ obj = context.object
+ return (obj and obj.type == 'MESH')
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ facemap = ob.face_maps.active
+
+ rows = 2
+ if facemap:
+ rows = 4
+
+ row = layout.row()
+ row.template_list("MESH_UL_fmaps", "", ob, "face_maps", ob.face_maps, "active_index", rows=rows)
+
+ col = row.column(align=True)
+ col.operator("object.face_map_add", icon='ZOOMIN', text="")
+ col.operator("object.face_map_remove", icon='ZOOMOUT', text="")
+ if facemap:
+ col.separator()
+ col.operator("object.face_map_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("object.face_map_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+ if ob.face_maps and (ob.mode == 'EDIT' and ob.type == 'MESH'):
+ row = layout.row()
+
+ sub = row.row(align=True)
+ sub.operator("object.face_map_assign", text="Assign")
+ sub.operator("object.face_map_remove_from", text="Remove")
+
+ sub = row.row(align=True)
+ sub.operator("object.face_map_select", text="Select")
+ sub.operator("object.face_map_deselect", text="Deselect")
+
+
class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
bl_label = "Shape Keys"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
+ engine = context.engine
obj = context.object
return (obj and obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'} and (engine in cls.COMPAT_ENGINES))
@@ -300,19 +353,16 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
row.active = enable_edit_value
row.prop(kb, "value")
- split = layout.split()
+ layout.use_property_split = True
- col = split.column(align=True)
- col.active = enable_edit_value
- col.label(text="Range:")
- col.prop(kb, "slider_min", text="Min")
- col.prop(kb, "slider_max", text="Max")
+ col = layout.column()
+ sub.active = enable_edit_value
+ sub = col.column(align=True)
+ sub.prop(kb, "slider_min", text="Range Min")
+ sub.prop(kb, "slider_max", text="Max")
- col = split.column(align=True)
- col.active = enable_edit_value
- col.label(text="Blend:")
- col.prop_search(kb, "vertex_group", ob, "vertex_groups", text="")
- col.prop_search(kb, "relative_key", key, "key_blocks", text="")
+ col.prop_search(kb, "vertex_group", ob, "vertex_groups", text="Vertex Group")
+ col.prop_search(kb, "relative_key", key, "key_blocks", text="Relative To")
else:
layout.prop(kb, "interpolation")
@@ -323,7 +373,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
bl_label = "UV Maps"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -333,7 +383,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
row = layout.row()
col = row.column()
- col.template_list("MESH_UL_uvmaps_vcols", "uvmaps", me, "uv_textures", me.uv_textures, "active_index", rows=1)
+ col.template_list("MESH_UL_uvmaps_vcols", "uvmaps", me, "uv_layers", me.uv_layers, "active_index", rows=1)
col = row.column(align=True)
col.operator("mesh.uv_texture_add", icon='ZOOMIN', text="")
@@ -342,7 +392,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
bl_label = "Vertex Colors"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -362,10 +412,11 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
class DATA_PT_customdata(MeshButtonsPanel, Panel):
bl_label = "Geometry Data"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
obj = context.object
me = context.mesh
@@ -388,7 +439,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Mesh
@@ -397,12 +448,14 @@ classes = (
MESH_MT_vertex_group_specials,
MESH_MT_shape_key_specials,
MESH_UL_vgroups,
+ MESH_UL_fmaps,
MESH_UL_shape_keys,
MESH_UL_uvmaps_vcols,
DATA_PT_context_mesh,
DATA_PT_normals,
DATA_PT_texture_space,
DATA_PT_vertex_groups,
+ DATA_PT_face_maps,
DATA_PT_shape_keys,
DATA_PT_uv_texture,
DATA_PT_vertex_colors,
diff --git a/release/scripts/startup/bl_ui/properties_data_metaball.py b/release/scripts/startup/bl_ui/properties_data_metaball.py
index dd62c4523b1..2a61e6cda79 100644
--- a/release/scripts/startup/bl_ui/properties_data_metaball.py
+++ b/release/scripts/startup/bl_ui/properties_data_metaball.py
@@ -54,40 +54,36 @@ class DATA_PT_metaball(DataButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
mball = context.meta_ball
- split = layout.split()
-
- col = split.column()
+ col = layout.column()
col.label(text="Resolution:")
sub = col.column(align=True)
- sub.prop(mball, "resolution", text="View")
+ sub.prop(mball, "resolution", text="Resolution View")
sub.prop(mball, "render_resolution", text="Render")
- col = split.column()
- col.label(text="Settings:")
col.prop(mball, "threshold", text="Threshold")
-
- layout.label(text="Update:")
- layout.row().prop(mball, "update_method", expand=True)
+ col.prop(mball, "update_method")
class DATA_PT_mball_texture_space(DataButtonsPanel, Panel):
bl_label = "Texture Space"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
mball = context.meta_ball
layout.prop(mball, "use_auto_texspace")
- row = layout.row()
- row.column().prop(mball, "texspace_location", text="Location")
- row.column().prop(mball, "texspace_size", text="Size")
+ col = layout.column()
+ col.prop(mball, "texspace_location")
+ col.prop(mball, "texspace_size")
class DATA_PT_metaball_element(DataButtonsPanel, Panel):
@@ -99,39 +95,37 @@ class DATA_PT_metaball_element(DataButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
metaelem = context.meta_ball.elements.active
- layout.prop(metaelem, "type")
+ col = layout.column()
- split = layout.split()
+ col.prop(metaelem, "type")
+
+ col.separator()
- col = split.column(align=True)
- col.label(text="Settings:")
col.prop(metaelem, "stiffness", text="Stiffness")
col.prop(metaelem, "use_negative", text="Negative")
col.prop(metaelem, "hide", text="Hide")
- col = split.column(align=True)
+ sub = col.column(align=True)
if metaelem.type in {'CUBE', 'ELLIPSOID'}:
- col.label(text="Size:")
- col.prop(metaelem, "size_x", text="X")
- col.prop(metaelem, "size_y", text="Y")
- col.prop(metaelem, "size_z", text="Z")
+ sub.prop(metaelem, "size_x", text="Size X")
+ sub.prop(metaelem, "size_y", text="Y")
+ sub.prop(metaelem, "size_z", text="Z")
elif metaelem.type == 'TUBE':
- col.label(text="Size:")
- col.prop(metaelem, "size_x", text="X")
+ sub.prop(metaelem, "size_x", text="Size X")
elif metaelem.type == 'PLANE':
- col.label(text="Size:")
- col.prop(metaelem, "size_x", text="X")
- col.prop(metaelem, "size_y", text="Y")
+ sub.prop(metaelem, "size_x", text="Size X")
+ sub.prop(metaelem, "size_y", text="Y")
class DATA_PT_custom_props_metaball(DataButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.MetaBall
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index a147950a36d..03ebea69d2b 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -327,8 +327,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.prop(md, "delimit")
layout_info = layout
- layout_info.label(text=iface_("Face Count: {:,}".format(md.face_count)),
- translate=False)
+ layout_info.label(
+ text=iface_("Face Count: {:,}".format(md.face_count)),
+ translate=False,
+ )
def DISPLACE(self, layout, ob, md):
has_texture = (md.texture is not None)
@@ -357,7 +359,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "texture_coords_object", text="")
elif md.texture_coords == 'UV' and ob.type == 'MESH':
col.label(text="UV Map:")
- col.prop_search(md, "uv_layer", ob.data, "uv_textures", text="")
+ col.prop_search(md, "uv_layer", ob.data, "uv_layers", text="")
layout.separator()
@@ -389,7 +391,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
sub.active = bool(md.vertex_group)
sub.prop(md, "protect")
col.label(text="Particle UV")
- col.prop_search(md, "particle_uv", ob.data, "uv_textures", text="")
+ col.prop_search(md, "particle_uv", ob.data, "uv_layers", text="")
col = split.column()
col.prop(md, "use_edge_cut")
@@ -951,7 +953,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
scene = context.scene
- engine = scene.render.engine
+ engine = context.engine
show_adaptive_options = (
engine == 'CYCLES' and md == ob.modifiers[-1] and
scene.cycles.feature_set == 'EXPERIMENTAL'
@@ -1014,18 +1016,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
def UV_PROJECT(self, layout, ob, md):
split = layout.split()
-
- col = split.column()
- col.label(text="Image:")
- col.prop(md, "image", text="")
-
col = split.column()
- col.label(text="UV Map:")
- col.prop_search(md, "uv_layer", ob.data, "uv_textures", text="")
+ col.prop_search(md, "uv_layer", ob.data, "uv_layers")
+ col.separator()
- split = layout.split()
- col = split.column()
- col.prop(md, "use_image_override")
col.prop(md, "projector_count", text="Projectors")
for proj in md.projectors:
col.prop(proj, "object", text="")
@@ -1079,7 +1073,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
if md.texture_coords == 'OBJECT':
layout.prop(md, "texture_coords_object", text="Object")
elif md.texture_coords == 'UV' and ob.type == 'MESH':
- layout.prop_search(md, "uv_layer", ob.data, "uv_textures")
+ layout.prop_search(md, "uv_layer", ob.data, "uv_layers")
def WAVE(self, layout, ob, md):
split = layout.split()
@@ -1125,7 +1119,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.template_ID(md, "texture", new="texture.new")
layout.prop(md, "texture_coords")
if md.texture_coords == 'UV' and ob.type == 'MESH':
- layout.prop_search(md, "uv_layer", ob.data, "uv_textures")
+ layout.prop_search(md, "uv_layer", ob.data, "uv_layers")
elif md.texture_coords == 'OBJECT':
layout.prop(md, "texture_coords_object")
@@ -1192,7 +1186,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
if md.mask_tex_mapping == 'OBJECT':
layout.prop(md, "mask_tex_map_object", text="Object")
elif md.mask_tex_mapping == 'UV' and ob.type == 'MESH':
- layout.prop_search(md, "mask_tex_uv_layer", ob.data, "uv_textures")
+ layout.prop_search(md, "mask_tex_uv_layer", ob.data, "uv_layers")
def VERTEX_WEIGHT_EDIT(self, layout, ob, md):
split = layout.split()
@@ -1361,7 +1355,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.label(text="UV Map:")
- col.prop_search(md, "uv_layer", ob.data, "uv_textures", text="")
+ col.prop_search(md, "uv_layer", ob.data, "uv_layers", text="")
def WIREFRAME(self, layout, ob, md):
has_vgroup = bool(md.vertex_group)
diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py
index eecb2690302..2a3dc4d02c1 100644
--- a/release/scripts/startup/bl_ui/properties_data_speaker.py
+++ b/release/scripts/startup/bl_ui/properties_data_speaker.py
@@ -29,14 +29,14 @@ class DataButtonsPanel:
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
+ engine = context.engine
return context.speaker and (engine in cls.COMPAT_ENGINES)
class DATA_PT_context_speaker(DataButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -55,69 +55,73 @@ class DATA_PT_context_speaker(DataButtonsPanel, Panel):
class DATA_PT_speaker(DataButtonsPanel, Panel):
bl_label = "Sound"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
speaker = context.speaker
- split = layout.split(percentage=0.75)
+ layout.template_ID(speaker, "sound", open="sound.open_mono")
- split.template_ID(speaker, "sound", open="sound.open_mono")
- split.prop(speaker, "muted")
+ layout.use_property_split = True
- row = layout.row()
- row.prop(speaker, "volume")
- row.prop(speaker, "pitch")
+ layout.prop(speaker, "muted")
+
+ col = layout.column()
+ col.active = not speaker.muted
+ col.prop(speaker, "volume", slider=True)
+ col.prop(speaker, "pitch")
class DATA_PT_distance(DataButtonsPanel, Panel):
bl_label = "Distance"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
- speaker = context.speaker
+ layout.use_property_split = True
- split = layout.split()
+ speaker = context.speaker
+ layout.active = not speaker.muted
- col = split.column()
- col.label("Volume:")
- col.prop(speaker, "volume_min", text="Minimum")
- col.prop(speaker, "volume_max", text="Maximum")
+ col = layout.column()
+ sub = col.column(align=True)
+ sub.prop(speaker, "volume_min", slider=True, text="Volume Min")
+ sub.prop(speaker, "volume_max", slider=True, text="Max")
col.prop(speaker, "attenuation")
- col = split.column()
- col.label("Distance:")
- col.prop(speaker, "distance_max", text="Maximum")
- col.prop(speaker, "distance_reference", text="Reference")
+ col.separator()
+ col.prop(speaker, "distance_max", text="Max Distance")
+ col.prop(speaker, "distance_reference", text="Distance Reference")
class DATA_PT_cone(DataButtonsPanel, Panel):
bl_label = "Cone"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
speaker = context.speaker
+ layout.active = not speaker.muted
+
+ col = layout.column()
- split = layout.split()
+ sub = col.column(align=True)
+ sub.prop(speaker, "cone_angle_outer", text="Angle Outer")
+ sub.prop(speaker, "cone_angle_inner", text="Inner")
- col = split.column()
- col.label("Angle:")
- col.prop(speaker, "cone_angle_outer", text="Outer")
- col.prop(speaker, "cone_angle_inner", text="Inner")
+ col.separator()
- col = split.column()
- col.label("Volume:")
- col.prop(speaker, "cone_volume_outer", text="Outer")
+ col.prop(speaker, "cone_volume_outer", slider=True)
class DATA_PT_custom_props_speaker(DataButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Speaker
diff --git a/release/scripts/startup/bl_ui/properties_data_workspace.py b/release/scripts/startup/bl_ui/properties_data_workspace.py
new file mode 100644
index 00000000000..3cda3dd0abd
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_data_workspace.py
@@ -0,0 +1,101 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import (
+ Panel,
+)
+
+from rna_prop_ui import PropertyPanel
+
+
+class WorkSpaceButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "workspace"
+
+
+class WORKSPACE_PT_owner_ids(WorkSpaceButtonsPanel, Panel):
+ bl_label = "Workspace Add-ons"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_header(self, context):
+ workspace = context.workspace
+ self.layout.prop(workspace, "use_filter_by_owner", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ # align just to pack more tightly
+ col = layout.box().column(align=True)
+
+ workspace = context.workspace
+ userpref = context.user_preferences
+
+ col.active = workspace.use_filter_by_owner
+
+ import addon_utils
+ addon_map = {mod.__name__: mod for mod in addon_utils.modules()}
+ owner_ids = {owner_id.name for owner_id in workspace.owner_ids}
+
+ for addon in userpref.addons:
+ module_name = addon.module
+ info = addon_utils.module_bl_info(addon_map[module_name])
+ if not info["use_owner"]:
+ continue
+ is_enabled = module_name in owner_ids
+ row = col.row()
+ row.operator(
+ "wm.owner_disable" if is_enabled else "wm.owner_enable",
+ icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT',
+ text="",
+ emboss=False,
+ ).owner_id = module_name
+ row.label("%s: %s" % (info["category"], info["name"]))
+ if is_enabled:
+ owner_ids.remove(module_name)
+
+ # Detect unused
+ if owner_ids:
+ layout.label(text="Unknown add-ons", icon='ERROR')
+ col = layout.box().column(align=True)
+ for module_name in sorted(owner_ids):
+ row = col.row()
+ row.operator(
+ "wm.owner_disable",
+ icon='CHECKBOX_HLT',
+ text="",
+ emboss=False,
+ ).owner_id = module_name
+ row.label(module_name)
+
+
+class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel):
+ _context_path = "workspace"
+ _property_type = bpy.types.WorkSpace
+
+
+classes = (
+ WORKSPACE_PT_owner_ids,
+ WORKSPACE_PT_custom_props,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index 7b656f9be81..12ecbeb3e6b 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -33,13 +33,13 @@ class RenderFreestyleButtonsPanel:
def poll(cls, context):
scene = context.scene
with_freestyle = bpy.app.build_options.freestyle
- return scene and with_freestyle and(scene.render.engine in cls.COMPAT_ENGINES)
+ return scene and with_freestyle and(context.engine in cls.COMPAT_ENGINES)
class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel):
bl_label = "Freestyle"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
rd = context.scene.render
@@ -62,34 +62,34 @@ class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel):
# Render layer properties
-class RenderLayerFreestyleButtonsPanel:
+class ViewLayerFreestyleButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
- bl_context = "render_layer"
+ bl_context = "view_layer"
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
@classmethod
def poll(cls, context):
scene = context.scene
- rd = context.scene.render
+ rd = scene.render
with_freestyle = bpy.app.build_options.freestyle
return (scene and with_freestyle and rd.use_freestyle and
- rd.layers.active and(scene.render.engine in cls.COMPAT_ENGINES))
+ (context.engine in cls.COMPAT_ENGINES))
-class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel):
+class ViewLayerFreestyleEditorButtonsPanel(ViewLayerFreestyleButtonsPanel):
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
@classmethod
def poll(cls, context):
if not super().poll(context):
return False
- rl = context.scene.render.layers.active
- return rl and rl.freestyle_settings.mode == 'EDITOR'
+ view_layer = context.view_layer
+ return view_layer and view_layer.freestyle_settings.mode == 'EDITOR'
-class RENDERLAYER_UL_linesets(UIList):
+class VIEWLAYER_UL_linesets(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
lineset = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
@@ -109,18 +109,18 @@ class RENDER_MT_lineset_specials(Menu):
layout.operator("scene.freestyle_lineset_paste", icon='PASTEDOWN')
-class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel):
+class VIEWLAYER_PT_freestyle(ViewLayerFreestyleButtonsPanel, Panel):
bl_label = "Freestyle"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
- rd = context.scene.render
- rl = rd.layers.active
- freestyle = rl.freestyle_settings
+ scene = context.scene
+ view_layer = context.view_layer
+ freestyle = view_layer.freestyle_settings
- layout.active = rl.use_freestyle
+ layout.active = view_layer.use_freestyle
row = layout.row()
layout.prop(freestyle, "mode", text="Control Mode")
@@ -165,9 +165,9 @@ class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel):
row.operator("scene.freestyle_module_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
-class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, Panel):
+class VIEWLAYER_PT_freestyle_lineset(ViewLayerFreestyleEditorButtonsPanel, Panel):
bl_label = "Freestyle Line Set"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_edge_type_buttons(self, box, lineset, edge_type):
# property names
@@ -183,16 +183,18 @@ class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, P
def draw(self, context):
layout = self.layout
- rd = context.scene.render
- rl = rd.layers.active
- freestyle = rl.freestyle_settings
+ scene = context.scene
+ rd = scene.render
+
+ view_layer = context.view_layer
+ freestyle = view_layer.freestyle_settings
lineset = freestyle.linesets.active
- layout.active = rl.use_freestyle
+ layout.active = view_layer.use_freestyle
row = layout.row()
rows = 4 if lineset else 2
- row.template_list("RENDERLAYER_UL_linesets", "", freestyle, "linesets", freestyle.linesets, "active_index", rows=rows)
+ row.template_list("VIEWLAYER_UL_linesets", "", freestyle, "linesets", freestyle.linesets, "active_index", rows=rows)
sub = row.column(align=True)
sub.operator("scene.freestyle_lineset_add", icon='ZOOMIN', text="")
@@ -256,10 +258,10 @@ class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, P
row.prop(lineset, "group_negation", expand=True)
-class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, Panel):
+class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Panel):
bl_label = "Freestyle Line Style"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_modifier_box_header(self, box, modifier):
row = box.row()
@@ -376,7 +378,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
row = box.row(align=True)
row.prop(modifier, "curvature_min")
row.prop(modifier, "curvature_max")
- freestyle = context.scene.render.layers.active.freestyle_settings
+ freestyle = context.view_layer.freestyle_settings
if not freestyle.use_smoothness:
message = "Enable Face Smoothness to use this modifier"
self.draw_modifier_box_error(col.box(), modifier, message)
@@ -431,7 +433,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
row = box.row(align=True)
row.prop(modifier, "curvature_min")
row.prop(modifier, "curvature_max")
- freestyle = context.scene.render.layers.active.freestyle_settings
+ freestyle = context.view_layer.freestyle_settings
if not freestyle.use_smoothness:
message = "Enable Face Smoothness to use this modifier"
self.draw_modifier_box_error(col.box(), modifier, message)
@@ -503,7 +505,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
row = box.row(align=True)
row.prop(modifier, "curvature_min")
row.prop(modifier, "curvature_max")
- freestyle = context.scene.render.layers.active.freestyle_settings
+ freestyle = context.view_layer.freestyle_settings
if not freestyle.use_smoothness:
message = "Enable Face Smoothness to use this modifier"
self.draw_modifier_box_error(col.box(), modifier, message)
@@ -611,11 +613,11 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
def draw(self, context):
layout = self.layout
- rd = context.scene.render
- rl = rd.layers.active
- lineset = rl.freestyle_settings.linesets.active
+ scene = context.scene
+ view_layer = context.view_layer
+ lineset = view_layer.freestyle_settings.linesets.active
- layout.active = rl.use_freestyle
+ layout.active = view_layer.use_freestyle
if lineset is None:
return
@@ -779,10 +781,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
layout.separator()
row = layout.row()
- if rd.use_shading_nodes:
- row.prop(linestyle, "use_nodes")
- else:
- row.prop(linestyle, "use_texture")
+ row.prop(linestyle, "use_nodes")
row.prop(linestyle, "texture_spacing", text="Spacing Along Stroke")
row = layout.row()
@@ -811,13 +810,13 @@ class MaterialFreestyleButtonsPanel:
material = context.material
with_freestyle = bpy.app.build_options.freestyle
return with_freestyle and material and scene and scene.render.use_freestyle and \
- (scene.render.engine in cls.COMPAT_ENGINES)
+ (context.engine in cls.COMPAT_ENGINES)
class MATERIAL_PT_freestyle_line(MaterialFreestyleButtonsPanel, Panel):
bl_label = "Freestyle Line"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -831,11 +830,11 @@ class MATERIAL_PT_freestyle_line(MaterialFreestyleButtonsPanel, Panel):
classes = (
RENDER_PT_freestyle,
- RENDERLAYER_UL_linesets,
+ VIEWLAYER_UL_linesets,
RENDER_MT_lineset_specials,
- RENDERLAYER_PT_freestyle,
- RENDERLAYER_PT_freestyle_lineset,
- RENDERLAYER_PT_freestyle_linestyle,
+ VIEWLAYER_PT_freestyle,
+ VIEWLAYER_PT_freestyle_lineset,
+ VIEWLAYER_PT_freestyle_linestyle,
MATERIAL_PT_freestyle_line,
)
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
deleted file mode 100644
index ac51b97e87d..00000000000
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ /dev/null
@@ -1,881 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-import bpy
-from bpy.types import Panel, Menu
-
-
-class PhysicsButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "physics"
-
-
-class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
- bl_label = "Physics"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- ob = context.active_object
- rd = context.scene.render
- return ob and ob.game and (rd.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.active_object
- game = ob.game
- soft = ob.game.soft_body
-
- layout.prop(game, "physics_type")
- layout.separator()
-
- physics_type = game.physics_type
-
- if physics_type == 'CHARACTER':
- layout.prop(game, "use_actor")
- layout.prop(ob, "hide_render", text="Invisible") # out of place but useful
- layout.prop(game, "step_height", slider=True)
- layout.prop(game, "jump_speed")
- layout.prop(game, "fall_speed")
- layout.prop(game, "jump_max")
-
- elif physics_type in {'DYNAMIC', 'RIGID_BODY'}:
- split = layout.split()
-
- col = split.column()
- col.prop(game, "use_actor")
- col.prop(game, "use_ghost")
- col.prop(ob, "hide_render", text="Invisible") # out of place but useful
-
- col = split.column()
- col.prop(game, "use_material_physics_fh")
- col.prop(game, "use_rotate_from_normal")
- col.prop(game, "use_sleep")
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Attributes:")
- col.prop(game, "mass")
- col.prop(game, "radius")
- col.prop(game, "form_factor")
-
- col = split.column()
- sub = col.column()
- sub.prop(game, "use_anisotropic_friction")
- subsub = sub.column()
- subsub.active = game.use_anisotropic_friction
- subsub.prop(game, "friction_coefficients", text="", slider=True)
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Linear Velocity:")
- sub = col.column(align=True)
- sub.prop(game, "velocity_min", text="Minimum")
- sub.prop(game, "velocity_max", text="Maximum")
- col.label(text="Angular Velocity:")
- sub = col.column(align=True)
- sub.prop(game, "angular_velocity_min", text="Minimum")
- sub.prop(game, "angular_velocity_max", text="Maximum")
-
- col = split.column()
- col.label(text="Damping:")
- sub = col.column(align=True)
- sub.prop(game, "damping", text="Translation", slider=True)
- sub.prop(game, "rotation_damping", text="Rotation", slider=True)
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Lock Translation:")
- col.prop(game, "lock_location_x", text="X")
- col.prop(game, "lock_location_y", text="Y")
- col.prop(game, "lock_location_z", text="Z")
-
- if physics_type == 'RIGID_BODY':
- col = split.column()
- col.label(text="Lock Rotation:")
- col.prop(game, "lock_rotation_x", text="X")
- col.prop(game, "lock_rotation_y", text="Y")
- col.prop(game, "lock_rotation_z", text="Z")
-
- elif physics_type == 'SOFT_BODY':
- col = layout.column()
- col.prop(game, "use_actor")
- col.prop(game, "use_ghost")
- col.prop(ob, "hide_render", text="Invisible")
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Attributes:")
- col.prop(game, "mass")
- # disabled in the code
- # col.prop(soft, "weld_threshold")
- col.prop(soft, "location_iterations")
- col.prop(soft, "linear_stiffness", slider=True)
- col.prop(soft, "dynamic_friction", slider=True)
- col.prop(soft, "collision_margin", slider=True)
- col.prop(soft, "use_bending_constraints", text="Bending Constraints")
-
- col = split.column()
- col.prop(soft, "use_shape_match")
- sub = col.column()
- sub.active = soft.use_shape_match
- sub.prop(soft, "shape_threshold", slider=True)
-
- col.separator()
-
- col.label(text="Cluster Collision:")
- col.prop(soft, "use_cluster_rigid_to_softbody")
- col.prop(soft, "use_cluster_soft_to_softbody")
- sub = col.column()
- sub.active = (soft.use_cluster_rigid_to_softbody or soft.use_cluster_soft_to_softbody)
- sub.prop(soft, "cluster_iterations", text="Iterations")
-
- elif physics_type == 'STATIC':
- col = layout.column()
- col.prop(game, "use_actor")
- col.prop(game, "use_ghost")
- col.prop(game, "use_record_animation")
- col.prop(ob, "hide_render", text="Invisible")
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Attributes:")
- col.prop(game, "radius")
-
- col = split.column()
- sub = col.column()
- sub.prop(game, "use_anisotropic_friction")
- subsub = sub.column()
- subsub.active = game.use_anisotropic_friction
- subsub.prop(game, "friction_coefficients", text="", slider=True)
-
- elif physics_type == 'SENSOR':
- col = layout.column()
- col.prop(game, "use_actor", text="Detect Actors")
- col.prop(ob, "hide_render", text="Invisible")
-
- elif physics_type in {'INVISIBLE', 'NO_COLLISION', 'OCCLUDER'}:
- layout.prop(ob, "hide_render", text="Invisible")
-
- elif physics_type == 'NAVMESH':
- layout.operator("mesh.navmesh_face_copy")
- layout.operator("mesh.navmesh_face_add")
-
- layout.separator()
-
- layout.operator("mesh.navmesh_reset")
- layout.operator("mesh.navmesh_clear")
-
-
-class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel):
- bl_label = "Collision Bounds"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- game = context.object.game
- rd = context.scene.render
- return (rd.engine in cls.COMPAT_ENGINES) \
- and (game.physics_type in {'SENSOR', 'STATIC', 'DYNAMIC', 'RIGID_BODY', 'CHARACTER', 'SOFT_BODY'})
-
- def draw_header(self, context):
- game = context.active_object.game
-
- self.layout.prop(game, "use_collision_bounds", text="")
-
- def draw(self, context):
- layout = self.layout
-
- game = context.active_object.game
- split = layout.split()
- split.active = game.use_collision_bounds
-
- col = split.column()
- col.prop(game, "collision_bounds_type", text="Bounds")
-
- row = col.row()
- row.prop(game, "collision_margin", text="Margin", slider=True)
-
- sub = row.row()
- sub.active = game.physics_type not in {'SOFT_BODY', 'CHARACTER'}
- sub.prop(game, "use_collision_compound", text="Compound")
-
- layout.separator()
- split = layout.split()
- col = split.column()
- col.prop(game, "collision_group")
- col = split.column()
- col.prop(game, "collision_mask")
-
-
-class PHYSICS_PT_game_obstacles(PhysicsButtonsPanel, Panel):
- bl_label = "Create Obstacle"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- game = context.object.game
- rd = context.scene.render
- return (rd.engine in cls.COMPAT_ENGINES) \
- and (game.physics_type in {'SENSOR', 'STATIC', 'DYNAMIC', 'RIGID_BODY', 'SOFT_BODY', 'CHARACTER', 'NO_COLLISION'})
-
- def draw_header(self, context):
- game = context.active_object.game
-
- self.layout.prop(game, "use_obstacle_create", text="")
-
- def draw(self, context):
- layout = self.layout
-
- game = context.active_object.game
-
- layout.active = game.use_obstacle_create
-
- row = layout.row()
- row.prop(game, "obstacle_radius", text="Radius")
- row.label()
-
-
-class RenderButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "render"
-
- @classmethod
- def poll(cls, context):
- rd = context.scene.render
- return (rd.engine in cls.COMPAT_ENGINES)
-
-
-class RENDER_PT_embedded(RenderButtonsPanel, Panel):
- bl_label = "Embedded Player"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.render
-
- row = layout.row()
- row.operator("view3d.game_start", text="Start")
- row = layout.row()
- row.label(text="Resolution:")
- row = layout.row(align=True)
- row.prop(rd, "resolution_x", slider=False, text="X")
- row.prop(rd, "resolution_y", slider=False, text="Y")
-
-
-class RENDER_PT_game_player(RenderButtonsPanel, Panel):
- bl_label = "Standalone Player"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- def draw(self, context):
- import sys
- layout = self.layout
- not_osx = sys.platform != "darwin"
-
- gs = context.scene.game_settings
-
- row = layout.row()
- row.operator("wm.blenderplayer_start", text="Start")
- row = layout.row()
- row.label(text="Resolution:")
- row = layout.row(align=True)
- row.active = not_osx or not gs.show_fullscreen
- row.prop(gs, "resolution_x", slider=False, text="X")
- row.prop(gs, "resolution_y", slider=False, text="Y")
- row = layout.row()
- col = row.column()
- col.prop(gs, "show_fullscreen")
-
- if not_osx:
- col = row.column()
- col.prop(gs, "use_desktop")
- col.active = gs.show_fullscreen
-
- col = layout.column()
- col.label(text="Quality:")
- col.prop(gs, "samples")
- col = layout.column(align=True)
- col.prop(gs, "depth", text="Bit Depth", slider=False)
- col.prop(gs, "frequency", text="Refresh Rate", slider=False)
-
-
-class RENDER_PT_game_stereo(RenderButtonsPanel, Panel):
- bl_label = "Stereo"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
- stereo_mode = gs.stereo
-
- # stereo options:
- layout.row().prop(gs, "stereo", expand=True)
-
- # stereo:
- if stereo_mode == 'STEREO':
- layout.prop(gs, "stereo_mode")
- layout.prop(gs, "stereo_eye_separation")
-
- # dome:
- elif stereo_mode == 'DOME':
- layout.prop(gs, "dome_mode", text="Dome Type")
-
- dome_type = gs.dome_mode
-
- split = layout.split()
-
- if dome_type in {'FISHEYE', 'TRUNCATED_REAR', 'TRUNCATED_FRONT'}:
- col = split.column()
- col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True)
- col.prop(gs, "dome_angle", slider=True)
-
- col = split.column()
- col.prop(gs, "dome_tessellation", text="Tessellation")
- col.prop(gs, "dome_tilt")
-
- elif dome_type == 'PANORAM_SPH':
- col = split.column()
- col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True)
-
- col = split.column()
- col.prop(gs, "dome_tessellation", text="Tessellation")
-
- else: # cube map
- col = split.column()
- col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True)
-
- col = split.column()
-
- layout.prop(gs, "dome_text")
-
-
-class RENDER_PT_game_shading(RenderButtonsPanel, Panel):
- bl_label = "Shading"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.row().prop(gs, "material_mode", expand=True)
-
- if gs.material_mode == 'GLSL':
- split = layout.split()
-
- col = split.column()
- col.prop(gs, "use_glsl_lights", text="Lights")
- col.prop(gs, "use_glsl_shaders", text="Shaders")
- col.prop(gs, "use_glsl_shadows", text="Shadows")
- col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting")
-
- col = split.column()
- col.prop(gs, "use_glsl_ramps", text="Ramps")
- col.prop(gs, "use_glsl_nodes", text="Nodes")
- col.prop(gs, "use_glsl_extra_textures", text="Extra Textures")
-
-
-class RENDER_PT_game_system(RenderButtonsPanel, Panel):
- bl_label = "System"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
- col = layout.column()
- row = col.row()
- col = row.column()
- col.prop(gs, "use_frame_rate")
- col.prop(gs, "use_restrict_animation_updates")
- col.prop(gs, "use_material_caching")
- col = row.column()
- col.prop(gs, "use_display_lists")
- col.active = gs.raster_storage != 'VERTEX_BUFFER_OBJECT'
-
- row = layout.row()
- row.prop(gs, "vsync")
-
- row = layout.row()
- row.prop(gs, "raster_storage")
-
- row = layout.row()
- row.label("Exit Key")
- row.prop(gs, "exit_key", text="", event=True)
-
-
-class RENDER_PT_game_display(RenderButtonsPanel, Panel):
- bl_label = "Display"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.prop(context.scene.render, "fps", text="Animation Frame Rate", slider=False)
-
- flow = layout.column_flow()
- flow.prop(gs, "show_debug_properties", text="Debug Properties")
- flow.prop(gs, "show_framerate_profile", text="Framerate and Profile")
- flow.prop(gs, "show_physics_visualization", text="Physics Visualization")
- flow.prop(gs, "use_deprecation_warnings")
- flow.prop(gs, "show_mouse", text="Mouse Cursor")
-
- col = layout.column()
- col.label(text="Framing:")
- col.row().prop(gs, "frame_type", expand=True)
- if gs.frame_type == 'LETTERBOX':
- col.prop(gs, "frame_color", text="")
-
-
-class SceneButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "scene"
-
-
-class SCENE_PT_game_physics(SceneButtonsPanel, Panel):
- bl_label = "Physics"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.prop(gs, "physics_engine", text="Engine")
- if gs.physics_engine != 'NONE':
- layout.prop(gs, "physics_gravity", text="Gravity")
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Physics Steps:")
- sub = col.column(align=True)
- sub.prop(gs, "physics_step_max", text="Max")
- sub.prop(gs, "physics_step_sub", text="Substeps")
- col.prop(gs, "fps", text="FPS")
-
- col = split.column()
- col.label(text="Logic Steps:")
- col.prop(gs, "logic_step_max", text="Max")
-
- col = layout.column()
- col.label(text="Physics Deactivation:")
- sub = col.row(align=True)
- sub.prop(gs, "deactivation_linear_threshold", text="Linear Threshold")
- sub.prop(gs, "deactivation_angular_threshold", text="Angular Threshold")
- sub = col.row()
- sub.prop(gs, "deactivation_time", text="Time")
-
- col = layout.column()
- col.prop(gs, "use_occlusion_culling", text="Occlusion Culling")
- sub = col.column()
- sub.active = gs.use_occlusion_culling
- sub.prop(gs, "occlusion_culling_resolution", text="Resolution")
-
- else:
- split = layout.split()
-
- col = split.column()
- col.label(text="Physics Steps:")
- col.prop(gs, "fps", text="FPS")
-
- col = split.column()
- col.label(text="Logic Steps:")
- col.prop(gs, "logic_step_max", text="Max")
-
-
-class SCENE_PT_game_physics_obstacles(SceneButtonsPanel, Panel):
- bl_label = "Obstacle Simulation"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.prop(gs, "obstacle_simulation", text="Type")
- if gs.obstacle_simulation != 'NONE':
- layout.prop(gs, "level_height")
- layout.prop(gs, "show_obstacle_simulation")
-
-
-class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel):
- bl_label = "Navigation Mesh"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene and scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.game_settings.recast_data
-
- layout.operator("mesh.navmesh_make", text="Build Navigation Mesh")
-
- col = layout.column()
- col.label(text="Rasterization:")
- row = col.row()
- row.prop(rd, "cell_size")
- row.prop(rd, "cell_height")
-
- col = layout.column()
- col.label(text="Agent:")
- split = col.split()
-
- col = split.column()
- col.prop(rd, "agent_height", text="Height")
- col.prop(rd, "agent_radius", text="Radius")
-
- col = split.column()
- col.prop(rd, "slope_max")
- col.prop(rd, "climb_max")
-
- col = layout.column()
- col.label(text="Region:")
- row = col.row()
- row.prop(rd, "region_min_size")
- if rd.partitioning != 'LAYERS':
- row.prop(rd, "region_merge_size")
-
- col = layout.column()
- col.prop(rd, "partitioning")
-
- col = layout.column()
- col.label(text="Polygonization:")
- split = col.split()
-
- col = split.column()
- col.prop(rd, "edge_max_len")
- col.prop(rd, "edge_max_error")
-
- split.prop(rd, "verts_per_poly")
-
- col = layout.column()
- col.label(text="Detail Mesh:")
- row = col.row()
- row.prop(rd, "sample_dist")
- row.prop(rd, "sample_max_error")
-
-
-class SCENE_PT_game_hysteresis(SceneButtonsPanel, Panel):
- bl_label = "Level of Detail"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene and scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- gs = context.scene.game_settings
-
- row = layout.row()
- row.prop(gs, "use_scene_hysteresis", text="Hysteresis")
- row = layout.row()
- row.active = gs.use_scene_hysteresis
- row.prop(gs, "scene_hysteresis_percentage", text="")
-
-
-class WorldButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "world"
-
-
-class WORLD_PT_game_context_world(WorldButtonsPanel, Panel):
- bl_label = ""
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- rd = context.scene.render
- return (context.scene) and (rd.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- world = context.world
- space = context.space_data
-
- split = layout.split(percentage=0.65)
- if scene:
- split.template_ID(scene, "world", new="world.new")
- elif world:
- split.template_ID(space, "pin_id")
-
-
-class WORLD_PT_game_world(WorldButtonsPanel, Panel):
- bl_label = "World"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- world = context.world
-
- row = layout.row()
- row.column().prop(world, "horizon_color")
- row.column().prop(world, "zenith_color")
- row.column().prop(world, "ambient_color")
-
-
-class WORLD_PT_game_environment_lighting(WorldButtonsPanel, Panel):
- bl_label = "Environment Lighting"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- light = context.world.light_settings
- self.layout.prop(light, "use_environment_light", text="")
-
- def draw(self, context):
- layout = self.layout
-
- light = context.world.light_settings
-
- layout.active = light.use_environment_light
-
- split = layout.split()
- split.prop(light, "environment_energy", text="Energy")
- split.prop(light, "environment_color", text="")
-
-
-class WORLD_PT_game_mist(WorldButtonsPanel, Panel):
- bl_label = "Mist"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- world = context.world
-
- self.layout.prop(world.mist_settings, "use_mist", text="")
-
- def draw(self, context):
- layout = self.layout
-
- world = context.world
-
- layout.active = world.mist_settings.use_mist
-
- layout.prop(world.mist_settings, "falloff")
-
- row = layout.row(align=True)
- row.prop(world.mist_settings, "start")
- row.prop(world.mist_settings, "depth")
-
- layout.prop(world.mist_settings, "intensity", text="Minimum Intensity")
-
-
-class DataButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "data"
-
-
-class DATA_PT_shadow_game(DataButtonsPanel, Panel):
- bl_label = "Shadow"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- COMPAT_LIGHTS = {'SPOT', 'SUN'}
- lamp = context.lamp
- engine = context.scene.render.engine
- return (lamp and lamp.type in COMPAT_LIGHTS) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- lamp = context.lamp
-
- self.layout.prop(lamp, "use_shadow", text="")
-
- def draw(self, context):
- layout = self.layout
-
- lamp = context.lamp
-
- layout.active = lamp.use_shadow
-
- split = layout.split()
-
- col = split.column()
- col.prop(lamp, "shadow_color", text="")
- if lamp.type == 'SUN':
- col.prop(lamp, "show_shadow_box")
-
- col = split.column()
- col.prop(lamp, "use_shadow_layer", text="This Layer Only")
- col.prop(lamp, "use_only_shadow")
-
- col = layout.column()
- col.label("Buffer Type:")
- col.prop(lamp, "ge_shadow_buffer_type", text="", toggle=True)
- col.label("Quality:")
- col = layout.column(align=True)
- col.prop(lamp, "shadow_buffer_size", text="Size")
- col.prop(lamp, "shadow_buffer_bias", text="Bias")
- col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias")
-
- row = layout.row()
- row.label("Clipping:")
- row = layout.row(align=True)
- row.prop(lamp, "shadow_buffer_clip_start", text="Clip Start")
- row.prop(lamp, "shadow_buffer_clip_end", text="Clip End")
-
- if lamp.type == 'SUN':
- row = layout.row()
- row.prop(lamp, "shadow_frustum_size", text="Frustum Size")
-
-
-class ObjectButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "object"
-
-
-class OBJECT_MT_lod_tools(Menu):
- bl_label = "Level Of Detail Tools"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("object.lod_by_name", text="Set By Name")
- layout.operator("object.lod_generate", text="Generate")
- layout.operator("object.lod_clear_all", text="Clear All", icon='PANEL_CLOSE')
-
-
-class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel):
- bl_label = "Levels of Detail"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- return context.scene.render.engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
- layout = self.layout
- ob = context.object
- gs = context.scene.game_settings
-
- col = layout.column()
-
- for i, level in enumerate(ob.lod_levels):
- if i == 0:
- continue
- box = col.box()
- row = box.row()
- row.prop(level, "object", text="")
- row.operator("object.lod_remove", text="", icon='PANEL_CLOSE').index = i
-
- row = box.row()
- row.prop(level, "distance")
- row = row.row(align=True)
- row.prop(level, "use_mesh", text="")
- row.prop(level, "use_material", text="")
-
- row = box.row()
- row.active = gs.use_scene_hysteresis
- row.prop(level, "use_object_hysteresis", text="Hysteresis Override")
- row = box.row()
- row.active = gs.use_scene_hysteresis and level.use_object_hysteresis
- row.prop(level, "object_hysteresis_percentage", text="")
-
- row = col.row(align=True)
- row.operator("object.lod_add", text="Add", icon='ZOOMIN')
- row.menu("OBJECT_MT_lod_tools", text="", icon='TRIA_DOWN')
-
-
-classes = (
- PHYSICS_PT_game_physics,
- PHYSICS_PT_game_collision_bounds,
- PHYSICS_PT_game_obstacles,
- RENDER_PT_embedded,
- RENDER_PT_game_player,
- RENDER_PT_game_stereo,
- RENDER_PT_game_shading,
- RENDER_PT_game_system,
- RENDER_PT_game_display,
- SCENE_PT_game_physics,
- SCENE_PT_game_physics_obstacles,
- SCENE_PT_game_navmesh,
- SCENE_PT_game_hysteresis,
- WORLD_PT_game_context_world,
- WORLD_PT_game_world,
- WORLD_PT_game_environment_lighting,
- WORLD_PT_game_mist,
- DATA_PT_shadow_game,
- OBJECT_MT_lod_tools,
- OBJECT_PT_levels_of_detail,
-)
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 72d8a53dd69..a2ccfb4f1b8 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -97,6 +97,11 @@ class GreasePencilDrawingToolsPanel:
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
+ @classmethod
+ def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
@staticmethod
def draw(self, context):
layout = self.layout
@@ -171,6 +176,9 @@ class GreasePencilStrokeEditPanel:
@classmethod
def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
if context.gpencil_data is None:
return False
@@ -259,6 +267,9 @@ class GreasePencilInterpolatePanel:
@classmethod
def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
if context.gpencil_data is None:
return False
elif context.space_data.type != 'VIEW_3D':
@@ -307,6 +318,11 @@ class GreasePencilBrushPanel:
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
+ @classmethod
+ def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
@staticmethod
def draw(self, context):
layout = self.layout
@@ -376,6 +392,9 @@ class GreasePencilStrokeSculptPanel:
@classmethod
def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
if context.gpencil_data is None:
return False
@@ -436,6 +455,9 @@ class GreasePencilBrushCurvesPanel:
@classmethod
def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
if context.active_gpencil_brush is None:
return False
@@ -1026,6 +1048,9 @@ class GreasePencilPaletteColorPanel:
@classmethod
def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
if context.gpencil_data is None:
return False
@@ -1128,6 +1153,9 @@ class GreasePencilToolsPanel:
@classmethod
def poll(cls, context):
+ # XXX - disabled in 2.8 branch.
+ return False
+
return (context.gpencil_data is not None)
@staticmethod
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index 450ca80bbc2..c766c8dedbc 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -378,6 +378,12 @@ class MASK_MT_select(Menu):
def draw(self, context):
layout = self.layout
+ layout.operator("mask.select_all", text="All").action = 'SELECT'
+ layout.operator("mask.select_all", text="None").action = 'DESELECT'
+ layout.operator("mask.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("mask.select_border")
layout.operator("mask.select_circle")
@@ -388,8 +394,6 @@ class MASK_MT_select(Menu):
layout.separator()
- layout.operator("mask.select_all").action = 'TOGGLE'
- layout.operator("mask.select_all", text="Inverse").action = 'INVERT'
layout.operator("mask.select_linked", text="Select Linked")
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 73740df37e8..3761cbba372 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -21,42 +21,7 @@ import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
from bpy.app.translations import pgettext_iface as iface_
-
-
-def active_node_mat(mat):
- # TODO, 2.4x has a pipeline section, for 2.5 we need to communicate
- # which settings from node-materials are used
- if mat is not None:
- mat_node = mat.active_node_material
- if mat_node:
- return mat_node
- else:
- return mat
-
- return None
-
-
-def check_material(mat):
- if mat is not None:
- if mat.use_nodes:
- if mat.active_node_material is not None:
- return True
- return False
- return True
- return False
-
-
-def simple_material(mat):
- if (mat is not None) and (not mat.use_nodes):
- return True
- return False
-
-
-class MATERIAL_MT_sss_presets(Menu):
- bl_label = "SSS Presets"
- preset_subdir = "sss"
- preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+from bpy_extras.node_utils import find_node_input
class MATERIAL_MT_specials(Menu):
@@ -82,12 +47,6 @@ class MATERIAL_UL_matslots(UIList):
layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
else:
layout.label(text="", icon_value=icon)
- if ma and not context.scene.render.use_shading_nodes:
- manode = ma.active_node_material
- if manode:
- layout.label(text=iface_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode))
- elif ma.use_nodes:
- layout.label(text="Node <none>")
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -101,20 +60,32 @@ class MaterialButtonsPanel:
@classmethod
def poll(cls, context):
- return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES)
+ return context.material and (context.engine in cls.COMPAT_ENGINES)
+
+
+class MATERIAL_PT_preview(MaterialButtonsPanel, Panel):
+ bl_label = "Preview"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ self.layout.template_preview(context.material)
+
+
+class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel):
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+ _context_path = "material"
+ _property_type = bpy.types.Material
-class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
+class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
bl_label = ""
+ bl_context = "material"
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- # An exception, don't call the parent poll func because
- # this manages materials for all engine types
-
- engine = context.scene.render.engine
+ engine = context.engine
return (context.material or context.object) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
@@ -126,10 +97,9 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
space = context.space_data
if ob:
- is_sortable = (len(ob.material_slots) > 1)
-
- rows = 1
- if is_sortable:
+ is_sortable = len(ob.material_slots) > 1
+ rows = 2
+ if (is_sortable):
rows = 4
row = layout.row()
@@ -159,8 +129,6 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
if ob:
split.template_ID(ob, "active_material", new="material.new")
row = split.row()
- if mat:
- row.prop(mat, "use_nodes", icon='NODETREE', text="")
if slot:
row.prop(slot, "link", text="")
@@ -170,921 +138,118 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
split.template_ID(space, "pin_id")
split.separator()
- if mat:
- layout.row().prop(mat, "type", expand=True)
- if mat.use_nodes:
- row = layout.row()
- row.label(text="", icon='NODETREE')
- if mat.active_node_material:
- row.prop(mat.active_node_material, "name", text="")
- else:
- row.label(text="No material node selected")
-
-
-class MATERIAL_PT_preview(MaterialButtonsPanel, Panel):
- bl_label = "Preview"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- self.layout.template_preview(context.material)
-
-
-class MATERIAL_PT_pipeline(MaterialButtonsPanel, Panel):
- bl_label = "Render Pipeline Options"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and (not simple_material(mat)) and (mat.type in {'SURFACE', 'WIRE', 'VOLUME'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self. layout
-
- mat = context.material
- mat_type = mat.type in {'SURFACE', 'WIRE'}
-
- row = layout.row()
- row.active = mat_type
- row.prop(mat, "use_transparency")
- sub = row.column()
- sub.prop(mat, "offset_z")
-
- sub.active = mat_type and mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY'
-
- row = layout.row()
- row.active = mat.use_transparency or not mat_type
- row.prop(mat, "transparency_method", expand=True)
-
- layout.separator()
-
- split = layout.split()
- col = split.column()
-
- col.prop(mat, "use_raytrace")
- col.prop(mat, "use_full_oversampling")
- sub = col.column()
- sub.active = mat_type
- sub.prop(mat, "use_sky")
- sub.prop(mat, "invert_z")
- col.prop(mat, "pass_index")
-
- col = split.column()
- col.active = mat_type
-
- col.prop(mat, "use_cast_shadows", text="Cast")
- col.prop(mat, "use_cast_shadows_only", text="Cast Only")
- col.prop(mat, "use_cast_buffer_shadows")
- sub = col.column()
- sub.active = mat.use_cast_buffer_shadows
- sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
- col.prop(mat, "use_cast_approximate")
-
-
-class MATERIAL_PT_diffuse(MaterialButtonsPanel, Panel):
- bl_label = "Diffuse"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
-
- split = layout.split()
-
- col = split.column()
- col.prop(mat, "diffuse_color", text="")
- sub = col.column()
- sub.active = (not mat.use_shadeless)
- sub.prop(mat, "diffuse_intensity", text="Intensity")
-
- col = split.column()
- col.active = (not mat.use_shadeless)
- col.prop(mat, "diffuse_shader", text="")
- col.prop(mat, "use_diffuse_ramp", text="Ramp")
-
- col = layout.column()
- col.active = (not mat.use_shadeless)
- if mat.diffuse_shader == 'OREN_NAYAR':
- col.prop(mat, "roughness")
- elif mat.diffuse_shader == 'MINNAERT':
- col.prop(mat, "darkness")
- elif mat.diffuse_shader == 'TOON':
- row = col.row()
- row.prop(mat, "diffuse_toon_size", text="Size")
- row.prop(mat, "diffuse_toon_smooth", text="Smooth")
- elif mat.diffuse_shader == 'FRESNEL':
- row = col.row()
- row.prop(mat, "diffuse_fresnel", text="Fresnel")
- row.prop(mat, "diffuse_fresnel_factor", text="Factor")
-
- if mat.use_diffuse_ramp:
- col = layout.column()
- col.active = (not mat.use_shadeless)
- col.separator()
- col.template_color_ramp(mat, "diffuse_ramp", expand=True)
- col.separator()
-
- row = col.row()
- row.prop(mat, "diffuse_ramp_input", text="Input")
- row.prop(mat, "diffuse_ramp_blend", text="Blend")
-
- col.prop(mat, "diffuse_ramp_factor", text="Factor")
-
-
-class MATERIAL_PT_specular(MaterialButtonsPanel, Panel):
- bl_label = "Specular"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
-
- layout.active = (not mat.use_shadeless)
-
- split = layout.split()
-
- col = split.column()
- col.prop(mat, "specular_color", text="")
- col.prop(mat, "specular_intensity", text="Intensity")
-
- col = split.column()
- col.prop(mat, "specular_shader", text="")
- col.prop(mat, "use_specular_ramp", text="Ramp")
-
- col = layout.column()
- if mat.specular_shader in {'COOKTORR', 'PHONG'}:
- col.prop(mat, "specular_hardness", text="Hardness")
- elif mat.specular_shader == 'BLINN':
- row = col.row()
- row.prop(mat, "specular_hardness", text="Hardness")
- row.prop(mat, "specular_ior", text="IOR")
- elif mat.specular_shader == 'WARDISO':
- col.prop(mat, "specular_slope", text="Slope")
- elif mat.specular_shader == 'TOON':
- row = col.row()
- row.prop(mat, "specular_toon_size", text="Size")
- row.prop(mat, "specular_toon_smooth", text="Smooth")
-
- if mat.use_specular_ramp:
- layout.separator()
- layout.template_color_ramp(mat, "specular_ramp", expand=True)
- layout.separator()
-
- row = layout.row()
- row.prop(mat, "specular_ramp_input", text="Input")
- row.prop(mat, "specular_ramp_blend", text="Blend")
-
- layout.prop(mat, "specular_ramp_factor", text="Factor")
-
-
-class MATERIAL_PT_shading(MaterialButtonsPanel, Panel):
- bl_label = "Shading"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
-
- if mat.type in {'SURFACE', 'WIRE'}:
- split = layout.split()
-
- col = split.column()
- sub = col.column()
- sub.active = not mat.use_shadeless
- sub.prop(mat, "emit")
- sub.prop(mat, "ambient")
- sub = col.column()
- sub.prop(mat, "translucency")
-
- col = split.column()
- col.prop(mat, "use_shadeless")
- sub = col.column()
- sub.active = not mat.use_shadeless
- sub.prop(mat, "use_tangent_shading")
- sub.prop(mat, "use_cubic")
-
-
-class MATERIAL_PT_transp(MaterialButtonsPanel, Panel):
- bl_label = "Transparency"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- mat = context.material
-
- if simple_material(mat):
- self.layout.prop(mat, "use_transparency", text="")
-
- def draw(self, context):
- layout = self.layout
-
- base_mat = context.material
- mat = active_node_mat(context.material)
- rayt = mat.raytrace_transparency
-
- if simple_material(base_mat):
- row = layout.row()
- row.active = mat.use_transparency
- row.prop(mat, "transparency_method", expand=True)
-
- split = layout.split()
- split.active = base_mat.use_transparency
-
- col = split.column()
- col.prop(mat, "alpha")
- row = col.row()
- row.active = (base_mat.transparency_method != 'MASK') and (not mat.use_shadeless)
- row.prop(mat, "specular_alpha", text="Specular")
-
- col = split.column()
- col.active = (not mat.use_shadeless)
- col.prop(rayt, "fresnel")
- sub = col.column()
- sub.active = (rayt.fresnel > 0.0)
- sub.prop(rayt, "fresnel_factor", text="Blend")
-
- if base_mat.transparency_method == 'RAYTRACE':
- layout.separator()
- split = layout.split()
- split.active = base_mat.use_transparency
-
- col = split.column()
- col.prop(rayt, "ior")
- col.prop(rayt, "filter")
- col.prop(rayt, "falloff")
- col.prop(rayt, "depth_max")
- col.prop(rayt, "depth")
-
- col = split.column()
- col.label(text="Gloss:")
- col.prop(rayt, "gloss_factor", text="Amount")
- sub = col.column()
- sub.active = rayt.gloss_factor < 1.0
- sub.prop(rayt, "gloss_threshold", text="Threshold")
- sub.prop(rayt, "gloss_samples", text="Samples")
-
-
-class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel):
- bl_label = "Mirror"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- raym = active_node_mat(context.material).raytrace_mirror
-
- self.layout.prop(raym, "use", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
- raym = mat.raytrace_mirror
-
- layout.active = raym.use
-
- split = layout.split()
-
- col = split.column()
- col.prop(raym, "reflect_factor")
- col.prop(mat, "mirror_color", text="")
-
- col = split.column()
- col.prop(raym, "fresnel")
- sub = col.column()
- sub.active = (raym.fresnel > 0.0)
- sub.prop(raym, "fresnel_factor", text="Blend")
-
- split = layout.split()
-
- col = split.column()
- col.separator()
- col.prop(raym, "depth")
- col.prop(raym, "distance", text="Max Dist")
- col.separator()
- sub = col.split(percentage=0.4)
- sub.active = (raym.distance > 0.0)
- sub.label(text="Fade To:")
- sub.prop(raym, "fade_to", text="")
-
- col = split.column()
- col.label(text="Gloss:")
- col.prop(raym, "gloss_factor", text="Amount")
- sub = col.column()
- sub.active = (raym.gloss_factor < 1.0)
- sub.prop(raym, "gloss_threshold", text="Threshold")
- sub.prop(raym, "gloss_samples", text="Samples")
- sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
-
-
-class MATERIAL_PT_sss(MaterialButtonsPanel, Panel):
- bl_label = "Subsurface Scattering"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- mat = active_node_mat(context.material)
- sss = mat.subsurface_scattering
-
- self.layout.active = (not mat.use_shadeless)
- self.layout.prop(sss, "use", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = active_node_mat(context.material)
- sss = mat.subsurface_scattering
-
- layout.active = (sss.use) and (not mat.use_shadeless)
-
- row = layout.row().split()
- sub = row.row(align=True).split(align=True, percentage=0.75)
- sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label)
- sub.operator("material.sss_preset_add", text="", icon='ZOOMIN')
- sub.operator("material.sss_preset_add", text="", icon='ZOOMOUT').remove_active = True
-
- split = layout.split()
-
- col = split.column()
- col.prop(sss, "ior")
- col.prop(sss, "scale")
- col.prop(sss, "color", text="")
- col.prop(sss, "radius", text="RGB Radius", expand=True)
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Blend:")
- sub.prop(sss, "color_factor", text="Color")
- sub.prop(sss, "texture_factor", text="Texture")
- sub.label(text="Scattering Weight:")
- sub.prop(sss, "front")
- sub.prop(sss, "back")
- col.separator()
- col.prop(sss, "error_threshold", text="Error")
-
-class MATERIAL_PT_halo(MaterialButtonsPanel, Panel):
- bl_label = "Halo"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
- halo = mat.halo
-
- def number_but(layout, toggle, number, name, color):
- row = layout.row(align=True)
- row.prop(halo, toggle, text="")
- sub = row.column(align=True)
- sub.active = getattr(halo, toggle)
- sub.prop(halo, number, text=name, translate=False)
- if not color == "":
- sub.prop(mat, color, text="")
-
- split = layout.split()
-
- col = split.column()
- col.prop(mat, "alpha")
- col.prop(mat, "diffuse_color", text="")
- col.prop(halo, "seed")
-
- col = split.column()
- col.prop(halo, "size")
- col.prop(halo, "hardness")
- col.prop(halo, "add")
-
- layout.label(text="Options:")
-
- split = layout.split()
- col = split.column()
- col.prop(halo, "use_texture")
- col.prop(halo, "use_vertex_normal")
- col.prop(halo, "use_extreme_alpha")
- col.prop(halo, "use_shaded")
- col.prop(halo, "use_soft")
-
- col = split.column()
- number_but(col, "use_ring", "ring_count", iface_("Rings"), "mirror_color")
- number_but(col, "use_lines", "line_count", iface_("Lines"), "specular_color")
- number_but(col, "use_star", "star_tip_count", iface_("Star Tips"), "")
-
-
-class MATERIAL_PT_flare(MaterialButtonsPanel, Panel):
- bl_label = "Flare"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- halo = context.material.halo
-
- self.layout.prop(halo, "use_flare_mode", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
- halo = mat.halo
-
- layout.active = halo.use_flare_mode
-
- split = layout.split()
-
- col = split.column()
- col.prop(halo, "flare_size", text="Size")
- col.prop(halo, "flare_boost", text="Boost")
- col.prop(halo, "flare_seed", text="Seed")
-
- col = split.column()
- col.prop(halo, "flare_subflare_count", text="Subflares")
- col.prop(halo, "flare_subflare_size", text="Subsize")
-
-
-class MATERIAL_PT_game_settings(MaterialButtonsPanel, Panel):
- bl_label = "Game Settings"
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
- game = context.material.game_settings # don't use node material
-
- row = layout.row()
- row.prop(game, "use_backface_culling")
- row.prop(game, "invisible")
- row.prop(game, "text")
-
- row = layout.row()
- row.label(text="Alpha Blend:")
- row.label(text="Face Orientation:")
- row = layout.row()
- row.prop(game, "alpha_blend", text="")
- row.prop(game, "face_orientation", text="")
+def panel_node_draw(layout, ntree, output_type):
+ node = ntree.get_output_node('EEVEE')
+ if node:
+ input = find_node_input(node, 'Surface')
+ if input:
+ layout.template_node_view(ntree, node, input)
+ else:
+ layout.label(text="Incompatible output node")
+ else:
+ layout.label(text="No output node")
-class MATERIAL_PT_physics(MaterialButtonsPanel, Panel):
- bl_label = "Physics"
- COMPAT_ENGINES = {'BLENDER_GAME'}
- def draw_header(self, context):
- game = context.material.game_settings
- self.layout.prop(game, "physics", text="")
+class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
+ bl_label = "Surface"
+ bl_context = "material"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES)
+ engine = context.engine
+ return context.material and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
- layout.active = context.material.game_settings.physics
-
- phys = context.material.physics # don't use node material
-
- split = layout.split()
- row = split.row()
- row.prop(phys, "friction")
- row.prop(phys, "elasticity", slider=True)
- row = layout.row()
- row.label(text="Force Field:")
-
- row = layout.row()
- row.prop(phys, "fh_force")
- row.prop(phys, "fh_damping", slider=True)
-
- row = layout.row()
- row.prop(phys, "fh_distance")
- row.prop(phys, "use_fh_normal")
-
-
-class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
- bl_label = "Strand"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
mat = context.material
- engine = context.scene.render.engine
- return mat and (mat.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
- tan = mat.strand
- split = layout.split()
-
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Size:")
- sub.prop(tan, "root_size", text="Root")
- sub.prop(tan, "tip_size", text="Tip")
- sub.prop(tan, "size_min", text="Minimum")
- sub.prop(tan, "use_blender_units")
- sub = col.column()
- sub.active = (not mat.use_shadeless)
- sub.prop(tan, "use_tangent_shading")
- col.prop(tan, "shape")
+ layout.prop(mat, "use_nodes", icon='NODETREE')
+ layout.separator()
- col = split.column()
- col.label(text="Shading:")
- col.prop(tan, "width_fade")
- ob = context.object
- if ob and ob.type == 'MESH':
- col.prop_search(tan, "uv_layer", ob.data, "uv_textures", text="")
+ if mat.use_nodes:
+ panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL')
else:
- col.prop(tan, "uv_layer", text="")
- col.separator()
- sub = col.column()
- sub.active = (not mat.use_shadeless)
- sub.label("Surface diffuse:")
- sub = col.column()
- sub.prop(tan, "blend_distance", text="Distance")
+ layout.use_property_split = True
+ layout.prop(mat, "diffuse_color", text="Base Color")
+ layout.prop(mat, "metallic")
+ layout.prop(mat, "specular_intensity", text="Specular")
+ layout.prop(mat, "roughness")
-class MATERIAL_PT_options(MaterialButtonsPanel, Panel):
+class EEVEE_MATERIAL_PT_options(MaterialButtonsPanel, Panel):
bl_label = "Options"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ bl_context = "material"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
+ engine = context.engine
+ return context.material and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
- base_mat = context.material
- mat = active_node_mat(base_mat)
-
- split = layout.split()
-
- col = split.column()
- if simple_material(base_mat):
- col.prop(mat, "use_raytrace")
- col.prop(mat, "use_full_oversampling")
- col.prop(mat, "use_sky")
- col.prop(mat, "use_mist")
- if simple_material(base_mat):
- col.prop(mat, "invert_z")
- sub = col.row()
- sub.prop(mat, "offset_z")
- sub.active = mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY'
- sub = col.column(align=True)
- sub.label(text="Light Group:")
- sub.prop(mat, "light_group", text="")
- row = sub.row(align=True)
- row.active = bool(mat.light_group)
- row.prop(mat, "use_light_group_exclusive", text="Exclusive")
- row.prop(mat, "use_light_group_local", text="Local")
-
- col = split.column()
- col.prop(mat, "use_face_texture")
- sub = col.column()
- sub.active = mat.use_face_texture
- sub.prop(mat, "use_face_texture_alpha")
- col.separator()
- col.prop(mat, "use_vertex_color_paint")
- col.prop(mat, "use_vertex_color_light")
- col.prop(mat, "use_object_color")
- col.prop(mat, "use_uv_project")
- if simple_material(base_mat):
- col.prop(mat, "pass_index")
-
-
-class MATERIAL_PT_shadow(MaterialButtonsPanel, Panel):
- bl_label = "Shadow"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- base_mat = context.material
- mat = active_node_mat(base_mat)
-
- split = layout.split()
-
- col = split.column()
- col.prop(mat, "use_shadows", text="Receive")
- col.prop(mat, "use_transparent_shadows", text="Receive Transparent")
- col.prop(mat, "use_only_shadow", text="Shadows Only")
- sub = col.column()
- sub.active = mat.use_only_shadow
- sub.prop(mat, "shadow_only_type", text="")
- if not simple_material(base_mat):
- col = split.column()
+ layout.prop(mat, "blend_method")
- col.prop(mat, "use_ray_shadow_bias", text="Auto Ray Bias")
- sub = col.column()
- sub.active = (not mat.use_ray_shadow_bias)
- sub.prop(mat, "shadow_ray_bias", text="Ray Bias")
+ if mat.blend_method != 'OPAQUE':
+ layout.prop(mat, "transparent_shadow_method")
- if simple_material(base_mat):
- col = split.column()
-
- col.prop(mat, "use_cast_shadows", text="Cast")
- col.prop(mat, "use_cast_shadows_only", text="Cast Only")
- col.prop(mat, "use_cast_buffer_shadows")
- sub = col.column()
- sub.active = mat.use_cast_buffer_shadows
- if simple_material(base_mat):
- sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha")
- sub.prop(mat, "shadow_buffer_bias", text="Buffer Bias")
- if simple_material(base_mat):
- col.prop(mat, "use_cast_approximate")
-
-
-class MATERIAL_PT_transp_game(MaterialButtonsPanel, Panel):
- bl_label = "Transparency"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- mat = context.material
-
- if simple_material(mat):
- self.layout.prop(mat, "use_transparency", text="")
-
- def draw(self, context):
- layout = self.layout
- base_mat = context.material
- mat = active_node_mat(base_mat)
-
- layout.active = mat.use_transparency
-
- if simple_material(base_mat):
row = layout.row()
- row.prop(mat, "transparency_method", expand=True)
-
- layout.prop(mat, "alpha")
- layout.prop(mat, "specular_alpha", text="Specular")
-
-
-class VolumeButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "material"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES)
+ row.active = ((mat.blend_method == 'CLIP') or (mat.transparent_shadow_method == 'CLIP'))
+ row.prop(mat, "alpha_threshold")
+ if mat.blend_method not in {'OPAQUE', 'CLIP', 'HASHED'}:
+ layout.prop(mat, "show_transparent_backside")
-class MATERIAL_PT_volume_density(VolumeButtonsPanel, Panel):
- bl_label = "Density"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- vol = context.material.volume # don't use node material
+ layout.prop(mat, "use_screen_refraction")
+ layout.prop(mat, "refraction_depth")
+ layout.prop(mat, "use_screen_subsurface")
row = layout.row()
- row.prop(vol, "density")
- row.prop(vol, "density_scale")
+ row.active = mat.use_screen_subsurface
+ row.prop(mat, "use_sss_translucency")
-class MATERIAL_PT_volume_shading(VolumeButtonsPanel, Panel):
- bl_label = "Shading"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- vol = context.material.volume # don't use node material
-
- split = layout.split()
-
- col = split.column()
- col.prop(vol, "scattering")
- col.prop(vol, "asymmetry")
- col.prop(vol, "transmission_color")
-
- col = split.column()
- sub = col.column(align=True)
- sub.prop(vol, "emission")
- sub.prop(vol, "emission_color", text="")
- sub = col.column(align=True)
- sub.prop(vol, "reflection")
- sub.prop(vol, "reflection_color", text="")
-
-
-class MATERIAL_PT_volume_lighting(VolumeButtonsPanel, Panel):
- bl_label = "Lighting"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- vol = context.material.volume # don't use node material
-
- split = layout.split()
-
- col = split.column()
- col.prop(vol, "light_method", text="")
-
- col = split.column()
-
- if vol.light_method == 'SHADED':
- col.prop(vol, "use_external_shadows")
- col.prop(vol, "use_light_cache")
- sub = col.column()
- sub.active = vol.use_light_cache
- sub.prop(vol, "cache_resolution")
- elif vol.light_method in {'MULTIPLE_SCATTERING', 'SHADED_PLUS_MULTIPLE_SCATTERING'}:
- sub = col.column()
- sub.enabled = True
- sub.active = False
- sub.label("Light Cache Enabled")
- col.prop(vol, "cache_resolution")
-
- sub = col.column(align=True)
- sub.prop(vol, "ms_diffusion")
- sub.prop(vol, "ms_spread")
- sub.prop(vol, "ms_intensity")
-
-
-class MATERIAL_PT_volume_transp(VolumeButtonsPanel, Panel):
- bl_label = "Transparency"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+class MATERIAL_PT_viewport(MaterialButtonsPanel, Panel):
+ bl_label = "Viewport Display"
+ bl_context = "material"
+ bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
- mat = context.material
- engine = context.scene.render.engine
- return mat and simple_material(mat) and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES)
+ return context.material
def draw(self, context):
- layout = self.layout
-
- mat = context.material # don't use node material
-
- layout.row().prop(mat, "transparency_method", expand=True)
-
-
-class MATERIAL_PT_volume_integration(VolumeButtonsPanel, Panel):
- bl_label = "Integration"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- vol = context.material.volume # don't use node material
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Step Calculation:")
- col.prop(vol, "step_method", text="")
- col = col.column(align=True)
- col.prop(vol, "step_size")
-
- col = split.column()
- col.label()
- col.prop(vol, "depth_threshold")
-
-
-class MATERIAL_PT_volume_options(VolumeButtonsPanel, Panel):
- bl_label = "Options"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
mat = context.material
- engine = context.scene.render.engine
- return check_material(mat) and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES)
- def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
- mat = active_node_mat(context.material)
-
- split = layout.split()
-
- col = split.column()
- if simple_material(context.material):
- col.prop(mat, "use_raytrace")
- col.prop(mat, "use_full_oversampling")
- col.prop(mat, "use_mist")
-
- col = split.column()
- col.label(text="Light Group:")
- col.prop(mat, "light_group", text="")
- row = col.row()
- row.active = bool(mat.light_group)
- row.prop(mat, "use_light_group_exclusive", text="Exclusive")
-
-
-class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- _context_path = "material"
- _property_type = bpy.types.Material
+ col = layout.column()
+ col.prop(mat, "diffuse_color")
+ col.prop(mat, "specular_color")
+ col.prop(mat, "roughness")
classes = (
- MATERIAL_MT_sss_presets,
MATERIAL_MT_specials,
MATERIAL_UL_matslots,
- MATERIAL_PT_context_material,
MATERIAL_PT_preview,
- MATERIAL_PT_pipeline,
- MATERIAL_PT_diffuse,
- MATERIAL_PT_specular,
- MATERIAL_PT_shading,
- MATERIAL_PT_transp,
- MATERIAL_PT_mirror,
- MATERIAL_PT_sss,
- MATERIAL_PT_halo,
- MATERIAL_PT_flare,
- MATERIAL_PT_game_settings,
- MATERIAL_PT_physics,
- MATERIAL_PT_strand,
- MATERIAL_PT_options,
- MATERIAL_PT_shadow,
- MATERIAL_PT_transp_game,
- MATERIAL_PT_volume_density,
- MATERIAL_PT_volume_shading,
- MATERIAL_PT_volume_lighting,
- MATERIAL_PT_volume_transp,
- MATERIAL_PT_volume_integration,
- MATERIAL_PT_volume_options,
MATERIAL_PT_custom_props,
+ EEVEE_MATERIAL_PT_context_material,
+ EEVEE_MATERIAL_PT_surface,
+ EEVEE_MATERIAL_PT_options,
+ MATERIAL_PT_viewport,
)
+
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index 50cef9124ab..63b708ae059 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -40,7 +40,7 @@ class OBJECT_PT_context_object(ObjectButtonsPanel, Panel):
layout.template_ID(space, "pin_id")
else:
row = layout.row()
- row.template_ID(context.scene.objects, "active", filter='AVAILABLE')
+ row.template_ID(context.view_layer.objects, "active", filter='AVAILABLE')
class OBJECT_PT_transform(ObjectButtonsPanel, Panel):
@@ -48,150 +48,140 @@ class OBJECT_PT_transform(ObjectButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
ob = context.object
- row = layout.row()
+ col = flow.column()
+ row = col.row(align=True)
+ row.prop(ob, "location")
+ row.use_property_decorate = False
+ row.prop(ob, "lock_location", text="", emboss=False)
- row.column().prop(ob, "location")
if ob.rotation_mode == 'QUATERNION':
- row.column().prop(ob, "rotation_quaternion", text="Rotation")
+ col = flow.column()
+ row = col.row(align=True)
+ row.prop(ob, "rotation_quaternion", text="Rotation")
+ sub = row.column(align=True)
+ sub.use_property_decorate = False
+ sub.prop(ob, "lock_rotation_w", text="", emboss=False)
+ sub.prop(ob, "lock_rotation", text="", emboss=False)
elif ob.rotation_mode == 'AXIS_ANGLE':
# row.column().label(text="Rotation")
#row.column().prop(pchan, "rotation_angle", text="Angle")
#row.column().prop(pchan, "rotation_axis", text="Axis")
- row.column().prop(ob, "rotation_axis_angle", text="Rotation")
+ col = flow.column()
+ row = col.row(align=True)
+ row.prop(ob, "rotation_axis_angle", text="Rotation")
+
+ sub = row.column(align=True)
+ sub.use_property_decorate = False
+ sub.prop(ob, "lock_rotation_w", text="", emboss=False)
+ sub.prop(ob, "lock_rotation", text="", emboss=False)
else:
- row.column().prop(ob, "rotation_euler", text="Rotation")
+ col = flow.column()
+ row = col.row(align=True)
+ row.prop(ob, "rotation_euler", text="Rotation")
+ row.use_property_decorate = False
+ row.prop(ob, "lock_rotation", text="", emboss=False)
+
+ col = flow.column()
+ row = col.row(align=True)
+ row.prop(ob, "scale")
+ row.use_property_decorate = False
+ row.prop(ob, "lock_scale", text="", emboss=False)
- row.column().prop(ob, "scale")
-
- layout.prop(ob, "rotation_mode")
+ row = layout.row(align=True)
+ row.prop(ob, "rotation_mode")
+ row.label(text="", icon='BLANK1')
class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel):
bl_label = "Delta Transform"
+ bl_parent_id = "OBJECT_PT_transform"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=True, align=False)
ob = context.object
- row = layout.row()
+ col = flow.column()
+ col.prop(ob, "delta_location")
- row.column().prop(ob, "delta_location")
+ col = flow.column()
if ob.rotation_mode == 'QUATERNION':
- row.column().prop(ob, "delta_rotation_quaternion", text="Rotation")
+ col.prop(ob, "delta_rotation_quaternion", text="Rotation")
elif ob.rotation_mode == 'AXIS_ANGLE':
# row.column().label(text="Rotation")
#row.column().prop(pchan, "delta_rotation_angle", text="Angle")
#row.column().prop(pchan, "delta_rotation_axis", text="Axis")
#row.column().prop(ob, "delta_rotation_axis_angle", text="Rotation")
- row.column().label(text="Not for Axis-Angle")
+ col.label(text="Not for Axis-Angle")
else:
- row.column().prop(ob, "delta_rotation_euler", text="Delta Rotation")
-
- row.column().prop(ob, "delta_scale")
-
-
-class OBJECT_PT_transform_locks(ObjectButtonsPanel, Panel):
- bl_label = "Transform Locks"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.object
+ col.prop(ob, "delta_rotation_euler", text="Delta Rotation")
- split = layout.split(percentage=0.1)
-
- col = split.column(align=True)
- col.label(text="")
- col.label(text="X:")
- col.label(text="Y:")
- col.label(text="Z:")
-
- split.column().prop(ob, "lock_location", text="Location")
- split.column().prop(ob, "lock_rotation", text="Rotation")
- split.column().prop(ob, "lock_scale", text="Scale")
-
- if ob.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
- row = layout.row()
- row.prop(ob, "lock_rotations_4d", text="Lock Rotation")
-
- sub = row.row()
- sub.active = ob.lock_rotations_4d
- sub.prop(ob, "lock_rotation_w", text="W")
+ col = flow.column()
+ col.prop(ob, "delta_scale")
class OBJECT_PT_relations(ObjectButtonsPanel, Panel):
bl_label = "Relations"
+ bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
ob = context.object
- split = layout.split()
-
- col = split.column()
- col.prop(ob, "layers")
- col.separator()
- col.prop(ob, "pass_index")
-
- col = split.column()
- col.label(text="Parent:")
- col.prop(ob, "parent", text="")
-
- sub = col.column()
- sub.prop(ob, "parent_type", text="")
+ col = flow.column()
+ col.prop(ob, "parent")
+ sub = col.row(align=True)
+ sub.prop(ob, "parent_type")
parent = ob.parent
if parent and ob.parent_type == 'BONE' and parent.type == 'ARMATURE':
- sub.prop_search(ob, "parent_bone", parent.data, "bones", text="")
+ sub.prop_search(ob, "parent_bone", parent.data, "bones")
sub.active = (parent is not None)
+ col = flow.column()
+ col.active = (ob.parent is not None)
+ col.prop(ob, "use_slow_parent")
+ sub = col.row(align=True)
+ sub.active = (ob.use_slow_parent)
+ sub.prop(ob, "slow_parent_offset", text="Offset")
-class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel):
- bl_label = "Relations Extras"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.object
-
- split = layout.split()
+ col = flow.column()
+ col.separator()
- if context.scene.render.engine != 'BLENDER_GAME':
- col = split.column()
- col.label(text="Tracking Axes:")
- col.prop(ob, "track_axis", text="Axis")
- col.prop(ob, "up_axis", text="Up Axis")
+ col.prop(ob, "track_axis", text="Tracking Axis")
+ col.prop(ob, "up_axis", text="Up Axis")
- col = split.column()
- col.prop(ob, "use_slow_parent")
- row = col.row()
- row.active = ((ob.parent is not None) and (ob.use_slow_parent))
- row.prop(ob, "slow_parent_offset", text="Offset")
+ col = flow.column()
+ col.separator()
- layout.prop(ob, "use_extra_recalc_object")
- layout.prop(ob, "use_extra_recalc_data")
+ col.prop(ob, "pass_index")
-class GROUP_MT_specials(Menu):
- bl_label = "Group Specials"
+class COLLECTION_MT_specials(Menu):
+ bl_label = "Collection Specials"
def draw(self, context):
layout = self.layout
- layout.operator("object.group_unlink", icon='X')
- layout.operator("object.grouped_select")
+ layout.operator("object.collection_unlink", icon='X')
+ layout.operator("object.collection_objects_select")
layout.operator("object.dupli_offset_from_cursor")
-class OBJECT_PT_groups(ObjectButtonsPanel, Panel):
- bl_label = "Groups"
+class OBJECT_PT_collections(ObjectButtonsPanel, Panel):
+ bl_label = "Collections"
+ bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
@@ -199,42 +189,40 @@ class OBJECT_PT_groups(ObjectButtonsPanel, Panel):
obj = context.object
row = layout.row(align=True)
- if bpy.data.groups:
- row.operator("object.group_link", text="Add to Group")
+ if bpy.data.collections:
+ row.operator("object.collection_link", text="Add to Collection")
else:
- row.operator("object.group_add", text="Add to Group")
- row.operator("object.group_add", text="", icon='ZOOMIN')
+ row.operator("object.collection_add", text="Add to Collection")
+ row.operator("object.collection_add", text="", icon='ZOOMIN')
obj_name = obj.name
- for group in bpy.data.groups:
+ for collection in bpy.data.collections:
# XXX this is slow and stupid!, we need 2 checks, one thats fast
# and another that we can be sure its not a name collision
# from linked library data
- group_objects = group.objects
- if obj_name in group.objects and obj in group_objects[:]:
+ collection_objects = collection.objects
+ if obj_name in collection.objects and obj in collection_objects[:]:
col = layout.column(align=True)
- col.context_pointer_set("group", group)
+ col.context_pointer_set("collection", collection)
row = col.box().row()
- row.prop(group, "name", text="")
- row.operator("object.group_remove", text="", icon='X', emboss=False)
- row.menu("GROUP_MT_specials", icon='DOWNARROW_HLT', text="")
+ row.prop(collection, "name", text="")
+ row.operator("object.collection_remove", text="", icon='X', emboss=False)
+ row.menu("COLLECTION_MT_specials", icon='DOWNARROW_HLT', text="")
- split = col.box().split()
-
- col = split.column()
- col.prop(group, "layers", text="Dupli Visibility")
-
- col = split.column()
- col.prop(group, "dupli_offset", text="")
+ row = col.box().row()
+ row.prop(collection, "dupli_offset", text="")
class OBJECT_PT_display(ObjectButtonsPanel, Panel):
- bl_label = "Display"
+ bl_label = "Viewport Display"
+ bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
obj = context.object
obj_type = obj.type
@@ -243,84 +231,93 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
is_empty_image = (obj_type == 'EMPTY' and obj.empty_draw_type == 'IMAGE')
is_dupli = (obj.dupli_type != 'NONE')
- split = layout.split()
-
- col = split.column()
+ col = flow.column(align=True)
col.prop(obj, "show_name", text="Name")
col.prop(obj, "show_axis", text="Axis")
+
# Makes no sense for cameras, armatures, etc.!
# but these settings do apply to dupli instances
+ col = flow.column(align=True)
if is_geometry or is_dupli:
- col.prop(obj, "show_wire", text="Wire")
+ col.prop(obj, "show_wire", text="Wireframe")
if obj_type == 'MESH' or is_dupli:
col.prop(obj, "show_all_edges")
- col = split.column()
- row = col.row()
- row.prop(obj, "show_bounds", text="Bounds")
- sub = row.row()
+ col = flow.column()
+ col.prop(obj, "show_bounds", text="Bounds")
+ sub = col.column()
sub.active = obj.show_bounds
- sub.prop(obj, "draw_bounds_type", text="")
+ sub.prop(obj, "draw_bounds_type")
+ col = flow.column()
if is_geometry:
col.prop(obj, "show_texture_space", text="Texture Space")
- col.prop(obj, "show_x_ray", text="X-Ray")
- if obj_type == 'MESH' or is_empty_image:
- col.prop(obj, "show_transparent", text="Transparency")
+ col.prop(obj.display, "show_shadows", text="Shadow")
- split = layout.split()
+ col.prop(obj, "show_x_ray", text="X-Ray")
+ # if obj_type == 'MESH' or is_empty_image:
+ # col.prop(obj, "show_transparent", text="Transparency")
- col = split.column()
+ col = flow.column()
if is_wire:
# wire objects only use the max. draw type for duplis
col.active = is_dupli
- col.label(text="Maximum Dupli Draw Type:")
- else:
- col.label(text="Maximum Draw Type:")
- col.prop(obj, "draw_type", text="")
+ col.prop(
+ obj, "draw_type",
+ text="Maximum Draw Type" if is_wire else "Maximum Draw Type",
+ )
- col = split.column()
if is_geometry or is_empty_image:
# Only useful with object having faces/materials...
- col.label(text="Object Color:")
- col.prop(obj, "color", text="")
+ col.prop(obj, "color")
class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
bl_label = "Duplication"
+ bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
ob = context.object
- layout.row().prop(ob, "dupli_type", expand=True)
+ row = layout.row()
+ row.prop(ob, "dupli_type", expand=True)
+
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
if ob.dupli_type == 'FRAMES':
- split = layout.split()
- col = split.column(align=True)
+ col = flow.column(align=True)
col.prop(ob, "dupli_frames_start", text="Start")
col.prop(ob, "dupli_frames_end", text="End")
- col = split.column(align=True)
+ col = flow.column(align=True)
col.prop(ob, "dupli_frames_on", text="On")
col.prop(ob, "dupli_frames_off", text="Off")
- layout.prop(ob, "use_dupli_frames_speed", text="Speed")
+ col = flow.column(align=True)
+ col.prop(ob, "use_dupli_frames_speed", text="Speed")
elif ob.dupli_type == 'VERTS':
layout.prop(ob, "use_dupli_vertices_rotation", text="Rotation")
elif ob.dupli_type == 'FACES':
- row = layout.row()
- row.prop(ob, "use_dupli_faces_scale", text="Scale")
- sub = row.row()
+ col = flow.column()
+ col.prop(ob, "use_dupli_faces_scale", text="Scale")
+ sub = col.column()
sub.active = ob.use_dupli_faces_scale
sub.prop(ob, "dupli_faces_scale", text="Inherit Scale")
- elif ob.dupli_type == 'GROUP':
- layout.prop(ob, "dupli_group", text="Group")
+ elif ob.dupli_type == 'COLLECTION':
+ col = flow.column()
+ col.prop(ob, "dupli_group", text="Collection")
+
+ if ob.dupli_type != 'NONE' or len(ob.particle_systems):
+ col = flow.column(align=True)
+ col.prop(ob, "show_duplicator_for_viewport")
+ col.prop(ob, "show_duplicator_for_render")
from .properties_animviz import (
@@ -362,7 +359,7 @@ class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel): # , Panel): # inherit fr
class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "object"
_property_type = bpy.types.Object
@@ -371,13 +368,11 @@ classes = (
OBJECT_PT_context_object,
OBJECT_PT_transform,
OBJECT_PT_delta_transform,
- OBJECT_PT_transform_locks,
OBJECT_PT_relations,
- OBJECT_PT_relations_extras,
- GROUP_MT_specials,
- OBJECT_PT_groups,
- OBJECT_PT_display,
+ COLLECTION_MT_specials,
+ OBJECT_PT_collections,
OBJECT_PT_duplication,
+ OBJECT_PT_display,
OBJECT_PT_motion_paths,
OBJECT_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index b4049bf7b68..f1e5102f061 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -96,8 +96,8 @@ class VIEW3D_MT_tools_projectpaint_clone(Menu):
def draw(self, context):
layout = self.layout
- for i, tex in enumerate(context.active_object.data.uv_textures):
- props = layout.operator("wm.context_set_int", text=tex.name, translate=False)
+ for i, uv_layer in enumerate(context.active_object.data.uv_layers):
+ props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
props.data_path = "active_object.data.uv_texture_clone_index"
props.value = i
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 14ca6f700f4..05538e71faf 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -21,6 +21,7 @@ import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
from bpy.app.translations import pgettext_iface as iface_
+from bl_operators.presets import PresetMenu
from .properties_physics_common import (
point_cache_ui,
@@ -42,7 +43,7 @@ def particle_panel_enabled(context, psys):
def particle_panel_poll(cls, context):
psys = context.particle_system
- engine = context.scene.render.engine
+ engine = context.engine
settings = 0
if psys:
@@ -66,7 +67,7 @@ def particle_get_settings(context):
class PARTICLE_MT_specials(Menu):
bl_label = "Particle Specials"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -82,12 +83,12 @@ class PARTICLE_MT_specials(Menu):
layout.operator("particle.duplicate_particle_system")
-class PARTICLE_MT_hair_dynamics_presets(Menu):
+class PARTICLE_PT_hair_dynamics_presets(PresetMenu):
bl_label = "Hair Dynamics Presets"
preset_subdir = "hair_dynamics"
preset_operator = "script.execute_preset"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- draw = Menu.draw_preset
+ preset_add_operator = "particle.hair_dynamics_preset_add"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
class ParticleButtonsPanel:
@@ -131,20 +132,16 @@ class PARTICLE_UL_particle_systems(bpy.types.UIList):
class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
+ engine = context.engine
return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
- if context.scene.render.engine == 'BLENDER_GAME':
- layout.label("Not available in the Game Engine")
- return
-
ob = context.object
psys = context.particle_system
part = 0
@@ -153,7 +150,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
row = layout.row()
row.template_list("PARTICLE_UL_particle_systems", "particle_systems", ob, "particle_systems",
- ob.particle_systems, "active_index", rows=1)
+ ob.particle_systems, "active_index", rows=2)
col = row.column(align=True)
col.operator("object.particle_system_add", icon='ZOOMIN', text="")
@@ -238,7 +235,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
bl_label = "Emission"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -259,67 +256,81 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
psys = context.particle_system
part = particle_get_settings(context)
+ layout.use_property_split = True
+
layout.enabled = particle_panel_enabled(context, psys) and (psys is None or not psys.has_multiple_caches)
- row = layout.row()
- row.active = part.emit_from == 'VERT' or part.distribution != 'GRID'
- row.prop(part, "count")
+ col = layout.column()
+ col.active = part.emit_from == 'VERT' or part.distribution != 'GRID'
+ col.prop(part, "count")
if part.type == 'HAIR':
- row.prop(part, "hair_length")
+ col.prop(part, "hair_length")
if not part.use_advanced_hair:
row = layout.row()
- row.prop(part, "use_modifier_stack")
+ col.prop(part, "use_modifier_stack")
return
if part.type != 'HAIR':
- split = layout.split()
- col = split.column(align=True)
- col.prop(part, "frame_start")
- col.prop(part, "frame_end")
+ col = layout.column()
+
+ sub = col.column(align=True)
+ sub.prop(part, "frame_start", text="Frame Start")
+ sub.prop(part, "frame_end", text="End")
- col = split.column(align=True)
col.prop(part, "lifetime")
- col.prop(part, "lifetime_random", slider=True)
+ col.prop(part, "lifetime_random", slider=True, text="Lifetime Randomness")
- layout.label(text="Emit From:")
- layout.row().prop(part, "emit_from", expand=True)
- row = layout.row()
+class PARTICLE_PT_emission_source(ParticleButtonsPanel, Panel):
+ bl_label = "Source"
+ bl_parent_id = "PARTICLE_PT_emission"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ part = particle_get_settings(context)
+
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(part, "emit_from")
+ col.prop(part, "use_modifier_stack")
+ if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
+ col.prop(part, "distribution")
+
if part.emit_from == 'VERT':
- row.prop(part, "use_emit_random")
+ col.prop(part, "use_emit_random", text="Random Order")
elif part.distribution == 'GRID':
- row.prop(part, "invert_grid")
- row.prop(part, "hexagonal_grid")
+ col.label(text="Grid")
+ col.prop(part, "invert_grid")
+ col.prop(part, "hexagonal_grid")
else:
- row.prop(part, "use_emit_random")
- row.prop(part, "use_even_distribution")
+ col.prop(part, "use_emit_random")
+ col.prop(part, "use_even_distribution")
if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
- layout.row().prop(part, "distribution", expand=True)
- row = layout.row()
if part.distribution == 'JIT':
- row.prop(part, "userjit", text="Particles/Face")
- row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
+ col.prop(part, "userjit", text="Particles/Face")
+ col.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
elif part.distribution == 'GRID':
- row.prop(part, "grid_resolution")
- row.prop(part, "grid_random", text="Random", slider=True)
-
- row = layout.row()
- row.prop(part, "use_modifier_stack")
+ col.prop(part, "grid_resolution")
+ col.prop(part, "grid_random", text="Random", slider=True)
class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
bl_label = "Hair Dynamics"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
psys = context.particle_system
- engine = context.scene.render.engine
+ engine = context.engine
if psys is None:
return False
if psys.settings is None:
@@ -330,12 +341,23 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
psys = context.particle_system
self.layout.prop(psys, "use_hair_dynamics", text="")
+ def draw_header_preset(self, context):
+ psys = context.particle_system
+
+ if not psys.cloth:
+ return
+
+ layout = self.layout
+ layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False
+ PARTICLE_PT_hair_dynamics_presets.draw_panel_header(layout)
+
def draw(self, context):
layout = self.layout
psys = context.particle_system
if not psys.cloth:
+ layout.label(text="Hair dynamics disabled")
return
cloth_md = psys.cloth
@@ -344,49 +366,20 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False
- row = layout.row(align=True)
- row.menu("PARTICLE_MT_hair_dynamics_presets", text=bpy.types.PARTICLE_MT_hair_dynamics_presets.bl_label)
- row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMIN')
- row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMOUT').remove_active = True
-
- split = layout.column()
-
- col = split.column()
- col.label(text="Structure")
- col.prop(cloth, "mass")
- sub = col.column(align=True)
- subsub = sub.row(align=True)
- subsub.prop(cloth, "bending_stiffness", text="Stiffness")
- subsub.prop(psys.settings, "bending_random", text="Random")
- sub.prop(cloth, "bending_damping", text="Damping")
- # XXX has no noticeable effect with stiff hair structure springs
- #col.prop(cloth, "spring_damping", text="Damping")
-
- split.separator()
-
- col = split.column()
- col.label(text="Volume")
- col.prop(cloth, "air_damping", text="Air Drag")
- col.prop(cloth, "internal_friction", slider=True)
- sub = col.column(align=True)
- sub.prop(cloth, "density_target", text="Density Target")
- sub.prop(cloth, "density_strength", slider=True, text="Strength")
- col.prop(cloth, "voxel_cell_size")
+ layout.use_property_split = True
- split.separator()
+ layout.separator()
- col = split.column()
- col.label(text="Pinning")
- col.prop(cloth, "pin_stiffness", text="Goal Strength")
+ col = layout.column()
+ col.prop(cloth, "quality", text="Quality Steps", slider=True)
+ col.prop(psys.settings, "show_hair_grid", text="Display Hair Grid")
- split.separator()
+ layout.separator()
- col = split.column()
- col.label(text="Quality:")
- col.prop(cloth, "quality", text="Steps", slider=True)
+ col = layout.column()
+ col.prop(cloth, "pin_stiffness", text="Pin Goal Strength")
- row = col.row()
- row.prop(psys.settings, "show_hair_grid", text="HairGrid")
+ layout.separator()
if result:
box = layout.box()
@@ -409,15 +402,80 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
box.label("Error: %.5f .. %.5f (avg. %.5f)" % (result.min_error, result.max_error, result.avg_error))
+class PARTICLE_PT_hair_dynamics_structure(ParticleButtonsPanel, Panel):
+ bl_label = "Structure"
+ bl_parent_id = "PARTICLE_PT_hair_dynamics"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.particle_system.cloth is not None
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ cloth_md = psys.cloth
+ cloth = cloth_md.settings
+ result = cloth_md.solver_result
+
+ layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False
+
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(cloth, "mass")
+ sub = col.column(align=True)
+ sub.prop(cloth, "bending_stiffness", text="Stiffness")
+ sub.prop(psys.settings, "bending_random", text="Random")
+ col.prop(cloth, "bending_damping", text="Damping")
+ # XXX has no noticeable effect with stiff hair structure springs
+ #col.prop(cloth, "spring_damping", text="Damping")
+
+
+class PARTICLE_PT_hair_dynamics_volume(ParticleButtonsPanel, Panel):
+ bl_label = "Volume"
+ bl_parent_id = "PARTICLE_PT_hair_dynamics"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.particle_system.cloth is not None
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ cloth_md = psys.cloth
+ cloth = cloth_md.settings
+ result = cloth_md.solver_result
+
+ layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False
+
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(cloth, "air_damping", text="Air Drag")
+ col.prop(cloth, "internal_friction", slider=True)
+ col.prop(cloth, "voxel_cell_size")
+
+ col.separator()
+
+ col.prop(cloth, "density_target", text="Density Target")
+ col.prop(cloth, "density_strength", slider=True, text="Density Strength")
+
+
class PARTICLE_PT_cache(ParticleButtonsPanel, Panel):
bl_label = "Cache"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
psys = context.particle_system
- engine = context.scene.render.engine
+ engine = context.engine
if psys is None:
return False
if psys.settings is None:
@@ -442,7 +500,8 @@ class PARTICLE_PT_cache(ParticleButtonsPanel, Panel):
class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel):
bl_label = "Velocity"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -463,37 +522,35 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel):
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys)
+ layout.use_property_split = True
- split = layout.split()
-
- col = split.column()
- col.label(text="Emitter Geometry:")
+ col = layout.column()
col.prop(part, "normal_factor")
sub = col.column(align=True)
- sub.prop(part, "tangent_factor")
- sub.prop(part, "tangent_phase", slider=True)
+ sub.prop(part, "tangent_factor", text="Tangent")
+ sub.prop(part, "tangent_phase", slider=True, text="Tangent Phase")
- col = split.column()
- col.label(text="Emitter Object:")
- col.prop(part, "object_align_factor", text="")
+ col.separator()
+
+ col.prop(part, "object_align_factor")
+
+ col.separator()
- layout.label(text="Other:")
- row = layout.row()
if part.emit_from == 'PARTICLE':
- row.prop(part, "particle_factor")
+ col.prop(part, "particle_factor")
else:
- row.prop(part, "object_factor", slider=True)
- row.prop(part, "factor_random")
+ col.prop(part, "object_factor", slider=True)
+ col.prop(part, "factor_random", text="Randomize")
# if part.type=='REACTOR':
- # sub.prop(part, "reactor_factor")
- # sub.prop(part, "reaction_shape", slider=True)
+ # sub.prop(part, "reactor_factor")
+ # sub.prop(part, "reaction_shape", slider=True)
class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel):
bl_label = "Rotation"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -526,37 +583,52 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel):
part = context.space_data.pin_id
layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations
+ layout.use_property_split = True
- layout.label(text="Initial Orientation:")
+ col = layout.column()
- split = layout.split()
+ col.prop(part, "rotation_mode")
+ col.prop(part, "rotation_factor_random", slider=True, text="Randomize")
- col = split.column(align=True)
- col.prop(part, "rotation_mode", text="")
- col.prop(part, "rotation_factor_random", slider=True, text="Random")
+ col.separator()
- col = split.column(align=True)
col.prop(part, "phase_factor", slider=True)
- col.prop(part, "phase_factor_random", text="Random", slider=True)
+ col.prop(part, "phase_factor_random", text="Randomize Phase ", slider=True)
if part.type != 'HAIR':
- layout.label(text="Angular Velocity:")
+ col.prop(part, "use_dynamic_rotation")
- split = layout.split()
- col = split.column(align=True)
- col.prop(part, "angular_velocity_mode", text="")
- sub = col.column(align=True)
- sub.active = part.angular_velocity_mode != 'NONE'
- sub.prop(part, "angular_velocity_factor", text="")
+class PARTICLE_PT_rotation_angular_velocity(ParticleButtonsPanel, Panel):
+ bl_label = "Angular Velocity"
+ bl_parent_id = "PARTICLE_PT_rotation"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- col = split.column()
- col.prop(part, "use_dynamic_rotation")
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ if psys:
+ part = psys.settings
+ else:
+ part = context.space_data.pin_id
+
+ layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations
+ layout.use_property_split = True
+
+ col = layout.column()
+
+ col.prop(part, "angular_velocity_mode", text="Axis")
+ sub = col.column(align=True)
+ sub.active = part.angular_velocity_mode != 'NONE'
+ sub.prop(part, "angular_velocity_factor", text="Amount")
class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
bl_label = "Physics"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -572,127 +644,87 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
psys = context.particle_system
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys)
- layout.row().prop(part, "physics_type", expand=True)
+ layout.prop(part, "physics_type")
- row = layout.row()
+ col = layout.column()
if part.physics_type != 'NO':
- col = row.column(align=True)
+ col = col.column()
col.prop(part, "mass")
col.prop(part, "use_multiply_size_mass", text="Multiply mass with size")
- if part.physics_type in {'NEWTON', 'FLUID'}:
- split = layout.split()
+ if part.physics_type == 'FLUID':
+ fluid = part.fluid
- col = split.column()
- col.label(text="Forces:")
- col.prop(part, "brownian_factor")
- col.prop(part, "drag_factor", slider=True)
- col.prop(part, "damping", slider=True)
+ col.label(text="Fluid")
+ col.prop(fluid, "solver")
+ col.prop(fluid, "stiffness", text="Stiffness")
+ col.prop(fluid, "linear_viscosity", text="Viscosity")
+ col.prop(fluid, "buoyancy", text="Buoyancy", slider=True)
- col = split.column()
- col.label(text="Integration:")
- col.prop(part, "integrator", text="")
- col.prop(part, "timestep")
- sub = col.row()
- sub.prop(part, "subframes")
- supports_courant = part.physics_type == 'FLUID'
- subsub = sub.row()
- subsub.enabled = supports_courant
- subsub.prop(part, "use_adaptive_subframes", text="")
- if supports_courant and part.use_adaptive_subframes:
- col.prop(part, "courant_target", text="Threshold")
+ col.label(text="Advanced")
- row = layout.row()
- row.prop(part, "use_size_deflect")
- row.prop(part, "use_die_on_collision")
+ if fluid.solver == 'DDR':
+ sub = col.column()
+ sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion)
+ sub.prop(fluid, "factor_repulsion")
- layout.prop(part, "collision_group")
+ sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity)
+ sub.prop(fluid, "factor_stiff_viscosity")
+
+ sub = col.column()
+ sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius)
+ sub.prop(fluid, "factor_radius")
+
+ sub.prop(fluid, "rest_density", slider=fluid.use_factor_density)
+ sub.prop(fluid, "use_factor_density")
+
+ if fluid.solver == 'CLASSICAL':
+ # With the classical solver, it is possible to calculate the
+ # spacing between particles when the fluid is at rest. This
+ # makes it easier to set stable initial conditions.
+ particle_volume = part.mass / fluid.rest_density
+ spacing = pow(particle_volume, 1.0 / 3.0)
+
+ sub.label(text="Spacing: %g" % spacing)
- if part.physics_type == 'FLUID':
- fluid = part.fluid
-
- split = layout.split()
- sub = split.row()
- sub.prop(fluid, "solver", expand=True)
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Fluid Properties:")
- col.prop(fluid, "stiffness", text="Stiffness")
- col.prop(fluid, "linear_viscosity", text="Viscosity")
- col.prop(fluid, "buoyancy", text="Buoyancy", slider=True)
-
- col = split.column()
- col.label(text="Advanced:")
-
- if fluid.solver == 'DDR':
- sub = col.row()
- sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion)
- sub.prop(fluid, "factor_repulsion", text="")
-
- sub = col.row()
- sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity)
- sub.prop(fluid, "factor_stiff_viscosity", text="")
-
- sub = col.row()
- sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius)
- sub.prop(fluid, "factor_radius", text="")
-
- sub = col.row()
- sub.prop(fluid, "rest_density", slider=fluid.use_factor_density)
- sub.prop(fluid, "use_factor_density", text="")
-
- if fluid.solver == 'CLASSICAL':
- # With the classical solver, it is possible to calculate the
- # spacing between particles when the fluid is at rest. This
- # makes it easier to set stable initial conditions.
- particle_volume = part.mass / fluid.rest_density
- spacing = pow(particle_volume, 1.0 / 3.0)
- sub = col.row()
- sub.label(text="Spacing: %g" % spacing)
-
- elif fluid.solver == 'DDR':
- split = layout.split()
-
- col = split.column()
- col.label(text="Springs:")
- col.prop(fluid, "spring_force", text="Force")
- col.prop(fluid, "use_viscoelastic_springs")
- sub = col.column(align=True)
- sub.active = fluid.use_viscoelastic_springs
- sub.prop(fluid, "yield_ratio", slider=True)
- sub.prop(fluid, "plasticity", slider=True)
-
- col = split.column()
- col.label(text="Advanced:")
- sub = col.row()
- sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length)
- sub.prop(fluid, "factor_rest_length", text="")
- col.label(text="")
- sub = col.column()
- sub.active = fluid.use_viscoelastic_springs
- sub.prop(fluid, "use_initial_rest_length")
- sub.prop(fluid, "spring_frames", text="Frames")
+ elif fluid.solver == 'DDR':
+
+ col.label(text="Springs")
+ col.prop(fluid, "spring_force", text="Force")
+ col.prop(fluid, "use_viscoelastic_springs")
+
+ sub = col.column()
+ sub.active = fluid.use_viscoelastic_springs
+ sub.prop(fluid, "yield_ratio", slider=True)
+ sub.prop(fluid, "plasticity", slider=True)
+
+ col.label(text="Advanced")
+ sub = col.column()
+ sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length)
+ sub.prop(fluid, "factor_rest_length", text="")
+
+ sub = col.column()
+ sub.active = fluid.use_viscoelastic_springs
+ sub.prop(fluid, "use_initial_rest_length")
+ sub.prop(fluid, "spring_frames", text="Frames")
elif part.physics_type == 'KEYED':
- split = layout.split()
- sub = split.column()
- row = layout.row()
- col = row.column()
- col.active = not psys.use_keyed_timing
- col.prop(part, "keyed_loops", text="Loops")
+ sub = col.column()
+ sub.active = not psys.use_keyed_timing
+ sub.prop(part, "keyed_loops", text="Loops")
if psys:
- row.prop(psys, "use_keyed_timing", text="Use Timing")
+ col.prop(psys, "use_keyed_timing", text="Use Timing")
+
+ col.label(text="Keys")
- layout.label(text="Keys:")
elif part.physics_type == 'BOIDS':
boids = part.boids
@@ -790,15 +822,102 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
sub.prop(key, "system", text="System")
+class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel):
+ bl_label = "Deflection"
+ bl_parent_id = "PARTICLE_PT_physics"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.physics_type in {'NEWTON', 'FLUID'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ layout.enabled = particle_panel_enabled(context, psys)
+
+ col = layout.column()
+ col.prop(part, "use_size_deflect")
+ col.prop(part, "use_die_on_collision")
+
+ col.prop(part, "collision_group")
+
+
+class PARTICLE_PT_physics_forces(ParticleButtonsPanel, Panel):
+ bl_label = "Forces"
+ bl_parent_id = "PARTICLE_PT_physics"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.physics_type == 'NEWTON'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ layout.enabled = particle_panel_enabled(context, psys)
+
+ col = layout.column()
+
+ col.prop(part, "brownian_factor")
+ col.prop(part, "drag_factor", slider=True)
+ col.prop(part, "damping", slider=True)
+
+
+class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel):
+ bl_label = "Integration"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "PARTICLE_PT_physics"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.physics_type == 'NEWTON'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ layout.enabled = particle_panel_enabled(context, psys)
+
+ col = layout.column()
+
+ col.prop(part, "integrator")
+ col.prop(part, "timestep")
+ sub = col.row()
+ sub.prop(part, "subframes")
+ supports_courant = part.physics_type == 'FLUID'
+ subsub = sub.row()
+ subsub.enabled = supports_courant
+ subsub.prop(part, "use_adaptive_subframes", text="")
+ if supports_courant and part.use_adaptive_subframes:
+ col.prop(part, "courant_target", text="Threshold")
+
+
class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
bl_label = "Boid Brain"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
psys = context.particle_system
settings = particle_get_settings(context)
- engine = context.scene.render.engine
+ engine = context.engine
if settings is None:
return False
@@ -895,12 +1014,13 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
bl_label = "Render"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
settings = particle_get_settings(context)
- engine = context.scene.render.engine
+ engine = context.engine
if settings is None:
return False
@@ -908,257 +1028,453 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
psys = context.particle_system
part = particle_get_settings(context)
+ layout.prop(part, "render_type", text="Render As")
+
+ if part.type == 'EMITTER' or \
+ (part.render_type in {'OBJECT', 'COLLECTION'} and part.type == 'HAIR'):
+ if part.render_type not in {'NONE'}:
+
+ col = layout.column(align=True)
+ col.prop(part, "particle_size", text="Scale")
+ col.prop(part, "size_random", slider=True, text="Scale Randomness")
+
if psys:
- row = layout.row()
- if part.render_type in {'OBJECT', 'GROUP'}:
- row.enabled = False
- row.prop(part, "material_slot", text="")
- row.prop(psys, "parent")
+ col = layout.column()
+ if part.render_type not in {'OBJECT', 'COLLECTION', 'NONE'}:
+ # col.enabled = False
+ col.prop(part, "material_slot", text="Material")
+ col.prop(psys, "parent", text="Coordinate System")
- split = layout.split()
- col = split.column()
- col.prop(part, "use_render_emitter")
- col.prop(part, "use_parent_particles")
+class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel):
+ bl_label = "Extra"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- col = split.column()
- col.prop(part, "show_unborn")
- col.prop(part, "use_dead")
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type != 'NONE'
- layout.row().prop(part, "render_type", expand=True)
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
- split = layout.split()
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
- col = split.column()
+ col = layout.column()
- if part.render_type == 'LINE':
- col.prop(part, "line_length_tail")
- col.prop(part, "line_length_head")
+ col = layout.column()
+ col.prop(part, "use_parent_particles", text="Parent Particles")
+ col.prop(part, "show_unborn", text="Unborn")
+ col.prop(part, "use_dead", text="Dead")
- split.prop(part, "use_velocity_length")
- elif part.render_type == 'PATH':
- col.prop(part, "use_strand_primitive")
- sub = col.column()
- sub.active = (part.use_strand_primitive is False)
- sub.prop(part, "use_render_adaptive")
- sub = col.column()
- sub.active = part.use_render_adaptive or part.use_strand_primitive is True
- sub.prop(part, "adaptive_angle")
- sub = col.column()
- sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False)
- sub.prop(part, "adaptive_pixel")
- col.prop(part, "use_hair_bspline")
- col.prop(part, "render_step", text="Steps")
- col = split.column()
- col.label(text="Timing:")
- col.prop(part, "use_absolute_path_time")
+class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel):
+ bl_label = "Line"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- if part.type == 'HAIR' or psys.point_cache.is_baked:
- col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time)
- else:
- col.prop(part, "trail_count")
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'LINE'
- col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
- col.prop(part, "length_random", text="Random", slider=True)
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
- row = layout.row()
- col = row.column()
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
- if part.type == 'HAIR' and part.use_strand_primitive is True and part.child_type == 'INTERPOLATED':
- layout.prop(part, "use_simplify")
- if part.use_simplify is True:
- row = layout.row()
- row.prop(part, "simplify_refsize")
- row.prop(part, "simplify_rate")
- row.prop(part, "simplify_transition")
- row = layout.row()
- row.prop(part, "use_simplify_viewport")
- sub = row.row()
- sub.active = part.use_simplify_viewport is True
- sub.prop(part, "simplify_viewport")
+ col = layout.column()
- elif part.render_type == 'OBJECT':
- col.prop(part, "dupli_object")
- sub = col.row()
- sub.prop(part, "use_global_dupli")
- sub.prop(part, "use_rotation_dupli")
- sub.prop(part, "use_scale_dupli")
- elif part.render_type == 'GROUP':
- col.prop(part, "dupli_group")
- split = layout.split()
+ col.separator()
+ sub = col.column(align=True)
+ sub.prop(part, "line_length_tail", text="Length Tail")
+ sub.prop(part, "line_length_head", text="Head")
+ col.prop(part, "use_velocity_length", text="Velocity Length")
- col = split.column()
- col.prop(part, "use_whole_group")
- sub = col.column()
- sub.active = (part.use_whole_group is False)
- sub.prop(part, "use_group_pick_random")
- sub.prop(part, "use_group_count")
- col = split.column()
- sub = col.column()
- sub.active = (part.use_whole_group is False)
- sub.prop(part, "use_global_dupli")
- sub.prop(part, "use_rotation_dupli")
- sub.prop(part, "use_scale_dupli")
+class PARTICLE_PT_render_path(ParticleButtonsPanel, Panel):
+ bl_label = "Path"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- if part.use_group_count and not part.use_whole_group:
- row = layout.row()
- row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights",
- part, "active_dupliweight_index")
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'PATH'
- col = row.column()
- sub = col.row()
- subsub = sub.column(align=True)
- subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
- subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
- subsub.operator("particle.dupliob_move_up", icon='TRIA_UP', text="")
- subsub.operator("particle.dupliob_move_down", icon='TRIA_DOWN', text="")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
- weight = part.active_dupliweight
- if weight:
- row = layout.row()
- row.prop(weight, "count")
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
- elif part.render_type == 'BILLBOARD':
- ob = context.object
+ col = layout.column()
- col.label(text="Align:")
+ col.prop(part, "use_strand_primitive")
+ sub = col.column()
+ sub.active = (part.use_strand_primitive is False)
+ sub.prop(part, "use_render_adaptive")
+ sub = col.column()
+ sub.active = part.use_render_adaptive or part.use_strand_primitive is True
+ sub.prop(part, "adaptive_angle")
+ sub = col.column()
+ sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False)
+ sub.prop(part, "adaptive_pixel")
+ col.prop(part, "use_hair_bspline")
+ col.prop(part, "render_step", text="Steps")
+
+
+class PARTICLE_PT_render_path_timing(ParticleButtonsPanel, Panel):
+ bl_label = "Timing"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- row = layout.row()
- row.prop(part, "billboard_align", expand=True)
- row.prop(part, "lock_billboard", text="Lock")
- row = layout.row()
- row.prop(part, "billboard_object")
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'PATH'
- row = layout.row()
- col = row.column(align=True)
- col.label(text="Tilt:")
- col.prop(part, "billboard_tilt", text="Angle", slider=True)
- col.prop(part, "billboard_tilt_random", text="Random", slider=True)
- col = row.column()
- col.prop(part, "billboard_offset")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
- row = layout.row()
- col = row.column()
- col.prop(part, "billboard_size", text="Scale")
- if part.billboard_align == 'VEL':
- col = row.column(align=True)
- col.label("Velocity Scale:")
- col.prop(part, "billboard_velocity_head", text="Head")
- col.prop(part, "billboard_velocity_tail", text="Tail")
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
- if psys:
- col = layout.column()
- col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_textures")
- col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_textures")
+ col = layout.column()
- split = layout.split(percentage=0.33)
- split.label(text="Split UVs:")
- split.prop(part, "billboard_uv_split", text="Number of splits")
+ col.prop(part, "use_absolute_path_time")
- if psys:
- col = layout.column()
- col.active = part.billboard_uv_split > 1
- col.prop_search(psys, "billboard_split_uv", ob.data, "uv_textures")
+ if part.type == 'HAIR' or psys.point_cache.is_baked:
+ col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time)
+ else:
+ col.prop(part, "trail_count")
+
+ col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
+ col.prop(part, "length_random", text="Random", slider=True)
+
+
+class PARTICLE_PT_render_object(ParticleButtonsPanel, Panel):
+ bl_label = "Object"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'OBJECT'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ col.prop(part, "dupli_object", text="Instance Object")
+ sub = col.column()
+ sub.prop(part, "use_global_dupli", text="Global Coordinates")
+ sub.prop(part, "use_rotation_dupli", text="Object Rotation")
+ sub.prop(part, "use_scale_dupli", text="Object Scale")
- row = col.row()
- row.label(text="Animate:")
- row.prop(part, "billboard_animation", text="")
- row.label(text="Offset:")
- row.prop(part, "billboard_offset_split", text="")
- if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD':
+class PARTICLE_PT_render_collection(ParticleButtonsPanel, Panel):
+ bl_label = "Collection"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'COLLECTION'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ col.prop(part, "dupli_group")
+
+ col.prop(part, "use_whole_group")
+ sub = col.column()
+ sub.active = (part.use_whole_group is False)
+ sub.prop(part, "use_group_pick_random")
+ sub.prop(part, "use_global_dupli", text="Global Coordinates")
+ sub.prop(part, "use_rotation_dupli", text="Object Rotation")
+ sub.prop(part, "use_scale_dupli", text="Object Scale")
+
+
+class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel):
+ bl_label = "Use Count"
+ bl_parent_id = "PARTICLE_PT_render_collection"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'COLLECTION'
+
+ def draw_header(self, context):
+ layout = self.layout
+ part = particle_get_settings(context)
+
+ layout.active = not part.use_whole_group
+
+ layout.prop(part, "use_group_count", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ layout.active = part.use_group_count and not part.use_whole_group
+
+ row = layout.row()
+ row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights",
+ part, "active_dupliweight_index")
+
+ col = row.column()
+ sub = col.row()
+ subsub = sub.column(align=True)
+ subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
+ subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
+ subsub.operator("particle.dupliob_move_up", icon='TRIA_UP', text="")
+ subsub.operator("particle.dupliob_move_down", icon='TRIA_DOWN', text="")
+ subsub.separator()
+ subsub.operator("particle.dupliob_refresh", icon='FILE_REFRESH', text="")
+
+ weight = part.active_dupliweight
+ if weight:
row = layout.row()
- col = row.column()
- col.prop(part, "trail_count")
- if part.trail_count > 1:
- col.prop(part, "use_absolute_path_time", text="Length in Frames")
- col = row.column()
- col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time)
- col.prop(part, "length_random", text="Random", slider=True)
- else:
- col = row.column()
- col.label(text="")
+ row.prop(weight, "count")
- if part.type == 'EMITTER' or \
- (part.render_type in {'OBJECT', 'GROUP'} and part.type == 'HAIR'):
- row = layout.row(align=True)
- row.prop(part, "particle_size")
- row.prop(part, "size_random", slider=True)
+
+class PARTICLE_PT_render_billboards_alignment(ParticleButtonsPanel, Panel):
+ bl_label = "Billboard Alignment"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'BILLBOARD'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ col.prop(part, "billboard_align", text="Align To")
+ col.prop(part, "lock_billboard", text="Lock Axis")
+ col.prop(part, "billboard_object")
+
+
+class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel):
+ bl_label = "Billboard Tilt"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'BILLBOARD'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ sub = col.column(align=True)
+ sub.prop(part, "billboard_tilt", text="Angle", slider=True)
+ sub.prop(part, "billboard_tilt_random", text="Random", slider=True)
+
+ sub = col.column(align=True)
+ sub.prop(part, "billboard_offset")
+ col.prop(part, "billboard_size", text="Scale")
+ if part.billboard_align == 'VEL':
+ col = col.column(align=True)
+ col.prop(part, "billboard_velocity_head", text="Velocity ScaleHead")
+ col.prop(part, "billboard_velocity_tail", text="Tail")
+
+
+class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel):
+ bl_label = "Billboard UVs"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type == 'BILLBOARD'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ ob = context.object
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ if psys:
+ col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_layers")
+ col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_layers")
+
+ col.prop(part, "billboard_uv_split", text="Split UVs")
+
+ if psys:
+ sub = col.column()
+ sub.active = part.billboard_uv_split > 1
+ sub.prop_search(psys, "billboard_split_uv", ob.data, "uv_layers")
+
+ sub.prop(part, "billboard_animation")
+ sub.prop(part, "billboard_offset_split")
+
+
+class PARTICLE_PT_render_trails(ParticleButtonsPanel, Panel):
+ bl_label = "Trails"
+ bl_parent_id = "PARTICLE_PT_render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.render_type in {'HALO', 'LINE', 'BILLBOARD'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ col = layout.column()
+
+ col.prop(part, "trail_count")
+
+ sub = col.column()
+ sub.active = (part.trail_count > 1)
+ sub.prop(part, "use_absolute_path_time", text="Length in Frames")
+ sub.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time)
+ sub.prop(part, "length_random", text="Random Length", slider=True)
class PARTICLE_PT_draw(ParticleButtonsPanel, Panel):
- bl_label = "Display"
+ bl_label = "Viewport Display"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
settings = particle_get_settings(context)
- engine = context.scene.render.engine
+ engine = context.engine
if settings is None:
return False
return engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
psys = context.particle_system
part = particle_get_settings(context)
- row = layout.row()
- row.prop(part, "draw_method", expand=True)
- row.prop(part, "show_guide_hairs")
+ layout.prop(part, "draw_method", text="Display As")
if part.draw_method == 'NONE' or (part.render_type == 'NONE' and part.draw_method == 'RENDER'):
return
path = (part.render_type == 'PATH' and part.draw_method == 'RENDER') or part.draw_method == 'PATH'
- row = layout.row()
- row.prop(part, "draw_percentage", slider=True)
+ layout.separator()
+
+ col = layout.column()
+ col.prop(part, "draw_color", text="Color")
+ if part.draw_color in {'VELOCITY', 'ACCELERATION'}:
+ col.prop(part, "color_maximum", text="Fade Distance")
+
+ col = layout.column()
+
+ if path:
+ col.prop(part, "draw_step", text="Strand Steps")
+ col.prop(part, "draw_percentage", slider=True, text="Amount")
if part.draw_method != 'RENDER' or part.render_type == 'HALO':
- row.prop(part, "draw_size")
- else:
- row.label(text="")
+ col.prop(part, "draw_size", text="Size")
if part.draw_percentage != 100 and psys is not None:
if part.type == 'HAIR':
if psys.use_hair_dynamics and psys.point_cache.is_baked is False:
- layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
+ layout.row().label(text="Display percentage makes dynamics inaccurate without baking")
else:
phystype = part.physics_type
if phystype != 'NO' and phystype != 'KEYED' and psys.point_cache.is_baked is False:
- layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
+ layout.row().label(text="Display percentage makes dynamics inaccurate without baking")
+ else:
+ layout.row().label(text="")
- row = layout.row()
- col = row.column()
+ col = layout.column()
+ col.prop(part, "show_guide_hairs", text="Guide Hairs")
col.prop(part, "show_size")
col.prop(part, "show_velocity")
col.prop(part, "show_number")
if part.physics_type == 'BOIDS':
col.prop(part, "show_health")
- col = row.column(align=True)
- col.label(text="Color:")
- col.prop(part, "draw_color", text="")
- sub = col.row(align=True)
- sub.active = (part.draw_color in {'VELOCITY', 'ACCELERATION'})
- sub.prop(part, "color_maximum", text="Max")
-
- if path:
- col.prop(part, "draw_step")
-
class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
bl_label = "Children"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -1172,37 +1488,91 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
layout.row().prop(part, "child_type", expand=True)
+ layout.use_property_split = True
+
if part.child_type == 'NONE':
return
- row = layout.row()
+ col = layout.column()
- col = row.column(align=True)
- col.prop(part, "child_nbr", text="Display")
- col.prop(part, "rendered_child_count", text="Render")
+ sub = col.column(align=True)
+ sub.prop(part, "child_nbr", text="Display Amount")
+ sub.prop(part, "rendered_child_count", text="Render Amount")
+
+ col.separator()
+
+ col.prop(part, "child_length", slider=True)
+ col.prop(part, "child_length_threshold", slider=True)
+ if psys:
+ col.prop(psys, "child_seed", text="Seed")
+
+ col.separator()
if part.child_type == 'INTERPOLATED':
- col = row.column()
- if psys:
- col.prop(psys, "child_seed", text="Seed")
col.prop(part, "virtual_parents", slider=True)
col.prop(part, "create_long_hair_children")
else:
- col = row.column(align=True)
- col.prop(part, "child_size", text="Size")
- col.prop(part, "child_size_random", text="Random")
+ col.separator()
+ sub = col.column(align=True)
+ sub.prop(part, "child_size", text="Size")
+ sub.prop(part, "child_size_random", text="Randomize Size", slider=True)
- split = layout.split()
+ if part.child_type == 'SIMPLE':
+ col.separator()
+ col.prop(part, "child_radius", text="Radius")
+ col.prop(part, "child_roundness", text="Roundness", slider=True)
+ elif part.virtual_parents > 0.0:
+ sub = col.column(align=True)
+ sub.label(text="Parting not available with virtual parents")
- col = split.column()
- col.label(text="Effects:")
- sub = col.column(align=True)
- if part.child_type == 'SIMPLE':
- sub.prop(part, "twist")
- sub.prop(part, "use_twist_curve")
- if part.use_twist_curve:
- sub.template_curve_mapping(part, "twist_curve")
+class PARTICLE_PT_children_parting(ParticleButtonsPanel, Panel):
+ bl_label = "Parting"
+ bl_parent_id = "PARTICLE_PT_children"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.child_type == 'INTERPOLATED'
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(part, "child_parting_factor", text="Parting", slider=True)
+ col.prop(part, "child_parting_min", text="Min")
+ col.prop(part, "child_parting_max", text="Max")
+
+
+class PARTICLE_PT_children_clumping(ParticleButtonsPanel, Panel):
+ bl_label = "Clumping"
+ bl_parent_id = "PARTICLE_PT_children"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.child_type != 'NONE'
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ layout.use_property_split = True
+
+ col = layout.column()
+
+ sub = col.column()
sub.prop(part, "use_clump_curve")
if part.use_clump_curve:
@@ -1216,28 +1586,33 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
subsub.enabled = part.use_clump_noise
subsub.prop(part, "clump_noise_size")
- sub = col.column(align=True)
- sub.prop(part, "child_length", slider=True)
- sub.prop(part, "child_length_threshold", slider=True)
-
if part.child_type == 'SIMPLE':
- sub = col.column(align=True)
- sub.prop(part, "child_radius", text="Radius")
- sub.prop(part, "child_roundness", text="Roundness", slider=True)
- if psys:
- sub.prop(psys, "child_seed", text="Seed")
- elif part.virtual_parents > 0.0:
- sub = col.column(align=True)
- sub.label(text="Parting not")
- sub.label(text="available with")
- sub.label(text="virtual parents")
- else:
- sub = col.column(align=True)
- sub.prop(part, "child_parting_factor", text="Parting", slider=True)
- sub.prop(part, "child_parting_min", text="Min")
- sub.prop(part, "child_parting_max", text="Max")
+ sub.prop(part, "twist")
+ sub.prop(part, "use_twist_curve")
+ if part.use_twist_curve:
+ sub.template_curve_mapping(part, "twist_curve")
+
+
+class PARTICLE_PT_children_roughness(ParticleButtonsPanel, Panel):
+ bl_label = "Roughness"
+ bl_parent_id = "PARTICLE_PT_children"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.child_type != 'NONE'
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
- col = split.column()
+ layout.use_property_split = True
+
+ col = layout.column()
col.prop(part, "use_roughness_curve")
if part.use_roughness_curve:
@@ -1246,8 +1621,6 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
sub.prop(part, "roughness_1", text="Roughness")
sub.prop(part, "roughness_1_size", text="Size")
else:
- col.label(text="Roughness:")
-
sub = col.column(align=True)
sub.prop(part, "roughness_1", text="Uniform")
sub.prop(part, "roughness_1_size", text="Size")
@@ -1261,31 +1634,55 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
sub.prop(part, "roughness_2_size", text="Size")
sub.prop(part, "roughness_2_threshold", slider=True)
- layout.row().label(text="Kink:")
- layout.row().prop(part, "kink", expand=True)
- split = layout.split()
- split.active = part.kink != 'NO'
+class PARTICLE_PT_children_kink(ParticleButtonsPanel, Panel):
+ bl_label = "Kink"
+ bl_parent_id = "PARTICLE_PT_children"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ part = particle_get_settings(context)
+ return part.child_type != 'NONE'
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ part = particle_get_settings(context)
+
+ layout.use_property_split = True
+
+ col = layout.column()
+
+ col.prop(part, "kink", text="Kink Type")
+ col = layout.column()
+ col.active = part.kink != 'NO'
if part.kink == 'SPIRAL':
- col = split.column()
- sub = col.column(align=True)
- sub.prop(part, "kink_amplitude", text="Radius")
- sub.prop(part, "kink_amplitude_random", text="Random", slider=True)
- sub = col.column(align=True)
+
+ sub = col.column()
+ sub.prop(part, "kink_amplitude", text="Amplitude")
+ sub.prop(part, "kink_amplitude_random", text="Randomize Amplitude", slider=True)
+
+ col.separator()
+
+ sub = col.column()
sub.prop(part, "kink_axis")
- sub.prop(part, "kink_axis_random", text="Random", slider=True)
- col = split.column(align=True)
+ sub.prop(part, "kink_axis_random", text="Randomize Axis", slider=True)
+
+ col.separator()
+
col.prop(part, "kink_frequency", text="Frequency")
col.prop(part, "kink_shape", text="Shape", slider=True)
col.prop(part, "kink_extra_steps", text="Steps")
- else:
- col = split.column()
+
+ elif part.kink in {'CURL', 'RADIAL', 'WAVE', 'BRAID', 'WAVE'}:
sub = col.column(align=True)
sub.prop(part, "kink_amplitude")
sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
col.prop(part, "kink_flat", slider=True)
- col = split.column(align=True)
col.prop(part, "kink_frequency")
col.prop(part, "kink_shape", slider=True)
@@ -1293,7 +1690,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
bl_label = "Field Weights"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -1314,41 +1711,85 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
class PARTICLE_PT_force_fields(ParticleButtonsPanel, Panel):
bl_label = "Force Field Settings"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
part = particle_get_settings(context)
- row = layout.row()
- row.prop(part, "use_self_effect")
- row.prop(part, "effector_amount", text="Amount")
+ col = layout.column()
+ col.prop(part, "use_self_effect")
+ col.prop(part, "effector_amount", text="Effector Amount")
+
+
+class PARTICLE_PT_force_fields_type1(ParticleButtonsPanel, Panel):
+ bl_label = "Type 1"
+ bl_parent_id = "PARTICLE_PT_force_fields"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ part = particle_get_settings(context)
- split = layout.split(percentage=0.2)
- split.label(text="Type 1:")
- split.prop(part.force_field_1, "type", text="")
+ col = layout.column()
+ col.prop(part.force_field_1, "type", text="Type 1")
basic_force_field_settings_ui(self, context, part.force_field_1)
- if part.force_field_1.type != 'NONE':
- layout.label(text="Falloff:")
- basic_force_field_falloff_ui(self, context, part.force_field_1)
- if part.force_field_1.type != 'NONE':
- layout.label(text="")
- split = layout.split(percentage=0.2)
- split.label(text="Type 2:")
- split.prop(part.force_field_2, "type", text="")
+class PARTICLE_PT_force_fields_type2(ParticleButtonsPanel, Panel):
+ bl_label = "Type 2"
+ bl_parent_id = "PARTICLE_PT_force_fields"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ part = particle_get_settings(context)
+
+ col = layout.column()
+ col.prop(part.force_field_2, "type", text="Type 2")
basic_force_field_settings_ui(self, context, part.force_field_2)
- if part.force_field_2.type != 'NONE':
- layout.label(text="Falloff:")
+
+
+class PARTICLE_PT_force_fields_type1_falloff(ParticleButtonsPanel, Panel):
+ bl_label = "Falloff"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "PARTICLE_PT_force_fields_type1"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ part = particle_get_settings(context)
+
+ basic_force_field_falloff_ui(self, context, part.force_field_1)
+
+
+class PARTICLE_PT_force_fields_type2_falloff(ParticleButtonsPanel, Panel):
+ bl_label = "Falloff"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "PARTICLE_PT_force_fields_type2"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ part = particle_get_settings(context)
+
basic_force_field_falloff_ui(self, context, part.force_field_2)
class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
bl_label = "Vertex Groups"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -1358,6 +1799,7 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
psys = context.particle_system
@@ -1417,30 +1859,118 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
# row.prop(psys, "invert_vertex_group_field", text="")
+class PARTICLE_PT_textures(ParticleButtonsPanel, Panel):
+ bl_label = "Textures"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ if context.particle_system is None:
+ return False
+ return particle_panel_poll(cls, context)
+
+ def draw(self, context):
+ layout = self.layout
+
+ psys = context.particle_system
+ part = psys.settings
+
+ row = layout.row()
+ row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
+ col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+ col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
+
+ if not part.active_texture:
+ layout.template_ID(part, "active_texture", new="texture.new")
+ else:
+ slot = part.texture_slots[part.active_texture_index]
+ layout.template_ID(slot, "texture", new="texture.new")
+
+
+class PARTICLE_PT_hair_shape(ParticleButtonsPanel, Panel):
+ bl_label = "Hair Shape"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ if context.particle_system is None:
+ return False
+ return particle_panel_poll(cls, context)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ psys = context.particle_system
+ part = psys.settings
+
+ layout.prop(part, "shape", text="Strand Shape")
+
+ col = layout.column(align=True)
+ col.prop(part, "root_radius", text="Radius Root")
+ col.prop(part, "tip_radius", text="Tip")
+
+ col = layout.column()
+ col.prop(part, "radius_scale", text="Radius Scaling")
+ col.prop(part, "use_close_tip")
+
+
class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "particle_system.settings"
_property_type = bpy.types.ParticleSettings
classes = (
PARTICLE_MT_specials,
- PARTICLE_MT_hair_dynamics_presets,
+ PARTICLE_PT_hair_dynamics_presets,
PARTICLE_UL_particle_systems,
PARTICLE_PT_context_particles,
PARTICLE_PT_emission,
+ PARTICLE_PT_emission_source,
PARTICLE_PT_hair_dynamics,
+ PARTICLE_PT_hair_dynamics_structure,
+ PARTICLE_PT_hair_dynamics_volume,
PARTICLE_PT_cache,
PARTICLE_PT_velocity,
PARTICLE_PT_rotation,
+ PARTICLE_PT_rotation_angular_velocity,
PARTICLE_PT_physics,
+ PARTICLE_PT_physics_forces,
+ PARTICLE_PT_physics_deflection,
+ PARTICLE_PT_physics_integration,
PARTICLE_PT_boidbrain,
PARTICLE_PT_render,
+ PARTICLE_PT_render_line,
+ PARTICLE_PT_render_path,
+ PARTICLE_PT_render_path_timing,
+ PARTICLE_PT_render_object,
+ PARTICLE_PT_render_collection,
+ PARTICLE_PT_render_collection_use_count,
+ PARTICLE_PT_render_billboards_tilt,
+ PARTICLE_PT_render_billboards_uv,
+ PARTICLE_PT_render_trails,
+ PARTICLE_PT_render_extra,
PARTICLE_PT_draw,
PARTICLE_PT_children,
+ PARTICLE_PT_children_parting,
+ PARTICLE_PT_children_clumping,
+ PARTICLE_PT_children_roughness,
+ PARTICLE_PT_children_kink,
+ PARTICLE_PT_hair_shape,
PARTICLE_PT_field_weights,
PARTICLE_PT_force_fields,
+ PARTICLE_PT_force_fields_type1,
+ PARTICLE_PT_force_fields_type1_falloff,
+ PARTICLE_PT_force_fields_type2,
+ PARTICLE_PT_force_fields_type2_falloff,
PARTICLE_PT_vertexgroups,
+ PARTICLE_PT_textures,
PARTICLE_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py
index 45cddd3d6b9..2f659af3891 100644
--- a/release/scripts/startup/bl_ui/properties_physics_cloth.py
+++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel
+from bl_operators.presets import PresetMenu
from .properties_physics_common import (
point_cache_ui,
@@ -30,11 +31,11 @@ def cloth_panel_enabled(md):
return md.point_cache.is_baked is False
-class CLOTH_MT_presets(Menu):
+class CLOTH_PT_presets(PresetMenu):
bl_label = "Cloth Presets"
preset_subdir = "cloth"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "cloth.preset_add"
class PhysicButtonsPanel:
@@ -45,13 +46,15 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.cloth)
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.cloth)
class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
bl_label = "Cloth"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header_preset(self, context):
+ CLOTH_PT_presets.draw_panel_header(self.layout)
def draw(self, context):
layout = self.layout
@@ -64,14 +67,6 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
split = layout.split(percentage=0.25)
- split.label(text="Presets:")
- sub = split.row(align=True)
- sub.menu("CLOTH_MT_presets", text=bpy.types.CLOTH_MT_presets.bl_label)
- sub.operator("cloth.preset_add", text="", icon='ZOOMIN')
- sub.operator("cloth.preset_add", text="", icon='ZOOMOUT').remove_active = True
-
- split = layout.split(percentage=0.25)
-
split.label(text="Quality:")
split.prop(cloth, "quality", text="Steps")
@@ -131,9 +126,10 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
- bl_label = "Cloth Cache"
+ bl_label = "Cache"
+ bl_parent_id = 'PHYSICS_PT_cloth'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
md = context.cloth
@@ -141,9 +137,10 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
- bl_label = "Cloth Collision"
+ bl_label = "Collision"
+ bl_parent_id = 'PHYSICS_PT_cloth'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
cloth = context.cloth.collision_settings
@@ -181,9 +178,10 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel):
- bl_label = "Cloth Stiffness Scaling"
+ bl_label = "Stiffness Scaling"
+ bl_parent_id = 'PHYSICS_PT_cloth'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
cloth = context.cloth.settings
@@ -214,9 +212,10 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel):
- bl_label = "Cloth Sewing Springs"
+ bl_label = "Sewing Springs"
+ bl_parent_id = 'PHYSICS_PT_cloth'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
cloth = context.cloth.settings
@@ -248,9 +247,10 @@ class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel):
class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel):
- bl_label = "Cloth Field Weights"
+ bl_label = "Field Weights"
+ bl_parent_id = 'PHYSICS_PT_cloth'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
cloth = context.cloth.settings
@@ -258,7 +258,7 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel):
classes = (
- CLOTH_MT_presets,
+ CLOTH_PT_presets,
PHYSICS_PT_cloth,
PHYSICS_PT_cloth_cache,
PHYSICS_PT_cloth_collision,
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index b821b20a1ae..e071de0108b 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -30,8 +30,7 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
- rd = context.scene.render
- return (context.object) and rd.engine in cls.COMPAT_ENGINES
+ return (context.object) and context.engine in cls.COMPAT_ENGINES
def physics_add(self, layout, md, name, type, typeicon, toggles):
@@ -57,7 +56,7 @@ def physics_add_special(self, layout, data, name, addop, removeop, typeicon):
class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
obj = context.object
@@ -140,14 +139,16 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
layout.enabled = False
if not cache.use_external or cachetype == 'SMOKE':
- row = layout.row(align=True)
+ col = layout.column(align=True)
+ col.use_property_split = True
if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}:
- row.enabled = enabled
- row.prop(cache, "frame_start")
- row.prop(cache, "frame_end")
+
+ col.enabled = enabled
+ col.prop(cache, "frame_start", text="Simulation Start")
+ col.prop(cache, "frame_end")
if cachetype not in {'SMOKE', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
- row.prop(cache, "frame_step")
+ col.prop(cache, "frame_step")
if cachetype != 'SMOKE':
layout.label(text=cache.info)
@@ -207,9 +208,12 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
def effector_weights_ui(self, context, weights, weight_type):
layout = self.layout
+ layout.use_property_split = True
layout.prop(weights, "group")
+ layout.use_property_split = False
+
split = layout.split()
split.prop(weights, "gravity", slider=True)
@@ -240,13 +244,12 @@ def effector_weights_ui(self, context, weights, weight_type):
def basic_force_field_settings_ui(self, context, field):
layout = self.layout
-
- split = layout.split()
+ layout.use_property_split = True
if not field or field.type == 'NONE':
return
- col = split.column()
+ col = layout.column()
if field.type == 'DRAG':
col.prop(field, "linear_drag", text="Linear")
@@ -266,10 +269,10 @@ def basic_force_field_settings_ui(self, context, field):
else:
col.prop(field, "flow")
- col = split.column()
+ col = layout.column()
sub = col.column(align=True)
sub.prop(field, "noise")
- sub.prop(field, "seed")
+ sub.prop(field, "seed", text="Noise Seed")
if field.type == 'TURBULENCE':
col.prop(field, "use_global_coords", text="Global")
elif field.type == 'HARMONIC':
@@ -277,46 +280,33 @@ def basic_force_field_settings_ui(self, context, field):
if field.type == 'FORCE':
col.prop(field, "use_gravity_falloff", text="Gravitation")
- split = layout.split()
-
- col = split.column()
- col.label(text="Effect point:")
- col.prop(field, "apply_to_location")
- col.prop(field, "apply_to_rotation")
-
- col = split.column()
- col.label(text="Collision:")
+ col.prop(field, "apply_to_location", text="Affect Location")
+ col.prop(field, "apply_to_rotation", text="Affect Rotation")
col.prop(field, "use_absorption")
def basic_force_field_falloff_ui(self, context, field):
layout = self.layout
- split = layout.split(percentage=0.35)
-
if not field or field.type == 'NONE':
return
- col = split.column()
- col.prop(field, "z_direction", text="")
+ col = layout.column()
+ col.prop(field, "z_direction")
- col = split.column()
col.prop(field, "falloff_power", text="Power")
split = layout.split()
- col = split.column()
- row = col.row(align=True)
- row.prop(field, "use_min_distance", text="")
- sub = row.row(align=True)
+ split.prop(field, "use_min_distance", text="Min Distance")
+ sub = split.column(align=True)
sub.active = field.use_min_distance
- sub.prop(field, "distance_min", text="Minimum")
+ sub.prop(field, "distance_min", text="")
- col = split.column()
- row = col.row(align=True)
- row.prop(field, "use_max_distance", text="")
- sub = row.row(align=True)
+ split = layout.split()
+ split.prop(field, "use_max_distance", text="Max Distance")
+ sub = split.column(align=True)
sub.active = field.use_max_distance
- sub.prop(field, "distance_max", text="Maximum")
+ sub.prop(field, "distance_max", text="")
classes = (
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index ef426253a69..6a66dafadf0 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -55,13 +55,12 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (ob and ob.type == 'MESH') and rd.engine in cls.COMPAT_ENGINES and context.dynamic_paint
+ return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and context.dynamic_paint
class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -109,7 +108,6 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
elif md.ui_type == 'BRUSH':
brush = md.brush_settings
- use_shading_nodes = context.scene.render.use_shading_nodes
if brush is None:
layout.operator("dpaint.type_toggle", text="Add Brush").type = 'BRUSH'
@@ -124,27 +122,19 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
col.prop(brush, "paint_wetness", text="Wetness")
col = split.column()
- if not use_shading_nodes:
- sub = col.column()
- sub.active = (brush.paint_source != 'PARTICLE_SYSTEM')
- sub.prop(brush, "use_material")
- if brush.use_material and brush.paint_source != 'PARTICLE_SYSTEM' and not use_shading_nodes:
- col.prop(brush, "material", text="")
- col.prop(brush, "paint_alpha", text="Alpha Factor")
- else:
- col.prop(brush, "paint_color", text="")
- col.prop(brush, "paint_alpha", text="Alpha")
+ col.prop(brush, "paint_color", text="")
+ col.prop(brush, "paint_alpha", text="Alpha")
class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Advanced"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_label = "Advanced"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
- return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and rd.engine in cls.COMPAT_ENGINES
+ return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and context.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -213,20 +203,20 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Output"
+ bl_label = "Output"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
return 0
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
return (surface and
(not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'}))) and
- (rd.engine in cls.COMPAT_ENGINES))
+ (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -276,7 +266,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
# image format outputs
if surface.surface_format == 'IMAGE':
layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
- layout.prop_search(surface, "uv_layer", ob.data, "uv_textures", text="UV Map")
+ layout.prop_search(surface, "uv_layer", ob.data, "uv_layers", text="UV Map")
layout.separator()
layout.prop(surface, "image_output_path", text="")
@@ -307,18 +297,18 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Initial Color"
+ bl_label = "Initial Color"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
return 0
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
- return (surface and surface.surface_type == 'PAINT') and (rd.engine in cls.COMPAT_ENGINES)
+ return (surface and surface.surface_type == 'PAINT') and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -337,25 +327,25 @@ class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
elif surface.init_color_type == 'TEXTURE':
layout.prop(surface, "init_texture")
- layout.prop_search(surface, "init_layername", ob.data, "uv_textures", text="UV Map")
+ layout.prop_search(surface, "init_layername", ob.data, "uv_layers", text="UV Map")
elif surface.init_color_type == 'VERTEX_COLOR':
layout.prop_search(surface, "init_layername", ob.data, "vertex_colors", text="Color Layer")
class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Effects"
+ bl_label = "Effects"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
return False
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
- return (surface and surface.surface_type == 'PAINT') and (rd.engine in cls.COMPAT_ENGINES)
+ return (surface and surface.surface_type == 'PAINT') and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -394,20 +384,20 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Cache"
+ bl_label = "Cache"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
return (md and
md.ui_type == 'CANVAS' and
md.canvas_settings and
md.canvas_settings.canvas_surfaces.active and
md.canvas_settings.canvas_surfaces.active.is_cache_user and
- (rd.engine in cls.COMPAT_ENGINES))
+ (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
@@ -417,14 +407,14 @@ class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Source"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_label = "Source"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
- return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES)
+ return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -470,15 +460,15 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Velocity"
+ bl_label = "Velocity"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
- return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES)
+ return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -507,15 +497,15 @@ class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Waves"
+ bl_label = "Waves"
+ bl_parent_id = "PHYSICS_PT_dynamic_paint"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.dynamic_paint
- rd = context.scene.render
- return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES)
+ return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py
index fb3d1631377..3b01015047f 100644
--- a/release/scripts/startup/bl_ui/properties_physics_field.py
+++ b/release/scripts/startup/bl_ui/properties_physics_field.py
@@ -33,60 +33,50 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
- rd = context.scene.render
- return (context.object) and (rd.engine in cls.COMPAT_ENGINES)
+ return (context.object) and (context.engine in cls.COMPAT_ENGINES)
class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
bl_label = "Force Fields"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (rd.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type != 'NONE')
+ if not ob:
+ return False
+ return (context.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type != 'NONE')
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
ob = context.object
field = ob.field
- split = layout.split(percentage=0.2)
- split.label(text="Type:")
-
- split.prop(field, "type", text="")
+ layout.prop(field, "type")
if field.type not in {'NONE', 'GUIDE', 'TEXTURE'}:
- split = layout.split(percentage=0.2)
- split.label(text="Shape:")
- split.prop(field, "shape", text="")
+ layout.prop(field, "shape", text="Shape")
elif field.type == 'TEXTURE':
- split = layout.split(percentage=0.2)
- split.label(text="Texture:")
- split.row().template_ID(field, "texture", new="texture.new")
-
- split = layout.split()
+ layout.row().template_ID(field, "texture", new="texture.new")
if field.type == 'NONE':
return # nothing to draw
elif field.type == 'GUIDE':
- col = split.column()
+ col = layout.column()
col.prop(field, "guide_minimum")
col.prop(field, "guide_free")
col.prop(field, "falloff_power")
col.prop(field, "use_guide_path_add")
col.prop(field, "use_guide_path_weight")
- col = split.column()
- col.label(text="Clumping:")
+ col.label(text="Clumping")
col.prop(field, "guide_clump_amount")
col.prop(field, "guide_clump_shape")
- row = layout.row()
- row.prop(field, "use_max_distance")
- sub = row.row()
+ col.prop(field, "use_max_distance")
+ sub = col.column()
sub.active = field.use_max_distance
sub.prop(field, "distance_max")
@@ -96,94 +86,96 @@ class PHYSICS_PT_field(PhysicButtonsPanel, Panel):
if field.guide_kink_type != 'NONE':
layout.prop(field, "guide_kink_axis")
- split = layout.split()
-
- col = split.column()
+ col = layout.column()
col.prop(field, "guide_kink_frequency")
col.prop(field, "guide_kink_shape")
-
- col = split.column()
col.prop(field, "guide_kink_amplitude")
elif field.type == 'TEXTURE':
- col = split.column()
+ col = layout.column()
col.prop(field, "strength")
- col.prop(field, "texture_mode", text="")
+ col.prop(field, "texture_mode")
col.prop(field, "texture_nabla")
- col = split.column()
col.prop(field, "use_object_coords")
col.prop(field, "use_2d_force")
elif field.type == 'SMOKE_FLOW':
- col = split.column()
+ col = layout.column()
col.prop(field, "strength")
col.prop(field, "flow")
- col = split.column()
- col.label(text="Domain Object:")
- col.prop(field, "source_object", "")
+ col.prop(field, "source_object")
col.prop(field, "use_smoke_density")
else:
basic_force_field_settings_ui(self, context, field)
- if field.type not in {'NONE', 'GUIDE'}:
- layout.label(text="Falloff:")
- layout.row().prop(field, "falloff_type", expand=True)
+class PHYSICS_PT_field_falloff(PhysicButtonsPanel, Panel):
+ bl_label = "Falloff"
+ bl_parent_id = "PHYSICS_PT_field"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (context.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type not in {'NONE', 'GUIDE'})
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+ field = ob.field
- basic_force_field_falloff_ui(self, context, field)
+ layout.prop(field, "falloff_type", text="Shape")
- if field.falloff_type == 'CONE':
- layout.separator()
+ basic_force_field_falloff_ui(self, context, field)
- split = layout.split(percentage=0.35)
+ if field.falloff_type == 'CONE':
+ layout.separator()
- col = split.column()
- col.label(text="Angular:")
- col.prop(field, "use_radial_min", text="Use Minimum")
- col.prop(field, "use_radial_max", text="Use Maximum")
+ col = layout.column()
+ col.prop(field, "radial_falloff", text="Power")
- col = split.column()
- col.prop(field, "radial_falloff", text="Power")
+ col.label(text="Angular")
- sub = col.column()
- sub.active = field.use_radial_min
- sub.prop(field, "radial_min", text="Angle")
+ col.prop(field, "use_radial_min", text="Use Min Angle")
+ sub = col.column()
+ sub.active = field.use_radial_min
+ sub.prop(field, "radial_min", text="Min Angle")
- sub = col.column()
- sub.active = field.use_radial_max
- sub.prop(field, "radial_max", text="Angle")
+ col.prop(field, "use_radial_max", text="Use Max Angle")
+ sub = col.column()
+ sub.active = field.use_radial_max
+ sub.prop(field, "radial_max", text="Max Angle")
- elif field.falloff_type == 'TUBE':
- layout.separator()
+ elif field.falloff_type == 'TUBE':
+ layout.separator()
- split = layout.split(percentage=0.35)
+ col = layout.column()
- col = split.column()
- col.label(text="Radial:")
- col.prop(field, "use_radial_min", text="Use Minimum")
- col.prop(field, "use_radial_max", text="Use Maximum")
+ col.prop(field, "radial_falloff", text="Power")
- col = split.column()
- col.prop(field, "radial_falloff", text="Power")
+ col.label(text="Radial")
- sub = col.column()
- sub.active = field.use_radial_min
- sub.prop(field, "radial_min", text="Distance")
+ col.prop(field, "use_radial_min", text="Use Minimum")
+ sub = col.column()
+ sub.active = field.use_radial_min
+ sub.prop(field, "radial_min", text="Distance")
- sub = col.column()
- sub.active = field.use_radial_max
- sub.prop(field, "radial_max", text="Distance")
+ col.prop(field, "use_radial_max", text="Use Maximum")
+ sub = col.column()
+ sub.active = field.use_radial_max
+ sub.prop(field, "radial_max", text="Distance")
class PHYSICS_PT_collision(PhysicButtonsPanel, Panel):
bl_label = "Collision"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.collision)
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.collision)
def draw(self, context):
layout = self.layout
@@ -191,6 +183,7 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, Panel):
md = context.collision
split = layout.split()
+ layout.use_property_split = True
coll = md.settings
@@ -199,39 +192,90 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, Panel):
layout.active = settings.use
- split = layout.split()
+ col = layout.column()
+ col.prop(settings, "absorption", text="Force Field Absorption")
+
+
+class PHYSICS_PT_collision_particle(PhysicButtonsPanel, Panel):
+ bl_label = "Particle"
+ bl_parent_id = "PHYSICS_PT_collision"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.collision)
+
+ def draw(self, context):
+ layout = self.layout
+
+ md = context.collision
- col = split.column()
- col.label(text="Particle:")
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ coll = md.settings
+
+ if coll:
+ settings = context.object.collision
+
+ layout.active = settings.use
+
+ col = flow.column()
col.prop(settings, "permeability", slider=True)
col.prop(settings, "stickiness")
+ col = flow.column()
col.prop(settings, "use_particle_kill")
- col.label(text="Particle Damping:")
- sub = col.column(align=True)
- sub.prop(settings, "damping_factor", text="Factor", slider=True)
- sub.prop(settings, "damping_random", text="Random", slider=True)
- col.label(text="Particle Friction:")
+ col = flow.column()
sub = col.column(align=True)
- sub.prop(settings, "friction_factor", text="Factor", slider=True)
- sub.prop(settings, "friction_random", text="Random", slider=True)
+ sub.prop(settings, "damping_factor", text="Damping", slider=True)
+ sub.prop(settings, "damping_random", text="Randomize", slider=True)
- col = split.column()
- col.label(text="Soft Body and Cloth:")
+ col = flow.column()
sub = col.column(align=True)
- sub.prop(settings, "thickness_outer", text="Outer", slider=True)
- sub.prop(settings, "thickness_inner", text="Inner", slider=True)
+ sub.prop(settings, "friction_factor", text="Friction", slider=True)
+ sub.prop(settings, "friction_random", text="Randomize", slider=True)
+
+
+class PHYSICS_PT_collision_softbody(PhysicButtonsPanel, Panel):
+ bl_label = "Softbody"
+ bl_parent_id = "PHYSICS_PT_collision"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.collision)
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
+
+ md = context.collision
+ coll = md.settings
+
+ if coll:
+ settings = context.object.collision
+
+ layout.active = settings.use
- col.label(text="Soft Body Damping:")
- col.prop(settings, "damping", text="Factor", slider=True)
+ col = flow.column()
+ col.prop(settings, "damping", text="Damping", slider=True)
- col.label(text="Force Fields:")
- col.prop(settings, "absorption", text="Absorption")
+ col = flow.column()
+ col.prop(settings, "thickness_outer", text="Thickness Outer", slider=True)
+ col.prop(settings, "thickness_inner", text="Inner", slider=True)
classes = (
PHYSICS_PT_field,
+ PHYSICS_PT_field_falloff,
PHYSICS_PT_collision,
+ PHYSICS_PT_collision_particle,
+ PHYSICS_PT_collision_softbody,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index ab92370f9ae..94611808059 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -20,13 +20,14 @@
import bpy
from bpy.types import Panel, Menu
from bpy.app.translations import pgettext_iface as iface_
+from bl_operators.presets import PresetMenu
-class FLUID_MT_presets(Menu):
+class FLUID_PT_presets(PresetMenu):
bl_label = "Fluid Presets"
preset_subdir = "fluid"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "fluid.preset_add"
class PhysicButtonsPanel:
@@ -37,13 +38,12 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (ob and ob.type == 'MESH') and rd.engine in cls.COMPAT_ENGINES and (context.fluid)
+ return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid)
class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
bl_label = "Fluid"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -204,15 +204,15 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
- bl_label = "Fluid World"
+ bl_label = "World"
+ bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.fluid
- rd = context.scene.render
- return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES
+ return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -242,11 +242,7 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
col.prop(fluid, "simulation_scale", text="Meters")
col = split.column()
- col.label(text="Viscosity Presets:")
- sub = col.row(align=True)
- sub.menu("FLUID_MT_presets", text=bpy.types.FLUID_MT_presets.bl_label)
- sub.operator("fluid.preset_add", text="", icon='ZOOMIN')
- sub.operator("fluid.preset_add", text="", icon='ZOOMOUT').remove_active = True
+ FLUID_PT_presets.draw_menu(col, text="Viscosity Presets")
sub = col.column(align=True)
sub.prop(fluid, "viscosity_base", text="Base")
@@ -258,15 +254,15 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel):
class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
- bl_label = "Fluid Boundary"
+ bl_label = "Boundary"
+ bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.fluid
- rd = context.scene.render
- return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES
+ return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -289,15 +285,15 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel):
class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
- bl_label = "Fluid Particles"
+ bl_label = "Particles"
+ bl_parent_id = 'PHYSICS_PT_fluid'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.fluid
- rd = context.scene.render
- return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES
+ return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -310,7 +306,7 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
classes = (
- FLUID_MT_presets,
+ FLUID_PT_presets,
PHYSICS_PT_fluid,
PHYSICS_PT_domain_gravity,
PHYSICS_PT_domain_boundary,
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
index 847df2e1fd7..db59665e21d 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
@@ -29,13 +29,13 @@ class PHYSICS_PT_rigidbody_panel:
class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Rigid Body"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
- (context.scene.render.engine in cls.COMPAT_ENGINES))
+ (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -55,14 +55,15 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
- bl_label = "Rigid Body Collisions"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_label = "Collisions"
+ bl_parent_id = 'PHYSICS_PT_rigid_body'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
- (context.scene.render.engine in cls.COMPAT_ENGINES))
+ (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -99,16 +100,17 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
- bl_label = "Rigid Body Dynamics"
- bl_default_closed = True
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_label = "Dynamics"
+ bl_parent_id = 'PHYSICS_PT_rigid_body'
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
obj.rigid_body.type == 'ACTIVE' and
- (context.scene.render.engine in cls.COMPAT_ENGINES))
+ (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
index 84a4cbb4b68..aca989fd0ba 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
@@ -29,13 +29,12 @@ class PHYSICS_PT_rigidbody_constraint_panel:
class PHYSICS_PT_rigid_body_constraint(PHYSICS_PT_rigidbody_constraint_panel, Panel):
bl_label = "Rigid Body Constraint"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (ob and ob.rigid_body_constraint and rd.engine in cls.COMPAT_ENGINES)
+ return (ob and ob.rigid_body_constraint and context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index 9489fb71e15..acbaecbda4c 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -34,13 +34,12 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.smoke)
+ return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.smoke)
class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
bl_label = "Smoke"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -136,9 +135,10 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Flow Advanced"
+ bl_label = "Advanced"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -160,7 +160,7 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
sub.label(text="Mapping:")
sub.prop(flow, "texture_map_type", expand=False, text="")
if flow.texture_map_type == 'UV':
- sub.prop_search(flow, "uv_layer", ob.data, "uv_textures", text="")
+ sub.prop_search(flow, "uv_layer", ob.data, "uv_layers", text="")
if flow.texture_map_type == 'AUTO':
sub.prop(flow, "texture_size")
sub.prop(flow, "texture_offset")
@@ -171,9 +171,10 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Flames"
+ bl_label = "Flames"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -201,9 +202,10 @@ class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Adaptive Domain"
+ bl_label = "Adaptive Domain"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -235,15 +237,15 @@ class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
- bl_label = "Smoke High Resolution"
+ bl_label = "High Resolution"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.smoke
- rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
+ return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
md = context.smoke.domain_settings
@@ -275,15 +277,15 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Groups"
+ bl_label = "Groups"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.smoke
- rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
+ return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -304,15 +306,15 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Cache"
+ bl_label = "Cache"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.smoke
- rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
+ return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -341,30 +343,30 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Field Weights"
+ bl_label = "Field Weights"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
md = context.smoke
- rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES)
+ return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
domain = context.smoke.domain_settings
effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
-class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
- bl_label = "Smoke Display Settings"
+class PHYSICS_PT_smoke_viewport_display(PhysicButtonsPanel, Panel):
+ bl_label = "Viewport Display"
+ bl_parent_id = 'PHYSICS_PT_smoke'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
md = context.smoke
- rd = context.scene.render
- return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine)
+ return md and (md.smoke_type == 'DOMAIN')
def draw(self, context):
domain = context.smoke.domain_settings
@@ -395,23 +397,53 @@ class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
row.enabled = do_full_slicing or not do_axis_slicing
row.prop(domain, "slice_per_voxel")
- layout.separator()
- layout.label(text="Debug:")
- layout.prop(domain, "draw_velocity")
- col = layout.column()
- col.enabled = domain.draw_velocity
- col.prop(domain, "vector_draw_type")
- col.prop(domain, "vector_scale")
- layout.separator()
- layout.label(text="Color Mapping:")
- layout.prop(domain, "use_color_ramp")
+class PHYSICS_PT_smoke_viewport_display_color(PhysicButtonsPanel, Panel):
+ bl_label = "Color Mapping"
+ bl_parent_id = 'PHYSICS_PT_smoke_viewport_display'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ md = context.smoke
+ return md and (md.smoke_type == 'DOMAIN')
+
+ def draw_header(self, context):
+ md = context.smoke.domain_settings
+
+ self.layout.prop(md, "use_color_ramp", text="")
+
+ def draw(self, context):
+ domain = context.smoke.domain_settings
+ layout = self.layout
+
col = layout.column()
col.enabled = domain.use_color_ramp
col.prop(domain, "coba_field")
col.template_color_ramp(domain, "color_ramp", expand=True)
+class PHYSICS_PT_smoke_viewport_display_debug(PhysicButtonsPanel, Panel):
+ bl_label = "Debug"
+ bl_parent_id = 'PHYSICS_PT_smoke_viewport_display'
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ md = context.smoke
+ return md and (md.smoke_type == 'DOMAIN')
+
+ def draw(self, context):
+ domain = context.smoke.domain_settings
+ layout = self.layout
+
+ layout.prop(domain, "draw_velocity")
+ col = layout.column()
+ col.enabled = domain.draw_velocity
+ col.prop(domain, "vector_draw_type")
+ col.prop(domain, "vector_scale")
+
+
classes = (
PHYSICS_PT_smoke,
PHYSICS_PT_smoke_flow_advanced,
@@ -421,7 +453,9 @@ classes = (
PHYSICS_PT_smoke_groups,
PHYSICS_PT_smoke_cache,
PHYSICS_PT_smoke_field_weights,
- PHYSICS_PT_smoke_display_settings,
+ PHYSICS_PT_smoke_viewport_display,
+ PHYSICS_PT_smoke_viewport_display_color,
+ PHYSICS_PT_smoke_viewport_display_debug,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py
index 8f193427441..68db165875e 100644
--- a/release/scripts/startup/bl_ui/properties_physics_softbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py
@@ -41,13 +41,12 @@ class PhysicButtonsPanel:
@classmethod
def poll(cls, context):
ob = context.object
- rd = context.scene.render
- return ob and ob.type in COMPAT_OB_TYPES and rd.engine in cls.COMPAT_ENGINES and context.soft_body
+ return ob and ob.type in COMPAT_OB_TYPES and context.engine in cls.COMPAT_ENGINES and context.soft_body
class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel):
bl_label = "Soft Body"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -75,9 +74,10 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Cache"
+ bl_label = "Cache"
+ bl_parent_id = 'PHYSICS_PT_softbody'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
md = context.soft_body
@@ -85,9 +85,10 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Goal"
+ bl_label = "Goal"
+ bl_parent_id = 'PHYSICS_PT_softbody'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
softbody = context.soft_body.settings
@@ -125,9 +126,10 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Edges"
+ bl_label = "Edges"
+ bl_parent_id = 'PHYSICS_PT_softbody'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
softbody = context.soft_body.settings
@@ -175,9 +177,10 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Self Collision"
+ bl_label = "Self Collision"
+ bl_parent_id = 'PHYSICS_PT_softbody'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
softbody = context.soft_body.settings
@@ -204,9 +207,10 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Solver"
+ bl_label = "Solver"
+ bl_parent_id = 'PHYSICS_PT_softbody'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -237,9 +241,10 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel):
class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Field Weights"
+ bl_label = "Field Weights"
+ bl_parent_id = 'PHYSICS_PT_softbody'
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
md = context.soft_body
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index bd5d926d4cd..a7cfee5ed8f 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -19,21 +19,21 @@
# <pep8 compliant>
import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Menu, Panel, UIList
+from bl_operators.presets import PresetMenu
-class RENDER_MT_presets(Menu):
+class RENDER_PT_presets(PresetMenu):
bl_label = "Render Presets"
preset_subdir = "render"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "render.preset_add"
-class RENDER_MT_ffmpeg_presets(Menu):
+class RENDER_PT_ffmpeg_presets(PresetMenu):
bl_label = "FFMPEG Presets"
preset_subdir = "ffmpeg"
preset_operator = "script.python_file_run"
- draw = Menu.draw_preset
class RENDER_MT_framerate_presets(Menu):
@@ -51,39 +51,42 @@ class RenderButtonsPanel:
@classmethod
def poll(cls, context):
- scene = context.scene
- return scene and (scene.render.engine in cls.COMPAT_ENGINES)
+ return (context.engine in cls.COMPAT_ENGINES)
-class RENDER_PT_render(RenderButtonsPanel, Panel):
- bl_label = "Render"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+class RENDER_PT_context(Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "render"
+ bl_options = {'HIDE_HEADER'}
+ bl_label = ""
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
- rd = context.scene.render
-
- row = layout.row(align=True)
- row.operator("render.render", text="Render", icon='RENDER_STILL')
- row.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True
- row.operator("sound.mixdown", text="Audio", icon='PLAY_AUDIO')
-
- split = layout.split(percentage=0.33)
+ scene = context.scene
+ rd = scene.render
- split.label(text="Display:")
- row = split.row(align=True)
- row.prop(rd, "display_mode", text="")
- row.prop(rd, "use_lock_interface", icon_only=True)
+ if rd.has_multiple_engines:
+ layout.prop(rd, "engine", text="Render Engine")
class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
bl_label = "Dimensions"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_frame_rate_args_prev = None
_preset_class = None
+ def draw_header_preset(self, context):
+ RENDER_PT_presets.draw_panel_header(self.layout)
+
@staticmethod
def _draw_framerate_label(*args):
# avoids re-creating text string each draw
@@ -127,237 +130,89 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
scene = context.scene
rd = scene.render
- row = layout.row(align=True)
- row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label)
- row.operator("render.preset_add", text="", icon='ZOOMIN')
- row.operator("render.preset_add", text="", icon='ZOOMOUT').remove_active = True
+ col = layout.column(align=True)
+ col.prop(rd, "resolution_x", text="Resolution X")
+ col.prop(rd, "resolution_y", text="Y")
+ col.prop(rd, "resolution_percentage", text="%")
- split = layout.split()
+ col = layout.column(align=True)
+ col.prop(rd, "pixel_aspect_x", text="Aspect X")
+ col.prop(rd, "pixel_aspect_y", text="Y")
- col = split.column()
+ col = layout.column(align=True)
+ col.prop(rd, "use_border", text="Border")
sub = col.column(align=True)
- sub.label(text="Resolution:")
- sub.prop(rd, "resolution_x", text="X")
- sub.prop(rd, "resolution_y", text="Y")
- sub.prop(rd, "resolution_percentage", text="")
-
- sub.label(text="Aspect Ratio:")
- sub.prop(rd, "pixel_aspect_x", text="X")
- sub.prop(rd, "pixel_aspect_y", text="Y")
-
- row = col.row()
- row.prop(rd, "use_border", text="Border")
- sub = row.row()
sub.active = rd.use_border
sub.prop(rd, "use_crop_to_border", text="Crop")
- col = split.column()
- sub = col.column(align=True)
- sub.label(text="Frame Range:")
- sub.prop(scene, "frame_start")
- sub.prop(scene, "frame_end")
- sub.prop(scene, "frame_step")
-
- sub.label(text="Frame Rate:")
-
- self.draw_framerate(sub, rd)
-
- subrow = sub.row(align=True)
- subrow.label(text="Time Remapping:")
- subrow = sub.row(align=True)
- subrow.prop(rd, "frame_map_old", text="Old")
- subrow.prop(rd, "frame_map_new", text="New")
-
-
-class RENDER_PT_antialiasing(RenderButtonsPanel, Panel):
- bl_label = "Anti-Aliasing"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw_header(self, context):
- rd = context.scene.render
-
- self.layout.prop(rd, "use_antialiasing", text="")
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.render
- layout.active = rd.use_antialiasing
-
- split = layout.split()
-
- col = split.column()
- col.row().prop(rd, "antialiasing_samples", expand=True)
- sub = col.row()
- sub.prop(rd, "use_full_sample")
-
- col = split.column()
- col.prop(rd, "pixel_filter_type", text="")
- col.prop(rd, "filter_size", text="Size")
-
-
-class RENDER_PT_motion_blur(RenderButtonsPanel, Panel):
- bl_label = "Sampled Motion Blur"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- rd = context.scene.render
- return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES)
+ col = layout.column(align=True)
+ col.prop(scene, "frame_start", text="Frame Start")
+ col.prop(scene, "frame_end", text="End")
+ col.prop(scene, "frame_step", text="Step")
- def draw_header(self, context):
- rd = context.scene.render
+ col = layout.split(percentage=0.5)
+ col.alignment = 'RIGHT'
+ col.label(text="Frame Rate")
+ self.draw_framerate(col, rd)
- self.layout.prop(rd, "use_motion_blur", text="")
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.render
- layout.active = rd.use_motion_blur
- row = layout.row()
- row.prop(rd, "motion_blur_samples")
- row.prop(rd, "motion_blur_shutter")
-
-
-class RENDER_PT_shading(RenderButtonsPanel, Panel):
- bl_label = "Shading"
+class RENDER_PT_frame_remapping(RenderButtonsPanel, Panel):
+ bl_label = "Time Remapping"
+ bl_parent_id = "RENDER_PT_dimensions"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
rd = context.scene.render
- split = layout.split()
-
- col = split.column()
- col.prop(rd, "use_textures", text="Textures")
- col.prop(rd, "use_shadows", text="Shadows")
- col.prop(rd, "use_sss", text="Subsurface Scattering")
- col.prop(rd, "use_envmaps", text="Environment Map")
-
- col = split.column()
- col.prop(rd, "use_raytrace", text="Ray Tracing")
- col.prop(rd, "alpha_mode", text="Alpha")
- col.prop(rd, "use_world_space_shading", text="World Space Shading")
-
-
-class RENDER_PT_performance(RenderButtonsPanel, Panel):
- bl_label = "Performance"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.render
-
- split = layout.split()
-
- col = split.column(align=True)
- col.label(text="Threads:")
- col.row(align=True).prop(rd, "threads_mode", expand=True)
- sub = col.column(align=True)
- sub.enabled = rd.threads_mode == 'FIXED'
- sub.prop(rd, "threads")
-
- col.label(text="Tile Size:")
- col.prop(rd, "tile_x", text="X")
- col.prop(rd, "tile_y", text="Y")
-
- col.separator()
- col.prop(rd, "preview_start_resolution")
- col.prop(rd, "preview_pixel_size", text="")
-
- col = split.column()
- col.label(text="Memory:")
- sub = col.column()
- sub.enabled = not rd.use_full_sample
- sub.prop(rd, "use_save_buffers")
- sub = col.column()
- sub.active = rd.use_compositing
- sub.prop(rd, "use_free_image_textures")
- sub = col.column()
- sub.active = rd.use_raytrace
- sub.label(text="Acceleration Structure:")
- sub.prop(rd, "raytrace_method", text="")
- if rd.raytrace_method == 'OCTREE':
- sub.prop(rd, "octree_resolution", text="Resolution")
- else:
- sub.prop(rd, "use_instances", text="Instances")
- sub.prop(rd, "use_local_coords", text="Local Coordinates")
+ col = layout.column(align=True)
+ col.prop(rd, "frame_map_old", text="Old")
+ col.prop(rd, "frame_map_new", text="New")
class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
rd = context.scene.render
- split = layout.split()
-
- col = split.column()
+ col = layout.column(align=True)
col.prop(rd, "use_compositing")
col.prop(rd, "use_sequencer")
- split.prop(rd, "dither_intensity", text="Dither", slider=True)
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.prop(rd, "use_fields", text="Fields")
- sub = col.column()
- sub.active = rd.use_fields
- sub.row().prop(rd, "field_order", expand=True)
- sub.prop(rd, "use_fields_still", text="Still")
-
- col = split.column()
- col.prop(rd, "use_edge_enhance")
- sub = col.column()
- sub.active = rd.use_edge_enhance
- sub.prop(rd, "edge_threshold", text="Threshold", slider=True)
- sub.prop(rd, "edge_color", text="")
+ col.prop(rd, "dither_intensity", text="Dither", slider=True)
class RENDER_PT_stamp(RenderButtonsPanel, Panel):
bl_label = "Metadata"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
rd = context.scene.render
- layout.prop(rd, "use_stamp")
- col = layout.column()
- col.active = rd.use_stamp
- row = col.row()
- row.prop(rd, "stamp_font_size", text="Font Size")
- row.prop(rd, "use_stamp_labels", text="Draw Labels")
-
- row = col.row()
- row.column().prop(rd, "stamp_foreground", slider=True)
- row.column().prop(rd, "stamp_background", slider=True)
-
- layout.label("Enabled Metadata")
split = layout.split()
- col = split.column()
+ col = split.column(align=True)
col.prop(rd, "use_stamp_time", text="Time")
col.prop(rd, "use_stamp_date", text="Date")
col.prop(rd, "use_stamp_render_time", text="RenderTime")
@@ -365,7 +220,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
col.prop(rd, "use_stamp_scene", text="Scene")
col.prop(rd, "use_stamp_memory", text="Memory")
- col = split.column()
+ col = split.column(align=True)
col.prop(rd, "use_stamp_camera", text="Camera")
col.prop(rd, "use_stamp_lens", text="Lens")
col.prop(rd, "use_stamp_filename", text="Filename")
@@ -373,22 +228,50 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
col.prop(rd, "use_stamp_marker", text="Marker")
col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip")
- row = layout.split(percentage=0.2)
+ if rd.use_sequencer:
+ col.prop(rd, "use_stamp_strip_meta", text="Sequence Strip")
+
+ row = layout.split(percentage=0.3)
row.prop(rd, "use_stamp_note", text="Note")
sub = row.row()
sub.active = rd.use_stamp_note
sub.prop(rd, "stamp_note_text", text="")
- if rd.use_sequencer:
- layout.label("Sequencer:")
- layout.prop(rd, "use_stamp_strip_meta")
+
+
+class RENDER_PT_stamp_burn(RenderButtonsPanel, Panel):
+ bl_label = "Burn Into Image"
+ bl_parent_id = "RENDER_PT_stamp"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header(self, context):
+ rd = context.scene.render
+
+ self.layout.prop(rd, "use_stamp", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.active = rd.use_stamp
+ col.prop(rd, "stamp_font_size", text="Font Size")
+ col.prop(rd, "use_stamp_labels", text="Draw Labels")
+ col.column().prop(rd, "stamp_foreground", slider=True)
+ col.column().prop(rd, "stamp_background", slider=True)
class RENDER_PT_output(RenderButtonsPanel, Panel):
bl_label = "Output"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = False
+ layout.use_property_decorate = False # No animation.
rd = context.scene.render
image_settings = rd.image_settings
@@ -396,17 +279,17 @@ class RENDER_PT_output(RenderButtonsPanel, Panel):
layout.prop(rd, "filepath", text="")
- split = layout.split()
+ layout.use_property_split = True
- col = split.column()
- col.active = not rd.is_movie_format
- col.prop(rd, "use_overwrite")
- col.prop(rd, "use_placeholder")
-
- col = split.column()
+ col = layout.column(align=True)
+ sub = col.column(align=True)
+ sub.active = not rd.is_movie_format
+ sub.prop(rd, "use_overwrite")
+ sub.prop(rd, "use_placeholder")
col.prop(rd, "use_file_extension")
col.prop(rd, "use_render_cache")
+ layout.use_property_split = False
layout.template_image_settings(image_settings, color_management=False)
if rd.use_multiview:
layout.template_image_views(image_settings)
@@ -415,7 +298,10 @@ class RENDER_PT_output(RenderButtonsPanel, Panel):
class RENDER_PT_encoding(RenderButtonsPanel, Panel):
bl_label = "Encoding"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header_preset(self, context):
+ RENDER_PT_ffmpeg_presets.draw_panel_header(self.layout)
@classmethod
def poll(cls, context):
@@ -428,8 +314,6 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel):
rd = context.scene.render
ffmpeg = rd.ffmpeg
- layout.menu("RENDER_MT_ffmpeg_presets", text="Presets")
-
split = layout.split()
split.prop(rd.ffmpeg, "format")
split.prop(ffmpeg, "use_autosplit")
@@ -494,92 +378,452 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel):
col.prop(ffmpeg, "packetsize", text="Packet Size")
-class RENDER_PT_bake(RenderButtonsPanel, Panel):
- bl_label = "Bake"
+class RENDER_UL_renderviews(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ view = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if view.name in {"left", "right"}:
+ layout.label(view.name, icon_value=icon + (not view.use))
+ else:
+ layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False)
+ layout.prop(view, "use", text="", index=index)
+
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label("", icon_value=icon + (not view.use))
+
+
+class RENDER_PT_stereoscopy(RenderButtonsPanel, Panel):
+ bl_label = "Stereoscopy"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "use_multiview", text="")
def draw(self, context):
layout = self.layout
- rd = context.scene.render
+ scene = context.scene
+ rd = scene.render
+ rv = rd.views.active
- layout.operator("object.bake_image", icon='RENDER_STILL')
+ layout.active = rd.use_multiview
+ basic_stereo = rd.views_format == 'STEREO_3D'
- layout.prop(rd, "bake_type")
+ row = layout.row()
+ row.prop(rd, "views_format", expand=True)
- multires_bake = False
- if rd.bake_type in ['NORMALS', 'DISPLACEMENT', 'DERIVATIVE', 'AO']:
- layout.prop(rd, "use_bake_multires")
- multires_bake = rd.use_bake_multires
+ if basic_stereo:
+ row = layout.row()
+ row.template_list("RENDER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
- if not multires_bake:
- if rd.bake_type == 'NORMALS':
- layout.prop(rd, "bake_normal_space")
- elif rd.bake_type in {'DISPLACEMENT', 'AO'}:
- layout.prop(rd, "use_bake_normalize")
+ row = layout.row()
+ row.label(text="File Suffix:")
+ row.prop(rv, "file_suffix", text="")
- # col.prop(rd, "bake_aa_mode")
- # col.prop(rd, "use_bake_antialiasing")
+ else:
+ row = layout.row()
+ row.template_list("RENDER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
- layout.separator()
+ col = row.column(align=True)
+ col.operator("scene.render_view_add", icon='ZOOMIN', text="")
+ col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
- split = layout.split()
+ row = layout.row()
+ row.label(text="Camera Suffix:")
+ row.prop(rv, "camera_suffix", text="")
- col = split.column()
- col.prop(rd, "use_bake_to_vertex_color")
- sub = col.column()
- sub.active = not rd.use_bake_to_vertex_color
- sub.prop(rd, "use_bake_clear")
- sub.prop(rd, "bake_margin")
- sub.prop(rd, "bake_quad_split", text="Split")
- col = split.column()
- col.prop(rd, "use_bake_selected_to_active")
- sub = col.column()
- sub.active = rd.use_bake_selected_to_active
- sub.prop(rd, "bake_distance")
- sub.prop(rd, "bake_bias")
+class RENDER_PT_eevee_ambient_occlusion(RenderButtonsPanel, Panel):
+ bl_label = "Ambient Occlusion"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_gtao", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_gtao
+ col = layout.column()
+ col.prop(props, "use_gtao_bent_normals")
+ col.prop(props, "use_gtao_bounce")
+ col.prop(props, "gtao_distance")
+ col.prop(props, "gtao_factor")
+ col.prop(props, "gtao_quality")
+
+
+class RENDER_PT_eevee_motion_blur(RenderButtonsPanel, Panel):
+ bl_label = "Motion Blur"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_motion_blur", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_motion_blur
+ col = layout.column()
+ col.prop(props, "motion_blur_samples")
+ col.prop(props, "motion_blur_shutter")
+
+
+class RENDER_PT_eevee_depth_of_field(RenderButtonsPanel, Panel):
+ bl_label = "Depth of Field"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_dof", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_dof
+ col = layout.column()
+ col.prop(props, "bokeh_max_size")
+ col.prop(props, "bokeh_threshold")
+
+
+class RENDER_PT_eevee_bloom(RenderButtonsPanel, Panel):
+ bl_label = "Bloom"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_bloom", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_bloom
+ col = layout.column()
+ col.prop(props, "bloom_threshold")
+ col.prop(props, "bloom_knee")
+ col.prop(props, "bloom_radius")
+ col.prop(props, "bloom_color")
+ col.prop(props, "bloom_intensity")
+ col.prop(props, "bloom_clamp")
+
+
+class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel):
+ bl_label = "Volumetric"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_volumetric", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_volumetric
+ col = layout.column()
+ sub = col.column(align=True)
+ sub.prop(props, "volumetric_start")
+ sub.prop(props, "volumetric_end")
+ col.prop(props, "volumetric_tile_size")
+ col.separator()
+ col.prop(props, "volumetric_samples")
+ sub.prop(props, "volumetric_sample_distribution")
+ col.separator()
+ col.prop(props, "use_volumetric_lights")
+
+ sub = col.column()
+ sub.active = props.use_volumetric_lights
+ sub.prop(props, "volumetric_light_clamp", text="Light Clamping")
+ col.separator()
+ col.prop(props, "use_volumetric_shadows")
+ sub = col.column()
+ sub.active = props.use_volumetric_shadows
+ sub.prop(props, "volumetric_shadow_samples", text="Shadow Samples")
+ col.separator()
+ col.prop(props, "use_volumetric_colored_transmittance")
+
+
+class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel):
+ bl_label = "Subsurface Scattering"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_sss", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ props = scene.eevee
+
+ layout.active = props.use_sss
+
+ col = layout.column()
+ col.prop(props, "sss_samples")
+ col.prop(props, "sss_jitter_threshold")
+ col.prop(props, "use_sss_separate_albedo")
+
+
+class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):
+ bl_label = "Screen Space Reflections"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw_header(self, context):
+ scene = context.scene
+ props = scene.eevee
+ self.layout.prop(props, "use_ssr", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ props = scene.eevee
+
+ col = layout.column()
+ col.active = props.use_ssr
+ col.prop(props, "use_ssr_refraction", text="Refraction")
+ col.prop(props, "use_ssr_halfres")
+ col.prop(props, "ssr_quality")
+ col.prop(props, "ssr_max_roughness")
+ col.prop(props, "ssr_thickness")
+ col.prop(props, "ssr_border_fade")
+ col.prop(props, "ssr_firefly_fac")
+
+
+class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel):
+ bl_label = "Shadows"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ props = scene.eevee
+
+ col = layout.column()
+ col.prop(props, "shadow_method")
+ col.prop(props, "shadow_cube_size", text="Cube Size")
+ col.prop(props, "shadow_cascade_size", text="Cascade Size")
+ col.prop(props, "use_shadow_high_bitdepth")
+
+
+class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel):
+ bl_label = "Sampling"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ scene = context.scene
+ props = scene.eevee
+
+ col = layout.column()
+ col.prop(props, "taa_samples")
+ col.prop(props, "taa_render_samples")
+ col.prop(props, "use_taa_reprojection")
+
+
+class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel):
+ bl_label = "Indirect Lighting"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ scene = context.scene
+ props = scene.eevee
+
+ col = layout.column()
+ col.operator("scene.light_cache_bake", text="Bake Indirect Lighting", icon='RENDER_STILL')
+ col.operator("scene.light_cache_bake", text="Bake Cubemap Only", icon='LIGHTPROBE_CUBEMAP').subset = "CUBEMAPS"
+ col.operator("scene.light_cache_free", text="Free Lighting Cache")
+
+ cache_info = scene.eevee.gi_cache_info
+ if cache_info:
+ col.label(text=cache_info)
+
+ col.prop(props, "gi_auto_bake")
+
+ col.prop(props, "gi_diffuse_bounces")
+ col.prop(props, "gi_cubemap_resolution")
+ col.prop(props, "gi_visibility_resolution", text="Diffuse Occlusion")
+
+ layout.use_property_split = False
+ row = layout.split(percentage=0.5)
+ row.alignment = 'RIGHT'
+ row.label("Cubemap Display")
+
+ sub = row.row(align=True)
+ sub.prop(props, "gi_cubemap_draw_size", text="Size")
+ if props.gi_show_cubemaps:
+ sub.prop(props, "gi_show_cubemaps", text="", toggle=True, icon='HIDE_OFF')
else:
- split = layout.split()
+ sub.prop(props, "gi_show_cubemaps", text="", toggle=True, icon='HIDE_ON')
- col = split.column()
- col.prop(rd, "use_bake_clear")
- col.prop(rd, "bake_margin")
+ row = layout.split(percentage=0.5)
+ row.alignment = 'RIGHT'
+ row.label("Irradiance Display")
- if rd.bake_type == 'DISPLACEMENT':
- col = split.column()
- col.prop(rd, "use_bake_lores_mesh")
+ sub = row.row(align=True)
+ sub.prop(props, "gi_irradiance_draw_size", text="Size")
+ if props.gi_show_irradiance:
+ sub.prop(props, "gi_show_irradiance", text="", toggle=True, icon='HIDE_OFF')
+ else:
+ sub.prop(props, "gi_show_irradiance", text="", toggle=True, icon='HIDE_ON')
- if rd.bake_type == 'AO':
- col = split.column()
- col.prop(rd, "bake_bias")
- col.prop(rd, "bake_samples")
- if rd.bake_type == 'DERIVATIVE':
- row = layout.row()
- row.prop(rd, "use_bake_user_scale", text="")
+class RENDER_PT_eevee_film(RenderButtonsPanel, Panel):
+ bl_label = "Film"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
- sub = row.column()
- sub.active = rd.use_bake_user_scale
- sub.prop(rd, "bake_user_scale", text="User Scale")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ rd = scene.render
+
+ col = layout.column()
+ col.prop(rd, "filter_size")
+ col.prop(rd, "alpha_mode", text="Alpha")
+
+
+class RENDER_PT_hair(RenderButtonsPanel, Panel):
+ bl_label = "Hair"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ scene = context.scene
+ rd = scene.render
+
+ row = layout.row()
+ row.prop(rd, "hair_type", expand=True)
+
+ layout.use_property_split = True
+ layout.prop(rd, "hair_subdiv")
classes = (
- RENDER_MT_presets,
- RENDER_MT_ffmpeg_presets,
+ RENDER_PT_presets,
+ RENDER_PT_ffmpeg_presets,
RENDER_MT_framerate_presets,
- RENDER_PT_render,
+ RENDER_PT_context,
RENDER_PT_dimensions,
- RENDER_PT_antialiasing,
- RENDER_PT_motion_blur,
- RENDER_PT_shading,
- RENDER_PT_performance,
+ RENDER_PT_frame_remapping,
RENDER_PT_post_processing,
- RENDER_PT_stamp,
RENDER_PT_output,
RENDER_PT_encoding,
- RENDER_PT_bake,
+ RENDER_PT_stamp,
+ RENDER_PT_stamp_burn,
+ RENDER_UL_renderviews,
+ RENDER_PT_stereoscopy,
+ RENDER_PT_hair,
+ RENDER_PT_eevee_sampling,
+ RENDER_PT_eevee_film,
+ RENDER_PT_eevee_shadows,
+ RENDER_PT_eevee_indirect_lighting,
+ RENDER_PT_eevee_subsurface_scattering,
+ RENDER_PT_eevee_screen_space_reflections,
+ RENDER_PT_eevee_ambient_occlusion,
+ RENDER_PT_eevee_volumetric,
+ RENDER_PT_eevee_motion_blur,
+ RENDER_PT_eevee_depth_of_field,
+ RENDER_PT_eevee_bloom,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py
deleted file mode 100644
index 084bc387822..00000000000
--- a/release/scripts/startup/bl_ui/properties_render_layer.py
+++ /dev/null
@@ -1,242 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-import bpy
-from bpy.types import Panel, UIList
-
-
-class RenderLayerButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "render_layer"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- return scene and (scene.render.engine in cls.COMPAT_ENGINES)
-
-
-class RENDERLAYER_UL_renderlayers(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.SceneRenderLayer)
- layer = item
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- layout.prop(layer, "name", text="", icon_value=icon, emboss=False)
- layout.prop(layer, "use", text="", index=index)
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label("", icon_value=icon)
-
-
-class RENDERLAYER_PT_layers(RenderLayerButtonsPanel, Panel):
- bl_label = "Layer List"
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- rd = scene.render
-
- if rd.engine == 'BLENDER_GAME':
- layout.label("Not available in the Game Engine")
- return
-
- row = layout.row()
- col = row.column()
- col.template_list("RENDERLAYER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2)
-
- col = row.column()
- sub = col.column(align=True)
- sub.operator("scene.render_layer_add", icon='ZOOMIN', text="")
- sub.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
- col.prop(rd, "use_single_layer", icon_only=True)
-
-
-class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel):
- bl_label = "Layer"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- rd = scene.render
- rl = rd.layers.active
-
- split = layout.split()
-
- col = split.column()
- col.prop(scene, "layers", text="Scene")
- col.label(text="")
- col.prop(rl, "light_override", text="Lights")
- col.prop(rl, "material_override", text="Material")
-
- col = split.column()
- col.prop(rl, "layers", text="Layer")
- col.prop(rl, "layers_zmask", text="Mask Layer")
-
- layout.separator()
- layout.label(text="Include:")
-
- split = layout.split()
-
- col = split.column()
- col.prop(rl, "use_zmask")
- row = col.row()
- row.prop(rl, "invert_zmask", text="Negate")
- row.active = rl.use_zmask
- col.prop(rl, "use_all_z")
-
- col = split.column()
- col.prop(rl, "use_solid")
- col.prop(rl, "use_halo")
- col.prop(rl, "use_ztransp")
-
- col = split.column()
- col.prop(rl, "use_sky")
- col.prop(rl, "use_edge_enhance")
- col.prop(rl, "use_strand")
- if bpy.app.build_options.freestyle:
- row = col.row()
- row.prop(rl, "use_freestyle")
- row.active = rd.use_freestyle
-
-
-class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
- bl_label = "Passes"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @staticmethod
- def draw_pass_type_buttons(box, rl, pass_type):
- # property names
- use_pass_type = "use_pass_" + pass_type
- exclude_pass_type = "exclude_" + pass_type
- # draw pass type buttons
- row = box.row()
- row.prop(rl, use_pass_type)
- row.prop(rl, exclude_pass_type, text="")
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- rd = scene.render
- rl = rd.layers.active
-
- split = layout.split()
-
- col = split.column()
- col.prop(rl, "use_pass_combined")
- col.prop(rl, "use_pass_z")
- col.prop(rl, "use_pass_vector")
- col.prop(rl, "use_pass_normal")
- col.prop(rl, "use_pass_uv")
- col.prop(rl, "use_pass_mist")
- col.prop(rl, "use_pass_object_index")
- col.prop(rl, "use_pass_material_index")
- col.prop(rl, "use_pass_color")
-
- col = split.column()
- col.prop(rl, "use_pass_diffuse")
- self.draw_pass_type_buttons(col, rl, "specular")
- self.draw_pass_type_buttons(col, rl, "shadow")
- self.draw_pass_type_buttons(col, rl, "emit")
- self.draw_pass_type_buttons(col, rl, "ambient_occlusion")
- self.draw_pass_type_buttons(col, rl, "environment")
- self.draw_pass_type_buttons(col, rl, "indirect")
- self.draw_pass_type_buttons(col, rl, "reflection")
- self.draw_pass_type_buttons(col, rl, "refraction")
-
-
-class RENDERLAYER_UL_renderviews(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.SceneRenderView)
- view = item
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- if view.name in {'left', 'right'}:
- layout.label(view.name, icon_value=icon + (not view.use))
- else:
- layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False)
- layout.prop(view, "use", text="", index=index)
-
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label("", icon_value=icon + (not view.use))
-
-
-class RENDERLAYER_PT_views(RenderLayerButtonsPanel, Panel):
- bl_label = "Views"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, context):
- rd = context.scene.render
- self.layout.prop(rd, "use_multiview", text="")
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- rd = scene.render
- rv = rd.views.active
-
- layout.active = rd.use_multiview
- basic_stereo = rd.views_format == 'STEREO_3D'
-
- row = layout.row()
- row.prop(rd, "views_format", expand=True)
-
- if basic_stereo:
- row = layout.row()
- row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
-
- row = layout.row()
- row.label(text="File Suffix:")
- row.prop(rv, "file_suffix", text="")
-
- else:
- row = layout.row()
- row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
-
- col = row.column(align=True)
- col.operator("scene.render_view_add", icon='ZOOMIN', text="")
- col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
-
- row = layout.row()
- row.label(text="Camera Suffix:")
- row.prop(rv, "camera_suffix", text="")
-
-
-classes = (
- RENDERLAYER_UL_renderlayers,
- RENDERLAYER_PT_layers,
- RENDERLAYER_PT_layer_options,
- RENDERLAYER_PT_layer_passes,
- RENDERLAYER_UL_renderviews,
- RENDERLAYER_PT_views,
-)
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 9b1f98ec1a4..d0fce0a2582 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -25,6 +25,7 @@ from bpy.types import (
)
from rna_prop_ui import PropertyPanel
+from bl_operators.presets import PresetMenu
from .properties_physics_common import (
point_cache_ui,
@@ -32,12 +33,12 @@ from .properties_physics_common import (
)
-class SCENE_MT_units_length_presets(Menu):
+class SCENE_PT_units_length_presets(PresetMenu):
"""Unit of measure for properties that use length values"""
bl_label = "Unit Presets"
preset_subdir = "units_length"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "scene.units_length_preset_add"
class SCENE_UL_keying_set_paths(UIList):
@@ -60,56 +61,47 @@ class SceneButtonsPanel:
@classmethod
def poll(cls, context):
- rd = context.scene.render
- return context.scene and (rd.engine in cls.COMPAT_ENGINES)
+ return (context.engine in cls.COMPAT_ENGINES)
class SCENE_PT_scene(SceneButtonsPanel, Panel):
bl_label = "Scene"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
-
+ layout.use_property_split = True
scene = context.scene
layout.prop(scene, "camera")
- layout.prop(scene, "background_set", text="Background")
- if context.scene.render.engine != 'BLENDER_GAME':
- layout.prop(scene, "active_clip", text="Active Clip")
+ layout.prop(scene, "background_set")
+ layout.prop(scene, "active_clip")
class SCENE_PT_unit(SceneButtonsPanel, Panel):
bl_label = "Units"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header_preset(self, context):
+ SCENE_PT_units_length_presets.draw_panel_header(self.layout)
def draw(self, context):
layout = self.layout
unit = context.scene.unit_settings
- row = layout.row(align=True)
- row.menu("SCENE_MT_units_length_presets", text=SCENE_MT_units_length_presets.bl_label)
- row.operator("scene.units_length_preset_add", text="", icon='ZOOMIN')
- row.operator("scene.units_length_preset_add", text="", icon='ZOOMOUT').remove_active = True
+ layout.use_property_split = True
- layout.separator()
+ col = layout.column()
+ col.prop(unit, "system")
- split = layout.split(percentage=0.35)
- split.label("Length:")
- split.prop(unit, "system", text="")
- split = layout.split(percentage=0.35)
- split.label("Angle:")
- split.prop(unit, "system_rotation", text="")
+ col = layout.column()
+ col.prop(unit, "system_rotation")
col = layout.column()
col.enabled = unit.system != 'NONE'
- split = col.split(percentage=0.35)
- split.label("Unit Scale:")
- split.prop(unit, "scale_length", text="")
- split = col.split(percentage=0.35)
- split.row()
- split.prop(unit, "use_separate")
+ col.prop(unit, "scale_length")
+ col.prop(unit, "use_separate")
class SceneKeyingSetsPanel:
@@ -167,7 +159,8 @@ class SceneKeyingSetsPanel:
class SCENE_PT_keying_sets(SceneButtonsPanel, SceneKeyingSetsPanel, Panel):
bl_label = "Keying Sets"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -200,7 +193,8 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, SceneKeyingSetsPanel, Panel):
class SCENE_PT_keying_set_paths(SceneButtonsPanel, SceneKeyingSetsPanel, Panel):
bl_label = "Active Keying Set"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ bl_parent_id = "SCENE_PT_keying_sets"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -257,84 +251,115 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel, SceneKeyingSetsPanel, Panel):
class SCENE_PT_color_management(SceneButtonsPanel, Panel):
bl_label = "Color Management"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
scene = context.scene
+ view = scene.view_settings
col = layout.column()
- col.label(text="Display:")
col.prop(scene.display_settings, "display_device")
- col = layout.column()
col.separator()
- col.label(text="Render:")
- col.template_colormanaged_view_settings(scene, "view_settings")
col = layout.column()
+ col.prop(view, "view_transform")
+ col.prop(view, "exposure")
+ col.prop(view, "gamma")
+ col.prop(view, "look")
+
col.separator()
- col.label(text="Sequencer:")
- col.prop(scene.sequencer_colorspace_settings, "name")
+
+ col.prop(scene.sequencer_colorspace_settings, "name", text="Sequencer")
+
+
+class SCENE_PT_color_management_curves(SceneButtonsPanel, Panel):
+ bl_label = "Use Curves"
+ bl_parent_id = "SCENE_PT_color_management"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw_header(self, context):
+
+ scene = context.scene
+ view = scene.view_settings
+
+ self.layout.prop(view, "use_curve_mapping", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ view = scene.view_settings
+
+ layout.use_property_split = False
+ layout.enabled = view.use_curve_mapping
+
+ layout.template_curve_mapping(view, "curve_mapping", levels=True)
class SCENE_PT_audio(SceneButtonsPanel, Panel):
bl_label = "Audio"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
scene = context.scene
rd = context.scene.render
ffmpeg = rd.ffmpeg
layout.prop(scene, "audio_volume")
- layout.operator("sound.bake_animation")
- split = layout.split()
+ col = layout.column()
+ col.prop(scene, "audio_distance_model")
+
+ col.prop(ffmpeg, "audio_channels")
+ col.prop(ffmpeg, "audio_mixrate", text="Sample Rate")
- col = split.column()
- col.label("Distance Model:")
- col.prop(scene, "audio_distance_model", text="")
- sub = col.column(align=True)
- sub.prop(scene, "audio_doppler_speed", text="Speed")
- sub.prop(scene, "audio_doppler_factor", text="Doppler")
+ layout.separator()
+
+ col = layout.column(align=True)
+ col.prop(scene, "audio_doppler_speed", text="Doppler Speed")
+ col.prop(scene, "audio_doppler_factor", text="Doppler Factor")
+
+ layout.separator()
- col = split.column()
- col.label("Format:")
- col.prop(ffmpeg, "audio_channels", text="")
- col.prop(ffmpeg, "audio_mixrate", text="Rate")
+ layout.operator("sound.bake_animation")
class SCENE_PT_physics(SceneButtonsPanel, Panel):
bl_label = "Gravity"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
self.layout.prop(context.scene, "use_gravity", text="")
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
scene = context.scene
layout.active = scene.use_gravity
- layout.prop(scene, "gravity", text="")
+ layout.prop(scene, "gravity")
class SCENE_PT_rigid_body_world(SceneButtonsPanel, Panel):
bl_label = "Rigid Body World"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- scene = context.scene
- rd = scene.render
- return scene and (rd.engine in cls.COMPAT_ENGINES)
+ return (context.engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
scene = context.scene
@@ -344,6 +369,7 @@ class SCENE_PT_rigid_body_world(SceneButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
scene = context.scene
@@ -361,27 +387,25 @@ class SCENE_PT_rigid_body_world(SceneButtonsPanel, Panel):
col.prop(rbw, "group")
col.prop(rbw, "constraints")
- split = col.split()
-
- col = split.column()
+ col = col.column()
col.prop(rbw, "time_scale", text="Speed")
col.prop(rbw, "use_split_impulse")
- col = split.column()
+ col = col.column()
col.prop(rbw, "steps_per_second", text="Steps Per Second")
col.prop(rbw, "solver_iterations", text="Solver Iterations")
class SCENE_PT_rigid_body_cache(SceneButtonsPanel, Panel):
- bl_label = "Rigid Body Cache"
+ bl_label = "Cache"
+ bl_parent_id = "SCENE_PT_rigid_body_world"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- rd = context.scene.render
scene = context.scene
- return scene and scene.rigidbody_world and (rd.engine in cls.COMPAT_ENGINES)
+ return scene and scene.rigidbody_world and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
scene = context.scene
@@ -391,15 +415,15 @@ class SCENE_PT_rigid_body_cache(SceneButtonsPanel, Panel):
class SCENE_PT_rigid_body_field_weights(SceneButtonsPanel, Panel):
- bl_label = "Rigid Body Field Weights"
+ bl_label = "Field Weights"
+ bl_parent_id = "SCENE_PT_rigid_body_world"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- rd = context.scene.render
scene = context.scene
- return scene and scene.rigidbody_world and (rd.engine in cls.COMPAT_ENGINES)
+ return scene and scene.rigidbody_world and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
scene = context.scene
@@ -410,7 +434,8 @@ class SCENE_PT_rigid_body_field_weights(SceneButtonsPanel, Panel):
class SCENE_PT_simplify(SceneButtonsPanel, Panel):
bl_label = "Simplify"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw_header(self, context):
rd = context.scene.render
@@ -419,46 +444,66 @@ class SCENE_PT_simplify(SceneButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+
+class SCENE_PT_simplify_viewport(SceneButtonsPanel, Panel):
+ bl_label = "Viewport"
+ bl_parent_id = "SCENE_PT_simplify"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
rd = context.scene.render
layout.active = rd.use_simplify
- split = layout.split()
+ col = layout.column()
+ col.prop(rd, "simplify_subdivision", text="Max Subdivision")
+ col.prop(rd, "simplify_child_particles", text="Max Child Particles")
+
+
+class SCENE_PT_simplify_render(SceneButtonsPanel, Panel):
+ bl_label = "Render"
+ bl_parent_id = "SCENE_PT_simplify"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- col = split.column()
- col.label(text="Viewport:")
- col.prop(rd, "simplify_subdivision", text="Subdivision")
- col.prop(rd, "simplify_child_particles", text="Child Particles")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ rd = context.scene.render
- col = split.column()
- col.label(text="Render:")
- col.prop(rd, "simplify_subdivision_render", text="Subdivision")
- col.prop(rd, "simplify_child_particles_render", text="Child Particles")
- col.prop(rd, "simplify_shadow_samples", text="Shadow Samples")
- col.prop(rd, "simplify_ao_sss", text="AO and SSS")
- col.prop(rd, "use_simplify_triangulate")
+ layout.active = rd.use_simplify
+
+ col = layout.column()
+ col.prop(rd, "simplify_subdivision_render", text="Max Subdivision")
+ col.prop(rd, "simplify_child_particles_render", text="Max Child Particles")
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "scene"
_property_type = bpy.types.Scene
classes = (
- SCENE_MT_units_length_presets,
+ SCENE_PT_units_length_presets,
SCENE_UL_keying_set_paths,
SCENE_PT_scene,
SCENE_PT_unit,
SCENE_PT_keying_sets,
SCENE_PT_keying_set_paths,
SCENE_PT_color_management,
+ SCENE_PT_color_management_curves,
SCENE_PT_audio,
SCENE_PT_physics,
SCENE_PT_rigid_body_world,
SCENE_PT_rigid_body_cache,
SCENE_PT_rigid_body_field_weights,
SCENE_PT_simplify,
+ SCENE_PT_simplify_viewport,
+ SCENE_PT_simplify_render,
SCENE_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 018f3df6f0d..b08b47fbe77 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -23,12 +23,9 @@ from bpy.types import Menu, Panel, UIList
from bpy.types import (
Brush,
FreestyleLineStyle,
- Lamp,
- Material,
Object,
ParticleSettings,
Texture,
- World,
)
from rna_prop_ui import PropertyPanel
@@ -38,7 +35,7 @@ from .properties_paint_common import brush_texture_settings
class TEXTURE_MT_specials(Menu):
bl_label = "Texture Specials"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -47,22 +44,9 @@ class TEXTURE_MT_specials(Menu):
layout.operator("texture.slot_paste", icon='PASTEDOWN')
-class TEXTURE_MT_envmap_specials(Menu):
- bl_label = "Environment Map Specials"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("texture.envmap_save", icon='IMAGEFILE')
- layout.operator("texture.envmap_clear", icon='FILE_REFRESH')
- layout.operator("texture.envmap_clear_all", icon='FILE_REFRESH')
-
-
class TEXTURE_UL_texslots(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.MaterialTextureSlot)
ma = data
slot = item
tex = slot.texture if slot else None
@@ -71,29 +55,12 @@ class TEXTURE_UL_texslots(UIList):
layout.prop(tex, "name", text="", emboss=False, icon_value=icon)
else:
layout.label(text="", icon_value=icon)
- if tex and isinstance(item, bpy.types.MaterialTextureSlot):
- layout.prop(ma, "use_textures", text="", index=index)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
-from .properties_material import active_node_mat
-
-
def context_tex_datablock(context):
- idblock = context.material
- if idblock:
- return active_node_mat(idblock)
-
- idblock = context.lamp
- if idblock:
- return idblock
-
- idblock = context.world
- if idblock:
- return idblock
-
idblock = context.brush
if idblock:
return idblock
@@ -108,129 +75,20 @@ def context_tex_datablock(context):
return idblock
-def id_tex_datablock(bid):
- if isinstance(bid, Object):
- if bid.type == 'LAMP':
- return bid.data
- return bid.active_material
-
- return bid
-
-
class TextureButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "texture"
- @classmethod
- def poll(cls, context):
- tex = context.texture
- return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.scene.render.engine in cls.COMPAT_ENGINES)
-
-class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel):
- bl_label = ""
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
+ bl_label = "Preview"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- engine = context.scene.render.engine
- # if not (hasattr(context, "texture_slot") or hasattr(context, "texture_node")):
- # return False
- return ((context.material or
- context.world or
- context.lamp or
- context.texture or
- context.line_style or
- context.particle_system or
- isinstance(context.space_data.pin_id, ParticleSettings) or
- context.texture_user) and
- (engine in cls.COMPAT_ENGINES))
-
- def draw(self, context):
- layout = self.layout
-
- slot = getattr(context, "texture_slot", None)
- node = getattr(context, "texture_node", None)
- space = context.space_data
tex = context.texture
- idblock = context_tex_datablock(context)
- pin_id = space.pin_id
-
- space.use_limited_texture_context = True
-
- if space.use_pin_id and not isinstance(pin_id, Texture):
- idblock = id_tex_datablock(pin_id)
- pin_id = None
-
- if not space.use_pin_id:
- layout.row().prop(space, "texture_context", expand=True)
- pin_id = None
-
- if space.texture_context == 'OTHER':
- if not pin_id:
- layout.template_texture_user()
- user = context.texture_user
- if user or pin_id:
- layout.separator()
-
- row = layout.row()
-
- if pin_id:
- row.template_ID(space, "pin_id")
- else:
- propname = context.texture_user_property.identifier
- row.template_ID(user, propname, new="texture.new")
-
- if tex:
- split = layout.split(percentage=0.2)
- if tex.use_nodes:
- if slot:
- split.label(text="Output:")
- split.prop(slot, "output_node", text="")
- else:
- split.label(text="Type:")
- split.prop(tex, "type", text="")
- return
-
- tex_collection = (pin_id is None) and (node is None) and (not isinstance(idblock, Brush))
-
- if tex_collection:
- row = layout.row()
-
- row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
- idblock, "active_texture_index", rows=2)
-
- col = row.column(align=True)
- col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
- col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
- col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
-
- if tex_collection:
- layout.template_ID(idblock, "active_texture", new="texture.new")
- elif node:
- layout.template_ID(node, "texture", new="texture.new")
- elif idblock:
- layout.template_ID(idblock, "texture", new="texture.new")
-
- if pin_id:
- layout.template_ID(space, "pin_id")
-
- if tex:
- split = layout.split(percentage=0.2)
- if tex.use_nodes:
- if slot:
- split.label(text="Output:")
- split.prop(slot, "output_node", text="")
- else:
- split.label(text="Type:")
- split.prop(tex, "type", text="")
-
-
-class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
- bl_label = "Preview"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -245,58 +103,100 @@ class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
layout.template_preview(tex, slot=slot)
# Show Alpha Button for Brush Textures, see #29502
- if context.space_data.texture_context == 'BRUSH':
+ idblock = context_tex_datablock(context)
+ if isinstance(idblock, Brush):
layout.prop(tex, "use_preview_alpha")
-class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
- bl_label = "Colors"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+class TEXTURE_PT_context(TextureButtonsPanel, Panel):
+ bl_label = ""
+ bl_context = "texture"
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
tex = context.texture
+ space = context.space_data
+ pin_id = space.pin_id
+ use_pin_id = space.use_pin_id
+ user = context.texture_user
- layout.prop(tex, "use_color_ramp", text="Ramp")
- if tex.use_color_ramp:
- layout.template_color_ramp(tex, "color_ramp", expand=True)
+ if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
+ pin_id = None
- split = layout.split()
+ if not pin_id:
+ layout.template_texture_user()
- col = split.column()
- col.label(text="RGB Multiply:")
- sub = col.column(align=True)
- sub.prop(tex, "factor_red", text="R")
- sub.prop(tex, "factor_green", text="G")
- sub.prop(tex, "factor_blue", text="B")
+ if user or pin_id:
+ layout.separator()
- col = split.column()
- col.label(text="Adjust:")
- col.prop(tex, "intensity")
- col.prop(tex, "contrast")
- col.prop(tex, "saturation")
+ split = layout.split(percentage=0.65)
+ col = split.column()
- col = layout.column()
- col.prop(tex, "use_clamp", text="Clamp")
+ if pin_id:
+ col.template_ID(space, "pin_id")
+ else:
+ propname = context.texture_user_property.identifier
+ col.template_ID(user, propname, new="texture.new")
-# Texture Slot Panels #
+ if tex:
+ split = layout.split(percentage=0.2)
+ split.label(text="Type:")
+ split.prop(tex, "type", text="")
-class TextureSlotPanel(TextureButtonsPanel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+class TEXTURE_PT_node(TextureButtonsPanel, Panel):
+ bl_label = "Node"
+ bl_context = "texture"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- if not hasattr(context, "texture_slot"):
- return False
+ node = context.texture_node
+ return node and (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ node = context.texture_node
+ ntree = node.id_data
+ layout.template_node_view(ntree, node, None)
+
+
+class TEXTURE_PT_node_mapping(TextureButtonsPanel, Panel):
+ bl_label = "Mapping"
+ bl_context = "texture"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- engine = context.scene.render.engine
- return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES)
+ @classmethod
+ def poll(cls, context):
+ node = context.texture_node
+ # TODO(sergey): perform a faster/nicer check?
+ return node and hasattr(node, 'texture_mapping') and (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ node = context.texture_node
-# Texture Type Panels #
+ mapping = node.texture_mapping
+
+ layout.prop(mapping, "vector_type", expand=True)
+
+ row = layout.row()
+
+ row.column().prop(mapping, "translation")
+ row.column().prop(mapping, "rotation")
+ row.column().prop(mapping, "scale")
+
+ layout.label(text="Projection:")
+
+ row = layout.row()
+ row.prop(mapping, "mapping_x", text="")
+ row.prop(mapping, "mapping_y", text="")
+ row.prop(mapping, "mapping_z", text="")
class TextureTypePanel(TextureButtonsPanel):
@@ -304,14 +204,14 @@ class TextureTypePanel(TextureButtonsPanel):
@classmethod
def poll(cls, context):
tex = context.texture
- engine = context.scene.render.engine
+ engine = context.engine
return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
class TEXTURE_PT_clouds(TextureTypePanel, Panel):
bl_label = "Clouds"
tex_type = 'CLOUDS'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -335,7 +235,7 @@ class TEXTURE_PT_clouds(TextureTypePanel, Panel):
class TEXTURE_PT_wood(TextureTypePanel, Panel):
bl_label = "Wood"
tex_type = 'WOOD'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -364,7 +264,7 @@ class TEXTURE_PT_wood(TextureTypePanel, Panel):
class TEXTURE_PT_marble(TextureTypePanel, Panel):
bl_label = "Marble"
tex_type = 'MARBLE'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -391,7 +291,7 @@ class TEXTURE_PT_marble(TextureTypePanel, Panel):
class TEXTURE_PT_magic(TextureTypePanel, Panel):
bl_label = "Magic"
tex_type = 'MAGIC'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -406,7 +306,7 @@ class TEXTURE_PT_magic(TextureTypePanel, Panel):
class TEXTURE_PT_blend(TextureTypePanel, Panel):
bl_label = "Blend"
tex_type = 'BLEND'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -424,7 +324,7 @@ class TEXTURE_PT_blend(TextureTypePanel, Panel):
class TEXTURE_PT_stucci(TextureTypePanel, Panel):
bl_label = "Stucci"
tex_type = 'STUCCI'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -444,221 +344,137 @@ class TEXTURE_PT_stucci(TextureTypePanel, Panel):
class TEXTURE_PT_image(TextureTypePanel, Panel):
bl_label = "Image"
tex_type = 'IMAGE'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
tex = context.texture
-
layout.template_image(tex, "image", tex.image_user)
def texture_filter_common(tex, layout):
- layout.label(text="Filter:")
- layout.prop(tex, "filter_type", text="")
+ layout.prop(tex, "filter_type", text="Filter Type")
if tex.use_mipmap and tex.filter_type in {'AREA', 'EWA', 'FELINE'}:
if tex.filter_type == 'FELINE':
- layout.prop(tex, "filter_probes", text="Probes")
+ layout.prop(tex, "filter_lightprobes", text="Light Probes")
else:
layout.prop(tex, "filter_eccentricity", text="Eccentricity")
- layout.prop(tex, "filter_size")
- layout.prop(tex, "use_filter_size_min")
+ layout.prop(tex, "filter_size", text="Size")
+ layout.prop(tex, "use_filter_size_min", text="Minimum Size")
class TEXTURE_PT_image_sampling(TextureTypePanel, Panel):
- bl_label = "Image Sampling"
+ bl_label = "Sampling"
bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = 'TEXTURE_PT_image'
tex_type = 'IMAGE'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
- if context.scene.render.engine == 'BLENDER_GAME':
- self.draw_bge(context)
- else:
- self.draw_bi(context)
-
- def draw_bi(self, context):
layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
idblock = context_tex_datablock(context)
tex = context.texture
slot = getattr(context, "texture_slot", None)
- split = layout.split()
+ col = flow.column()
+ col.prop(tex, "use_flip_axis", text="Flip X/Y Axis")
+ col.prop(tex, "use_interpolation")
- col = split.column()
- col.label(text="Alpha:")
- row = col.row()
- row.active = bool(tex.image and tex.image.use_alpha)
- row.prop(tex, "use_alpha", text="Use")
- col.prop(tex, "use_calculate_alpha", text="Calculate")
- col.prop(tex, "invert_alpha", text="Invert")
col.separator()
- col.prop(tex, "use_flip_axis", text="Flip X/Y Axis")
- col = split.column()
+ col = flow.column()
+ col.prop(tex, "use_mipmap")
+ sub = col.column()
+ sub.active = tex.use_mipmap
+ sub.prop(tex, "use_mipmap_gauss", text="Gaussian Filter")
- # Only for Material based textures, not for Lamp/World...
- if slot and isinstance(idblock, Material):
- col.prop(tex, "use_normal_map")
- row = col.row()
- row.active = tex.use_normal_map
- row.prop(slot, "normal_map_space", text="")
+ col.separator()
- row = col.row()
- row.active = not tex.use_normal_map
- row.prop(tex, "use_derivative_map")
+ col = flow.column()
+ texture_filter_common(tex, col)
- col.prop(tex, "use_mipmap")
- row = col.row()
- row.active = tex.use_mipmap
- row.prop(tex, "use_mipmap_gauss")
- col.prop(tex, "use_interpolation")
- texture_filter_common(tex, col)
+class TEXTURE_PT_image_alpha(TextureTypePanel, Panel):
+ bl_label = "Alpha"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = 'TEXTURE_PT_image'
+ tex_type = 'IMAGE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- def draw_bge(self, context):
+ def draw_header(self, context):
+ tex = context.texture
+ self.layout.prop(tex, "use_alpha", text="")
+
+ def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
- idblock = context_tex_datablock(context)
tex = context.texture
- slot = getattr(context, "texture_slot", None)
- split = layout.split()
-
- col = split.column()
- col.label(text="Alpha:")
+ col = layout.column()
+ col.active = bool(tex.image and tex.image.use_alpha)
col.prop(tex, "use_calculate_alpha", text="Calculate")
col.prop(tex, "invert_alpha", text="Invert")
- col = split.column()
-
- # Only for Material based textures, not for Lamp/World...
- if slot and isinstance(idblock, Material):
- col.prop(tex, "use_normal_map")
- row = col.row()
- row.active = tex.use_normal_map
- row.prop(slot, "normal_map_space", text="")
-
- row = col.row()
- row.active = not tex.use_normal_map
- row.prop(tex, "use_derivative_map")
-
class TEXTURE_PT_image_mapping(TextureTypePanel, Panel):
- bl_label = "Image Mapping"
+ bl_label = "Mapping"
bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = 'TEXTURE_PT_image'
tex_type = 'IMAGE'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
tex = context.texture
- layout.prop(tex, "extension")
-
- split = layout.split()
+ col = flow.column()
+ col.prop(tex, "extension")
if tex.extension == 'REPEAT':
- col = split.column(align=True)
- col.label(text="Repeat:")
- col.prop(tex, "repeat_x", text="X")
- col.prop(tex, "repeat_y", text="Y")
-
- col = split.column(align=True)
- col.label(text="Mirror:")
- row = col.row(align=True)
- row.prop(tex, "use_mirror_x", text="X")
- row.active = (tex.repeat_x > 1)
- row = col.row(align=True)
- row.prop(tex, "use_mirror_y", text="Y")
- row.active = (tex.repeat_y > 1)
- layout.separator()
+ sub = col.column(align=True)
+ sub.prop(tex, "repeat_x", text="Repeat X")
+ sub.prop(tex, "repeat_y", text="Y")
- elif tex.extension == 'CHECKER':
- col = split.column(align=True)
- row = col.row(align=True)
- row.prop(tex, "use_checker_even", text="Even")
- row.prop(tex, "use_checker_odd", text="Odd")
+ sub = col.column()
+ sub.prop(tex, "use_mirror_x", text="Mirror X")
+ sub.active = (tex.repeat_x > 1)
- col = split.column()
- col.prop(tex, "checker_distance", text="Distance")
+ sub = col.column()
+ sub.prop(tex, "use_mirror_y", text="Y")
+ sub.active = (tex.repeat_y > 1)
- layout.separator()
+ elif tex.extension == 'CHECKER':
+ col = layout.column(align=True)
+ col.prop(tex, "use_checker_even", text="Even")
+ col.prop(tex, "use_checker_odd", text="Odd")
- split = layout.split()
+ col = layout.column()
+ col.prop(tex, "checker_distance", text="Distance")
- col = split.column(align=True)
+ col = flow.column()
+ sub = col.column(align=True)
# col.prop(tex, "crop_rectangle")
- col.label(text="Crop Minimum:")
- col.prop(tex, "crop_min_x", text="X")
- col.prop(tex, "crop_min_y", text="Y")
-
- col = split.column(align=True)
- col.label(text="Crop Maximum:")
- col.prop(tex, "crop_max_x", text="X")
- col.prop(tex, "crop_max_y", text="Y")
-
-
-class TEXTURE_PT_envmap(TextureTypePanel, Panel):
- bl_label = "Environment Map"
- tex_type = 'ENVIRONMENT_MAP'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
- env = tex.environment_map
-
- row = layout.row()
- row.prop(env, "source", expand=True)
- row.menu("TEXTURE_MT_envmap_specials", icon='DOWNARROW_HLT', text="")
-
- if env.source == 'IMAGE_FILE':
- layout.template_ID(tex, "image", open="image.open")
- layout.template_image(tex, "image", tex.image_user, compact=True)
- else:
- layout.prop(env, "mapping")
- if env.mapping == 'PLANE':
- layout.prop(env, "zoom")
- layout.prop(env, "viewpoint_object")
-
- split = layout.split()
+ sub.prop(tex, "crop_min_x", text="Crop Minimum X")
+ sub.prop(tex, "crop_min_y", text="Y")
- col = split.column()
- col.prop(env, "layers_ignore")
- col.prop(env, "resolution")
- col.prop(env, "depth")
-
- col = split.column(align=True)
-
- col.label(text="Clipping:")
- col.prop(env, "clip_start", text="Start")
- col.prop(env, "clip_end", text="End")
-
-
-class TEXTURE_PT_envmap_sampling(TextureTypePanel, Panel):
- bl_label = "Environment Map Sampling"
- bl_options = {'DEFAULT_CLOSED'}
- tex_type = 'ENVIRONMENT_MAP'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
-
- texture_filter_common(tex, layout)
+ sub = col.column(align=True)
+ sub.prop(tex, "crop_max_x", text="Crop Maximum X")
+ sub.prop(tex, "crop_max_y", text="Y")
class TEXTURE_PT_musgrave(TextureTypePanel, Panel):
bl_label = "Musgrave"
tex_type = 'MUSGRAVE'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -694,7 +510,7 @@ class TEXTURE_PT_musgrave(TextureTypePanel, Panel):
class TEXTURE_PT_voronoi(TextureTypePanel, Panel):
bl_label = "Voronoi"
tex_type = 'VORONOI'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -730,7 +546,7 @@ class TEXTURE_PT_voronoi(TextureTypePanel, Panel):
class TEXTURE_PT_distortednoise(TextureTypePanel, Panel):
bl_label = "Distorted Noise"
tex_type = 'DISTORTED_NOISE'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@@ -749,180 +565,20 @@ class TEXTURE_PT_distortednoise(TextureTypePanel, Panel):
split.prop(tex, "nabla")
-class TEXTURE_PT_voxeldata(TextureButtonsPanel, Panel):
- bl_label = "Voxel Data"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- tex = context.texture
- engine = context.scene.render.engine
- return tex and (tex.type == 'VOXEL_DATA' and (engine in cls.COMPAT_ENGINES))
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
- vd = tex.voxel_data
-
- layout.prop(vd, "file_format")
- if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}:
- layout.prop(vd, "filepath")
- if vd.file_format == 'RAW_8BIT':
- layout.prop(vd, "resolution")
- elif vd.file_format == 'SMOKE':
- layout.prop(vd, "domain_object")
- layout.prop(vd, "smoke_data_type")
- elif vd.file_format == 'HAIR':
- layout.prop(vd, "domain_object")
- layout.prop(vd, "hair_data_type")
- elif vd.file_format == 'IMAGE_SEQUENCE':
- layout.template_ID(tex, "image", open="image.open")
- layout.template_image(tex, "image", tex.image_user, compact=True)
- # layout.prop(vd, "frame_duration")
-
- if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}:
- layout.prop(vd, "use_still_frame")
- row = layout.row()
- row.active = vd.use_still_frame
- row.prop(vd, "still_frame")
-
- layout.prop(vd, "interpolation")
- layout.prop(vd, "extension")
- layout.prop(vd, "intensity")
-
-
-class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel):
- bl_label = "Point Density"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- tex = context.texture
- engine = context.scene.render.engine
- return tex and (tex.type == 'POINT_DENSITY' and (engine in cls.COMPAT_ENGINES))
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
- pd = tex.point_density
-
- layout.row().prop(pd, "point_source", expand=True)
-
- split = layout.split()
-
- col = split.column()
- if pd.point_source == 'PARTICLE_SYSTEM':
- col.label(text="Object:")
- col.prop(pd, "object", text="")
-
- sub = col.column()
- sub.enabled = bool(pd.object)
- if pd.object:
- sub.label(text="System:")
- sub.prop_search(pd, "particle_system", pd.object, "particle_systems", text="")
- sub.label(text="Cache:")
- sub.prop(pd, "particle_cache_space", text="")
- else:
- col.label(text="Object:")
- col.prop(pd, "object", text="")
- col.label(text="Cache:")
- col.prop(pd, "vertex_cache_space", text="")
-
- col.separator()
-
- col.label(text="Color Source:")
- if pd.point_source == 'PARTICLE_SYSTEM':
- col.prop(pd, "particle_color_source", text="")
- if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}:
- col.prop(pd, "speed_scale")
- if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}:
- layout.template_color_ramp(pd, "color_ramp", expand=True)
- else:
- col.prop(pd, "vertex_color_source", text="")
- if pd.vertex_color_source == 'VERTEX_COLOR':
- if pd.object and pd.object.data:
- col.prop_search(pd, "vertex_attribute_name", pd.object.data, "vertex_colors", text="")
- if pd.vertex_color_source == 'VERTEX_WEIGHT':
- if pd.object:
- col.prop_search(pd, "vertex_attribute_name", pd.object, "vertex_groups", text="")
- layout.template_color_ramp(pd, "color_ramp", expand=True)
-
- col = split.column()
- col.label()
- col.prop(pd, "radius")
- col.label(text="Falloff:")
- col.prop(pd, "falloff", text="")
- if pd.falloff == 'SOFT':
- col.prop(pd, "falloff_soft")
- if pd.falloff == 'PARTICLE_VELOCITY':
- col.prop(pd, "falloff_speed_scale")
-
- col.prop(pd, "use_falloff_curve")
-
- if pd.use_falloff_curve:
- col = layout.column()
- col.label(text="Falloff Curve")
- col.template_curve_mapping(pd, "falloff_curve", brush=False)
-
-
-class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, Panel):
- bl_label = "Turbulence"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+class TextureSlotPanel(TextureButtonsPanel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- tex = context.texture
- engine = context.scene.render.engine
- return tex and (tex.type == 'POINT_DENSITY' and (engine in cls.COMPAT_ENGINES))
-
- def draw_header(self, context):
- pd = context.texture.point_density
-
- self.layout.prop(pd, "use_turbulence", text="")
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
- pd = tex.point_density
- layout.active = pd.use_turbulence
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Influence:")
- col.prop(pd, "turbulence_influence", text="")
- col.label(text="Noise Basis:")
- col.prop(pd, "noise_basis", text="")
-
- col = split.column()
- col.label()
- col.prop(pd, "turbulence_scale")
- col.prop(pd, "turbulence_depth")
- col.prop(pd, "turbulence_strength")
-
-
-class TEXTURE_PT_ocean(TextureTypePanel, Panel):
- bl_label = "Ocean"
- tex_type = 'OCEAN'
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- tex = context.texture
- ot = tex.ocean
+ if not hasattr(context, "texture_slot"):
+ return False
- col = layout.column()
- col.prop(ot, "ocean_object")
- col.prop(ot, "output")
+ return (context.engine in cls.COMPAT_ENGINES)
class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
bl_label = "Mapping"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -933,7 +589,7 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
if not getattr(context, "texture_slot", None):
return False
- engine = context.scene.render.engine
+ engine = context.engine
return (engine in cls.COMPAT_ENGINES)
def draw(self, context):
@@ -963,7 +619,7 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
split.label(text="Map:")
ob = context.object
if ob and ob.type == 'MESH':
- split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
+ split.prop_search(tex, "uv_layer", ob.data, "uv_layers", text="")
else:
split.prop(tex, "uv_layer", text="")
@@ -993,31 +649,6 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
row.prop(tex, "mapping_y", text="")
row.prop(tex, "mapping_z", text="")
- elif isinstance(idblock, Material):
- split = layout.split(percentage=0.3)
- split.label(text="Projection:")
- split.prop(tex, "mapping", text="")
-
- split = layout.split()
-
- col = split.column()
- if tex.texture_coords in {'ORCO', 'UV'}:
- col.prop(tex, "use_from_dupli")
- if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'):
- col.prop(tex, "use_map_to_bounds")
- elif tex.texture_coords == 'OBJECT':
- col.prop(tex, "use_from_original")
- if (idblock.type == 'VOLUME'):
- col.prop(tex, "use_map_to_bounds")
- else:
- col.label()
-
- col = split.column()
- row = col.row()
- row.prop(tex, "mapping_x", text="")
- row.prop(tex, "mapping_y", text="")
- row.prop(tex, "mapping_z", text="")
-
row = layout.row()
row.column().prop(tex, "offset")
row.column().prop(tex, "scale")
@@ -1025,7 +656,7 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
class TEXTURE_PT_influence(TextureSlotPanel, Panel):
bl_label = "Influence"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@@ -1036,7 +667,7 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
if not getattr(context, "texture_slot", None):
return False
- engine = context.scene.render.engine
+ engine = context.engine
return (engine in cls.COMPAT_ENGINES)
def draw(self, context):
@@ -1055,101 +686,7 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
sub.prop(tex, factor, text=name, slider=True)
return sub # XXX, temp. use_map_normal needs to override.
- if isinstance(idblock, Material):
- if idblock.type in {'SURFACE', 'WIRE'}:
- split = layout.split()
-
- col = split.column()
- col.label(text="Diffuse:")
- factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
- factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
- factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
- factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
-
- col.label(text="Specular:")
- factor_but(col, "use_map_specular", "specular_factor", "Intensity")
- factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
- factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
-
- col = split.column()
- col.label(text="Shading:")
- factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
- factor_but(col, "use_map_emit", "emit_factor", "Emit")
- factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
- factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
-
- col.label(text="Geometry:")
- # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
- sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
- sub_tmp.active = (tex.use_map_normal or tex.use_map_displacement)
- # END XXX
-
- factor_but(col, "use_map_warp", "warp_factor", "Warp")
- factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
-
- # ~ sub = col.column()
- # ~ sub.active = tex.use_map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror
- #~ sub.prop(tex, "default_value", text="Amount", slider=True)
- elif idblock.type == 'HALO':
- layout.label(text="Halo:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
- factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
-
- col = split.column()
- factor_but(col, "use_map_raymir", "raymir_factor", "Size")
- factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
- factor_but(col, "use_map_translucency", "translucency_factor", "Add")
- elif idblock.type == 'VOLUME':
- layout.label(text="Volume:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_density", "density_factor", "Density")
- factor_but(col, "use_map_emission", "emission_factor", "Emission")
- factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
- factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
-
- col = split.column()
- col.label(text=" ")
- factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
- factor_but(col, "use_map_color_transmission", "transmission_color_factor", "Transmission Color")
- factor_but(col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color")
-
- layout.label(text="Geometry:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_warp", "warp_factor", "Warp")
-
- col = split.column()
- factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
-
- elif isinstance(idblock, Lamp):
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_color", "color_factor", "Color")
-
- col = split.column()
- factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
-
- elif isinstance(idblock, World):
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_blend", "blend_factor", "Blend")
- factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
-
- col = split.column()
- factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
- factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
- elif isinstance(idblock, ParticleSettings):
+ if isinstance(idblock, ParticleSettings):
split = layout.split()
col = split.column()
@@ -1203,48 +740,59 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
col.prop(tex, "invert", text="Negative")
col.prop(tex, "use_stencil")
- if isinstance(idblock, (Material, World)):
- col.prop(tex, "default_value", text="DVar", slider=True)
- if isinstance(idblock, Material):
- layout.label(text="Bump Mapping:")
+class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
+ bl_label = "Colors"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- # only show bump settings if activated but not for normal-map images
- row = layout.row()
+ @classmethod
+ def poll(cls, context):
+ tex = context.texture
+ return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES)
- sub = row.row()
- sub.active = (
- (tex.use_map_normal or tex.use_map_warp) and
- not (tex.texture.type == 'IMAGE' and
- (tex.texture.use_normal_map or tex.texture.use_derivative_map))
- )
- sub.prop(tex, "bump_method", text="Method")
-
- # the space setting is supported for: derivative-maps + bump-maps
- # (DEFAULT,BEST_QUALITY), not for normal-maps
- sub = row.row()
- sub.active = (
- (tex.use_map_normal or tex.use_map_warp) and
- not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and
- ((tex.bump_method in {'BUMP_LOW_QUALITY', 'BUMP_MEDIUM_QUALITY', 'BUMP_BEST_QUALITY'}) or
- (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map))
- )
- sub.prop(tex, "bump_objectspace", text="Space")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ tex = context.texture
+
+ col = layout.column()
+ sub = col.column(align=True)
+ sub.prop(tex, "factor_red", text="Multiply R")
+ sub.prop(tex, "factor_green", text="G")
+ sub.prop(tex, "factor_blue", text="B")
+
+ col.prop(tex, "intensity")
+ col.prop(tex, "contrast")
+ col.prop(tex, "saturation")
+
+ col.prop(tex, "use_clamp", text="Clamp")
+ col.prop(tex, "use_color_ramp", text="Ramp")
+ if tex.use_color_ramp:
+ layout.use_property_split = False
+ layout.template_color_ramp(tex, "color_ramp", expand=True)
class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "texture"
_property_type = Texture
+ @classmethod
+ def poll(cls, context):
+ return context.texture and (context.engine in cls.COMPAT_ENGINES)
+
classes = (
TEXTURE_MT_specials,
- TEXTURE_MT_envmap_specials,
TEXTURE_UL_texslots,
- TEXTURE_PT_context_texture,
TEXTURE_PT_preview,
- TEXTURE_PT_colors,
+ TEXTURE_PT_context,
+ TEXTURE_PT_node,
+ TEXTURE_PT_node_mapping,
+ TEXTURE_PT_mapping,
+ TEXTURE_PT_influence,
TEXTURE_PT_clouds,
TEXTURE_PT_wood,
TEXTURE_PT_marble,
@@ -1252,19 +800,13 @@ classes = (
TEXTURE_PT_blend,
TEXTURE_PT_stucci,
TEXTURE_PT_image,
+ TEXTURE_PT_image_alpha,
TEXTURE_PT_image_sampling,
TEXTURE_PT_image_mapping,
- TEXTURE_PT_envmap,
- TEXTURE_PT_envmap_sampling,
TEXTURE_PT_musgrave,
TEXTURE_PT_voronoi,
TEXTURE_PT_distortednoise,
- TEXTURE_PT_voxeldata,
- TEXTURE_PT_pointdensity,
- TEXTURE_PT_pointdensity_turbulence,
- TEXTURE_PT_ocean,
- TEXTURE_PT_mapping,
- TEXTURE_PT_influence,
+ TEXTURE_PT_colors,
TEXTURE_PT_custom_props,
)
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
new file mode 100644
index 00000000000..05dc15216a2
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -0,0 +1,82 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Panel, UIList
+
+
+class ViewLayerButtonsPanel:
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "view_layer"
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+
+class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel):
+ bl_label = "View Layer"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ rd = scene.render
+ layer = bpy.context.view_layer
+
+ layout.prop(layer, "use", text="Use for Rendering")
+ layout.prop(rd, "use_single_layer", text="Render Single Layer")
+
+
+class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel):
+ bl_label = "Passes"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ rd = scene.render
+ view_layer = context.view_layer
+
+ col = layout.column()
+ col.prop(view_layer, "use_pass_combined")
+ col.prop(view_layer, "use_pass_z")
+ col.prop(view_layer, "use_pass_mist")
+ col.prop(view_layer, "use_pass_normal")
+ col.prop(view_layer, "use_pass_ambient_occlusion")
+ col.prop(view_layer, "use_pass_subsurface_direct", text="Subsurface Direct")
+ col.prop(view_layer, "use_pass_subsurface_color", text="Subsurface Color")
+
+
+classes = (
+ VIEWLAYER_PT_layer,
+ VIEWLAYER_PT_eevee_layer_passes,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py
index 107c31567b3..52a769fd223 100644
--- a/release/scripts/startup/bl_ui/properties_world.py
+++ b/release/scripts/startup/bl_ui/properties_world.py
@@ -20,6 +20,7 @@
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
+from bpy_extras.node_utils import find_node_input
class WorldButtonsPanel:
@@ -30,18 +31,17 @@ class WorldButtonsPanel:
@classmethod
def poll(cls, context):
- return (context.world and context.scene.render.engine in cls.COMPAT_ENGINES)
+ return (context.world and context.engine in cls.COMPAT_ENGINES)
class WORLD_PT_context_world(WorldButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- rd = context.scene.render
- return rd.engine in cls.COMPAT_ENGINES
+ return (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -50,215 +50,84 @@ class WORLD_PT_context_world(WorldButtonsPanel, Panel):
world = context.world
space = context.space_data
- texture_count = world and len(world.texture_slots.keys())
-
split = layout.split(percentage=0.85)
if scene:
split.template_ID(scene, "world", new="world.new")
elif world:
split.template_ID(space, "pin_id")
- if texture_count:
- split.label(text=str(texture_count), icon='TEXTURE')
-
-class WORLD_PT_preview(WorldButtonsPanel, Panel):
- bl_label = "Preview"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+class EEVEE_WORLD_PT_mist(WorldButtonsPanel, Panel):
+ bl_label = "Mist Pass"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
- rd = context.scene.render
- return (context.world) and (rd.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- self.layout.template_preview(context.world)
+ engine = context.engine
+ if context.world and (engine in cls.COMPAT_ENGINES):
+ for view_layer in context.scene.view_layers:
+ if view_layer.use_pass_mist:
+ return True
-
-class WORLD_PT_world(WorldButtonsPanel, Panel):
- bl_label = "World"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ return False
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
world = context.world
- row = layout.row()
- row.prop(world, "use_sky_paper")
- row.prop(world, "use_sky_blend")
- row.prop(world, "use_sky_real")
-
- row = layout.row()
- row.column().prop(world, "horizon_color")
- col = row.column()
- col.prop(world, "zenith_color")
- col.active = world.use_sky_blend
- row.column().prop(world, "ambient_color")
-
- row = layout.row()
- row.prop(world, "exposure")
- row.prop(world, "color_range")
-
-
-class WORLD_PT_ambient_occlusion(WorldButtonsPanel, Panel):
- bl_label = "Ambient Occlusion"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw_header(self, context):
- light = context.world.light_settings
- self.layout.prop(light, "use_ambient_occlusion", text="")
-
- def draw(self, context):
- layout = self.layout
-
- light = context.world.light_settings
-
- layout.active = light.use_ambient_occlusion
-
- split = layout.split()
- split.prop(light, "ao_factor", text="Factor")
- split.prop(light, "ao_blend_type", text="")
-
-
-class WORLD_PT_environment_lighting(WorldButtonsPanel, Panel):
- bl_label = "Environment Lighting"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw_header(self, context):
- light = context.world.light_settings
- self.layout.prop(light, "use_environment_light", text="")
-
- def draw(self, context):
- layout = self.layout
-
- light = context.world.light_settings
-
- layout.active = light.use_environment_light
-
- split = layout.split()
- split.prop(light, "environment_energy", text="Energy")
- split.prop(light, "environment_color", text="")
-
-
-class WORLD_PT_indirect_lighting(WorldButtonsPanel, Panel):
- bl_label = "Indirect Lighting"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw_header(self, context):
- light = context.world.light_settings
- self.layout.prop(light, "use_indirect_light", text="")
-
- def draw(self, context):
- layout = self.layout
-
- light = context.world.light_settings
-
- layout.active = light.use_indirect_light and light.gather_method == 'APPROXIMATE'
-
- split = layout.split()
- split.prop(light, "indirect_factor", text="Factor")
- split.prop(light, "indirect_bounces", text="Bounces")
-
- if light.gather_method == 'RAYTRACE':
- layout.label(text="Only works with Approximate gather method")
-
-
-class WORLD_PT_gather(WorldButtonsPanel, Panel):
- bl_label = "Gather"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- light = context.world.light_settings
-
- layout.active = light.use_ambient_occlusion or light.use_environment_light or light.use_indirect_light
-
- layout.row().prop(light, "gather_method", expand=True)
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Attenuation:")
- if light.gather_method == 'RAYTRACE':
- col.prop(light, "distance")
- col.prop(light, "use_falloff")
- sub = col.row()
- sub.active = light.use_falloff
- sub.prop(light, "falloff_strength", text="Strength")
-
- if light.gather_method == 'RAYTRACE':
- col = split.column()
-
- col.label(text="Sampling:")
- col.prop(light, "sample_method", text="")
-
- sub = col.column()
- sub.prop(light, "samples")
-
- if light.sample_method == 'ADAPTIVE_QMC':
- sub.prop(light, "threshold")
- sub.prop(light, "adapt_to_speed", slider=True)
- elif light.sample_method == 'CONSTANT_JITTERED':
- sub.prop(light, "bias")
-
- if light.gather_method == 'APPROXIMATE':
- col = split.column()
+ layout.prop(world.mist_settings, "start")
+ layout.prop(world.mist_settings, "depth")
+ layout.prop(world.mist_settings, "falloff")
- col.label(text="Sampling:")
- col.prop(light, "passes")
- col.prop(light, "error_threshold", text="Error")
- col.prop(light, "use_cache")
- col.prop(light, "correction")
+class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, Panel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+ _context_path = "world"
+ _property_type = bpy.types.World
-class WORLD_PT_mist(WorldButtonsPanel, Panel):
- bl_label = "Mist"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
- def draw_header(self, context):
- world = context.world
+class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
+ bl_label = "Surface"
+ bl_context = "world"
+ COMPAT_ENGINES = {'BLENDER_EEVEE'}
- self.layout.prop(world.mist_settings, "use_mist", text="")
+ @classmethod
+ def poll(cls, context):
+ engine = context.engine
+ return context.world and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
world = context.world
- layout.active = world.mist_settings.use_mist
+ layout.prop(world, "use_nodes", icon='NODETREE')
+ layout.separator()
- split = layout.split()
+ if world.use_nodes:
+ ntree = world.node_tree
+ node = ntree.get_output_node('EEVEE')
- col = split.column()
- col.prop(world.mist_settings, "intensity")
- col.prop(world.mist_settings, "start")
-
- col = split.column()
- col.prop(world.mist_settings, "depth")
- col.prop(world.mist_settings, "height")
-
- layout.prop(world.mist_settings, "falloff")
-
-
-class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- _context_path = "world"
- _property_type = bpy.types.World
+ if node:
+ input = find_node_input(node, 'Surface')
+ if input:
+ layout.template_node_view(ntree, node, input)
+ else:
+ layout.label(text="Incompatible output node")
+ else:
+ layout.label(text="No output node")
+ else:
+ layout.prop(world, "horizon_color", text="Color")
classes = (
WORLD_PT_context_world,
- WORLD_PT_preview,
- WORLD_PT_world,
- WORLD_PT_ambient_occlusion,
- WORLD_PT_environment_lighting,
- WORLD_PT_indirect_lighting,
- WORLD_PT_gather,
- WORLD_PT_mist,
WORLD_PT_custom_props,
+ EEVEE_WORLD_PT_surface,
+ EEVEE_WORLD_PT_mist,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index f8d9ae3ef9f..23c3e97ac9a 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -21,6 +21,7 @@
import bpy
from bpy.types import Panel, Header, Menu, UIList
from bpy.app.translations import pgettext_iface as iface_
+from bl_operators.presets import PresetMenu
from .properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
@@ -57,21 +58,20 @@ class CLIP_HT_header(Header):
sc = context.space_data
clip = sc.clip
- row = layout.row(align=True)
- row.template_header()
-
CLIP_MT_tracking_editor_menus.draw_collapsible(context, layout)
+ layout.separator_spacer()
+
row = layout.row()
row.template_ID(sc, "clip", open="clip.open")
+ layout.separator_spacer()
+
if clip:
tracking = clip.tracking
active_object = tracking.objects.active
if sc.view == 'CLIP':
- layout.prop(sc, "mode", text="")
- layout.prop(sc, "view", text="", expand=True)
layout.prop(sc, "pivot_point", text="", icon_only=True)
r = active_object.reconstruction
@@ -80,8 +80,6 @@ class CLIP_HT_header(Header):
layout.label(text="Solve error: %.4f" %
(r.average_error))
elif sc.view == 'GRAPH':
- layout.prop(sc, "view", text="", expand=True)
-
row = layout.row(align=True)
row.prop(sc, "show_graph_only_selected", text="")
row.prop(sc, "show_graph_hidden", text="")
@@ -103,7 +101,6 @@ class CLIP_HT_header(Header):
text="Filters")
elif sc.view == 'DOPESHEET':
dopesheet = tracking.dopesheet
- layout.prop(sc, "view", text="", expand=True)
row = layout.row(align=True)
row.prop(dopesheet, "show_only_selected", text="")
@@ -113,8 +110,6 @@ class CLIP_HT_header(Header):
row.prop(dopesheet, "sort_method", text="")
row.prop(dopesheet, "use_invert_sort",
text="Invert", toggle=True)
- else:
- layout.prop(sc, "view", text="", expand=True)
def _draw_masking(self, context):
layout = self.layout
@@ -123,35 +118,40 @@ class CLIP_HT_header(Header):
sc = context.space_data
clip = sc.clip
- row = layout.row(align=True)
- row.template_header()
-
CLIP_MT_masking_editor_menus.draw_collapsible(context, layout)
+ layout.separator_spacer()
+
row = layout.row()
row.template_ID(sc, "clip", open="clip.open")
- if clip:
- layout.prop(sc, "mode", text="")
+ layout.separator_spacer()
+ if clip:
row = layout.row()
row.template_ID(sc, "mask", new="mask.new")
+ layout.separator_spacer()
+
layout.prop(sc, "pivot_point", text="", icon_only=True)
row = layout.row(align=True)
- row.prop(toolsettings, "use_proportional_edit_mask",
- text="", icon_only=True)
- if toolsettings.use_proportional_edit_mask:
- row.prop(toolsettings, "proportional_edit_falloff",
- text="", icon_only=True)
+ row.prop(toolsettings, "use_proportional_edit_mask", text="", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = toolsettings.use_proportional_edit_mask
+ sub.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True)
def draw(self, context):
layout = self.layout
sc = context.space_data
+ row = layout.row(align=True)
+ row.template_header()
+
+ layout.prop(sc, "mode", text="")
if sc.mode == 'TRACKING':
+ layout.prop(sc, "view", text="")
self._draw_tracking(context)
else:
self._draw_masking(context)
@@ -284,6 +284,9 @@ class CLIP_PT_tracking_settings(CLIP_PT_tracking_panel, Panel):
bl_label = "Tracking Settings"
bl_category = "Track"
+ def draw_header_preset(self, context):
+ CLIP_PT_tracking_settings_presets.draw_panel_header(self.layout)
+
def draw(self, context):
sc = context.space_data
@@ -293,14 +296,6 @@ class CLIP_PT_tracking_settings(CLIP_PT_tracking_panel, Panel):
col = layout.column()
row = col.row(align=True)
- label = CLIP_MT_tracking_settings_presets.bl_label
- row.menu('CLIP_MT_tracking_settings_presets', text=label)
- row.operator("clip.tracking_settings_preset_add",
- text="", icon='ZOOMIN')
- row.operator("clip.tracking_settings_preset_add",
- text="", icon='ZOOMOUT').remove_active = True
-
- row = col.row(align=True)
row.prop(settings, "use_default_red_channel",
text="R", toggle=True)
row.prop(settings, "use_default_green_channel",
@@ -632,12 +627,8 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
layout.separator()
row = layout.row(align=True)
- label = bpy.types.CLIP_MT_track_color_presets.bl_label
- row.menu('CLIP_MT_track_color_presets', text=label)
+ CLIP_PT_track_color_presets.draw_menu(row, 'Color Presets')
row.menu('CLIP_MT_track_color_specials', text="", icon='DOWNARROW_HLT')
- row.operator("clip.track_color_preset_add", text="", icon='ZOOMIN')
- row.operator("clip.track_color_preset_add",
- text="", icon='ZOOMOUT').remove_active = True
row = layout.row()
row.prop(act_track, "use_custom_color")
@@ -727,19 +718,15 @@ class CLIP_PT_tracking_camera(Panel):
return False
+ def draw_header_preset(self, context):
+ CLIP_PT_camera_presets.draw_panel_header(self.layout)
+
def draw(self, context):
layout = self.layout
sc = context.space_data
clip = sc.clip
- row = layout.row(align=True)
- label = bpy.types.CLIP_MT_camera_presets.bl_label
- row.menu('CLIP_MT_camera_presets', text=label)
- row.operator("clip.camera_preset_add", text="", icon='ZOOMIN')
- row.operator("clip.camera_preset_add", text="",
- icon='ZOOMOUT').remove_active = True
-
col = layout.column(align=True)
col.label(text="Sensor:")
col.prop(clip.tracking.camera, "sensor_width", text="Width")
@@ -1245,9 +1232,8 @@ class CLIP_MT_view(Menu):
layout.prop(sc, "show_locked_time")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+
+ layout.menu("INFO_MT_area")
class CLIP_MT_clip(Menu):
@@ -1439,28 +1425,28 @@ class CLIP_MT_tracking_specials(Menu):
text="Unlock Tracks").action = 'UNLOCK'
-class CLIP_MT_camera_presets(Menu):
+class CLIP_PT_camera_presets(PresetMenu):
"""Predefined tracking camera intrinsics"""
bl_label = "Camera Presets"
preset_subdir = "tracking_camera"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "clip.camera_preset_add"
-class CLIP_MT_track_color_presets(Menu):
+class CLIP_PT_track_color_presets(PresetMenu):
"""Predefined track color"""
bl_label = "Color Presets"
preset_subdir = "tracking_track_color"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "clip.track_color_preset_add"
-class CLIP_MT_tracking_settings_presets(Menu):
+class CLIP_PT_tracking_settings_presets(PresetMenu):
"""Predefined tracking settings"""
bl_label = "Tracking Presets"
preset_subdir = "tracking_settings"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "clip.tracking_settings_preset_add"
class CLIP_MT_track_color_specials(Menu):
@@ -1544,9 +1530,9 @@ classes = (
CLIP_MT_select,
CLIP_MT_select_grouped,
CLIP_MT_tracking_specials,
- CLIP_MT_camera_presets,
- CLIP_MT_track_color_presets,
- CLIP_MT_tracking_settings_presets,
+ CLIP_PT_camera_presets,
+ CLIP_PT_track_color_presets,
+ CLIP_PT_tracking_settings_presets,
CLIP_MT_track_color_specials,
CLIP_MT_stabilize_2d_specials,
CLIP_MT_stabilize_2d_rotation_specials,
diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py
index e6f96d989c7..dd5ab03fcba 100644
--- a/release/scripts/startup/bl_ui/space_console.py
+++ b/release/scripts/startup/bl_ui/space_console.py
@@ -69,9 +69,7 @@ class CONSOLE_MT_console(Menu):
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class CONSOLE_MT_language(Menu):
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 731032bafa8..efd5e195fb8 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -19,11 +19,12 @@
# <pep8 compliant>
import bpy
-from bpy.types import Header, Menu
+from bpy.types import Header, Menu, Panel
+from .space_time import *
#######################################
-# DopeSheet Filtering
+# DopeSheet Filtering - Header Buttons
# used for DopeSheet, NLA, and Graph Editors
def dopesheet_filter(layout, context, genericFiltersOnly=False):
@@ -40,68 +41,153 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
row.prop(dopesheet, "show_only_errors", text="")
if not genericFiltersOnly:
- if bpy.data.groups:
+ if bpy.data.collections:
row = layout.row(align=True)
- row.prop(dopesheet, "show_only_group_objects", text="")
- if dopesheet.show_only_group_objects:
- row.prop(dopesheet, "filter_group", text="")
+ row.prop(dopesheet, "filter_collection", text="")
if not is_nla:
row = layout.row(align=True)
- row.prop(dopesheet, "show_only_matching_fcurves", text="")
- if dopesheet.show_only_matching_fcurves:
- row.prop(dopesheet, "filter_fcurve_name", text="")
- row.prop(dopesheet, "use_multi_word_filter", text="")
+ row.prop(dopesheet, "filter_fcurve_name", text="")
else:
row = layout.row(align=True)
- row.prop(dopesheet, "use_filter_text", text="")
- if dopesheet.use_filter_text:
+ row.prop(dopesheet, "filter_text", text="")
+
+#######################################
+# Dopesheet Filtering Popovers
+
+# Generic Layout - Used as base for filtering popovers used in all animation editors
+# Used for DopeSheet, NLA, and Graph Editors
+
+
+class DopesheetFilterPopoverBase:
+ bl_region_type = 'HEADER'
+ bl_label = "Filters"
+
+ # Generic = Affects all datatypes
+ # XXX: Perhaps we want these to stay in the header instead, for easy/fast access
+ @classmethod
+ def draw_generic_filters(cls, context, layout):
+ dopesheet = context.space_data.dopesheet
+ is_nla = context.area.type == 'NLA_EDITOR'
+
+ col = layout.column(align=True)
+ col.prop(dopesheet, "show_only_selected", icon='NONE')
+ col.prop(dopesheet, "show_hidden", icon='NONE')
+
+ if is_nla:
+ col.prop(dopesheet, "show_missing_nla", icon='NONE')
+ else: # graph and dopesheet editors - F-Curves and drivers only
+ col.prop(dopesheet, "show_only_errors", icon='NONE')
+
+ # Name/Membership Filters
+ # XXX: Perhaps these should just stay in the headers (exclusively)?
+ @classmethod
+ def draw_search_filters(cls, context, layout, generic_filters_only=False):
+ dopesheet = context.space_data.dopesheet
+ is_nla = context.area.type == 'NLA_EDITOR'
+
+ col = layout.column(align=True)
+ col.label("With Name:")
+ if not is_nla:
+ row = col.row(align=True)
+ row.prop(dopesheet, "filter_fcurve_name", text="")
+ else:
+ row = col.row(align=True)
row.prop(dopesheet, "filter_text", text="")
- row.prop(dopesheet, "use_multi_word_filter", text="")
- if not genericFiltersOnly:
- row = layout.row(align=True)
- row.prop(dopesheet, "show_datablock_filters", text="Filters")
-
- if dopesheet.show_datablock_filters:
- row.prop(dopesheet, "show_scenes", text="")
- row.prop(dopesheet, "show_worlds", text="")
- row.prop(dopesheet, "show_nodes", text="")
-
- row.prop(dopesheet, "show_transforms", text="")
-
- if bpy.data.meshes:
- row.prop(dopesheet, "show_meshes", text="")
- if bpy.data.shape_keys:
- row.prop(dopesheet, "show_shapekeys", text="")
- if bpy.data.meshes:
- row.prop(dopesheet, "show_modifiers", text="")
- if bpy.data.materials:
- row.prop(dopesheet, "show_materials", text="")
- if bpy.data.lamps:
- row.prop(dopesheet, "show_lamps", text="")
- if bpy.data.textures:
- row.prop(dopesheet, "show_textures", text="")
- if bpy.data.cameras:
- row.prop(dopesheet, "show_cameras", text="")
- if bpy.data.curves:
- row.prop(dopesheet, "show_curves", text="")
- if bpy.data.metaballs:
- row.prop(dopesheet, "show_metaballs", text="")
- if bpy.data.lattices:
- row.prop(dopesheet, "show_lattices", text="")
- if bpy.data.armatures:
- row.prop(dopesheet, "show_armatures", text="")
- if bpy.data.particles:
- row.prop(dopesheet, "show_particles", text="")
- if bpy.data.speakers:
- row.prop(dopesheet, "show_speakers", text="")
- if bpy.data.linestyles:
- row.prop(dopesheet, "show_linestyles", text="")
- if bpy.data.grease_pencil:
- row.prop(dopesheet, "show_gpencil", text="")
-
- layout.prop(dopesheet, "use_datablock_sort", text="")
+ if (not generic_filters_only) and (bpy.data.collections):
+ col = layout.column(align=True)
+ col.label("In Collection:")
+ col.prop(dopesheet, "filter_collection", text="")
+
+ # Standard = Present in all panels
+ @classmethod
+ def draw_standard_filters(cls, context, layout):
+ dopesheet = context.space_data.dopesheet
+
+ # Object Data Filters
+ layout.label("Include Sub-Object Data:")
+ split = layout.split()
+
+ # TODO: Add per-channel/axis convenience toggles?
+ col = split.column()
+ col.prop(dopesheet, "show_transforms", text="Transforms")
+
+ col = split.column()
+ col.prop(dopesheet, "show_modifiers", text="Modifiers")
+
+ layout.separator()
+
+ # datablock filters
+ layout.label("Include From Types:")
+ flow = layout.grid_flow(row_major=True, columns=2, even_rows=False, align=False)
+
+ flow.prop(dopesheet, "show_scenes", text="Scenes")
+ flow.prop(dopesheet, "show_worlds", text="Worlds")
+ flow.prop(dopesheet, "show_nodes", text="Node Trees")
+
+ if bpy.data.armatures:
+ flow.prop(dopesheet, "show_armatures", text="Armatures")
+ if bpy.data.cameras:
+ flow.prop(dopesheet, "show_cameras", text="Cameras")
+ if bpy.data.grease_pencil:
+ flow.prop(dopesheet, "show_gpencil", text="Grease Pencil Objects")
+ if bpy.data.lights:
+ flow.prop(dopesheet, "show_lights", text="Lights")
+ if bpy.data.materials:
+ flow.prop(dopesheet, "show_materials", text="Materials")
+ if bpy.data.textures:
+ flow.prop(dopesheet, "show_textures", text="Textures")
+ if bpy.data.meshes:
+ flow.prop(dopesheet, "show_meshes", text="Meshes")
+ if bpy.data.shape_keys:
+ flow.prop(dopesheet, "show_shapekeys", text="Shape Keys")
+ if bpy.data.curves:
+ flow.prop(dopesheet, "show_curves", text="Curves")
+ if bpy.data.particles:
+ flow.prop(dopesheet, "show_particles", text="Particles")
+ if bpy.data.lattices:
+ flow.prop(dopesheet, "show_lattices", text="Lattices")
+ if bpy.data.linestyles:
+ flow.prop(dopesheet, "show_linestyles", text="Line Styles")
+ if bpy.data.metaballs:
+ flow.prop(dopesheet, "show_metaballs", text="Metas")
+ if bpy.data.speakers:
+ flow.prop(dopesheet, "show_speakers", text="Speakers")
+
+ layout.separator()
+
+ # performance-related options (users will mostly have these enabled)
+ col = layout.column(align=True)
+ col.label("Options:")
+ col.prop(dopesheet, "use_datablock_sort", icon='NONE')
+
+
+# Popover for Dopesheet Editor(s) - Dopesheet, Action, Shapekey, GPencil, Mask, etc.
+class DOPESHEET_PT_filters(DopesheetFilterPopoverBase, Panel):
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = "Filters"
+
+ def draw(self, context):
+ layout = self.layout
+
+ dopesheet = context.space_data.dopesheet
+ ds_mode = context.space_data.mode
+
+ layout.prop(dopesheet, "show_summary", text="Summary")
+
+ DopesheetFilterPopoverBase.draw_generic_filters(context, layout)
+
+ if ds_mode in {'DOPESHEET', 'ACTION', 'GPENCIL'}:
+ layout.separator()
+ generic_filters_only = ds_mode != 'DOPESHEET'
+ DopesheetFilterPopoverBase.draw_search_filters(context, layout,
+ generic_filters_only=generic_filters_only)
+
+ if ds_mode == 'DOPESHEET':
+ layout.separator()
+ DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
#######################################
@@ -114,27 +200,49 @@ class DOPESHEET_HT_header(Header):
layout = self.layout
st = context.space_data
- toolsettings = context.tool_settings
row = layout.row(align=True)
row.template_header()
- DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
+ if st.mode == 'TIMELINE':
+ TIME_MT_editor_menus.draw_collapsible(context, layout)
+ TIME_HT_editor_buttons.draw_header(context, layout)
+ else:
+ layout.prop(st, "ui_mode", text="")
- layout.prop(st, "mode", text="")
+ DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
+ DOPESHEET_HT_editor_buttons.draw_header(context, layout)
+
+
+# Header for "normal" dopesheet editor modes (e.g. Dope Sheet, Action, Shape Keys, etc.)
+class DOPESHEET_HT_editor_buttons(Header):
+ bl_idname = "DOPESHEET_HT_editor_buttons"
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_label = ""
+
+ def draw(self, context):
+ pass
+
+ @staticmethod
+ def draw_header(context, layout):
+ st = context.space_data
+ toolsettings = context.tool_settings
if st.mode in {'ACTION', 'SHAPEKEY'}:
+ # TODO: These buttons need some tidying up - Probably by using a popover, and bypassing the template_id() here
row = layout.row(align=True)
row.operator("action.layer_prev", text="", icon='TRIA_DOWN')
row.operator("action.layer_next", text="", icon='TRIA_UP')
- layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
-
row = layout.row(align=True)
row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
row.operator("action.stash", text="Stash", icon='FREEZE')
- layout.prop(st.dopesheet, "show_summary", text="Summary")
+ layout.separator_spacer()
+
+ layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
+
+ layout.separator_spacer()
if st.mode == 'DOPESHEET':
dopesheet_filter(layout, context)
@@ -152,26 +260,28 @@ class DOPESHEET_HT_header(Header):
row.prop(st.dopesheet, "show_hidden", text="")
row = layout.row(align=True)
- row.prop(st.dopesheet, "use_filter_text", text="")
- if st.dopesheet.use_filter_text:
- row.prop(st.dopesheet, "filter_text", text="")
- row.prop(st.dopesheet, "use_multi_word_filter", text="")
+ row.prop(st.dopesheet, "filter_text", text="")
- row = layout.row(align=True)
- row.prop(toolsettings, "use_proportional_action",
- text="", icon_only=True)
- if toolsettings.use_proportional_action:
- row.prop(toolsettings, "proportional_edit_falloff",
- text="", icon_only=True)
+ layout.popover(
+ panel="DOPESHEET_PT_filters",
+ text="",
+ icon='FILTER',
+ )
# Grease Pencil mode doesn't need snapping, as it's frame-aligned only
if st.mode != 'GPENCIL':
layout.prop(st, "auto_snap", text="")
row = layout.row(align=True)
+ row.prop(toolsettings, "use_proportional_action", text="", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = toolsettings.use_proportional_action
+ sub.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True)
+
+ row = layout.row(align=True)
row.operator("action.copy", text="", icon='COPYDOWN')
row.operator("action.paste", text="", icon='PASTEDOWN')
- if st.mode not in ('GPENCIL', 'MASK'):
+ if st.mode not in {'GPENCIL', 'MASK'}:
row.operator("action.paste", text="", icon='PASTEFLIPDOWN').flipped = True
@@ -212,6 +322,10 @@ class DOPESHEET_MT_view(Menu):
layout.operator("action.properties", icon='MENU_PANEL')
layout.separator()
+ layout.prop(st.dopesheet, "use_multi_word_filter", text="Multi-word Match Search")
+
+ layout.separator()
+
layout.prop(st, "use_realtime_update")
layout.prop(st, "show_frame_indicator")
layout.prop(st, "show_sliders")
@@ -233,9 +347,7 @@ class DOPESHEET_MT_view(Menu):
layout.operator("action.view_frame")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class DOPESHEET_MT_select(Menu):
@@ -244,9 +356,9 @@ class DOPESHEET_MT_select(Menu):
def draw(self, context):
layout = self.layout
- # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None
- layout.operator("action.select_all_toggle").invert = False
- layout.operator("action.select_all_toggle", text="Invert Selection").invert = True
+ layout.operator("action.select_all", text="All").action = 'SELECT'
+ layout.operator("action.select_all", text="None").action = 'DESELECT'
+ layout.operator("action.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("action.select_border").axis_range = False
@@ -449,8 +561,69 @@ class DOPESHEET_MT_delete(Menu):
layout.operator("action.clean", text="Clean Channels").channels = True
+class DOPESHEET_MT_specials(Menu):
+ bl_label = "Dope Sheet Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("action.copy", text="Copy")
+ layout.operator("action.paste", text="Paste")
+ layout.operator("action.paste", text="Paste Flipped").flipped = True
+
+ layout.separator()
+
+ layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("action.easing_type", "type", text="Easing Type")
+
+ layout.separator()
+
+ layout.operator("action.keyframe_insert").type = 'SEL'
+ layout.operator("action.duplicate_move")
+ layout.operator("action.delete")
+
+ layout.separator()
+
+ layout.operator_menu_enum("action.mirror", "type", text="Mirror")
+ layout.operator_menu_enum("action.snap", "type", text="Snap")
+
+
+class DOPESHEET_MT_channel_specials(Menu):
+ bl_label = "Dope Sheet Channel Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
+ layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
+ layout.separator()
+ layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT'
+ layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT'
+
+ layout.separator()
+ layout.operator("anim.channels_group")
+ layout.operator("anim.channels_ungroup")
+
+ layout.separator()
+ layout.operator("anim.channels_editable_toggle")
+ layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode")
+
+ layout.separator()
+ layout.operator("anim.channels_expand")
+ layout.operator("anim.channels_collapse")
+
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+ layout.separator()
+
+ layout.operator("anim.channels_delete")
+
+
classes = (
DOPESHEET_HT_header,
+ DOPESHEET_HT_editor_buttons,
DOPESHEET_MT_editor_menus,
DOPESHEET_MT_view,
DOPESHEET_MT_select,
@@ -461,6 +634,9 @@ classes = (
DOPESHEET_MT_gpencil_channel,
DOPESHEET_MT_gpencil_frame,
DOPESHEET_MT_delete,
+ DOPESHEET_MT_specials,
+ DOPESHEET_MT_channel_specials,
+ DOPESHEET_PT_filters,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 2d45d11b423..9d903829bbb 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -18,7 +18,7 @@
# <pep8 compliant>
import bpy
-from bpy.types import Header, Panel, Menu
+from bpy.types import Header, Panel, Menu, UIList
class FILEBROWSER_HT_header(Header):
@@ -33,8 +33,7 @@ class FILEBROWSER_HT_header(Header):
if st.active_operator is None:
layout.template_header()
- row = layout.row()
- row.separator()
+ layout.menu("FILEBROWSER_MT_view")
row = layout.row(align=True)
row.operator("file.previous", text="", icon='BACK')
@@ -42,10 +41,8 @@ class FILEBROWSER_HT_header(Header):
row.operator("file.parent", text="", icon='FILE_PARENT')
row.operator("file.refresh", text="", icon='FILE_REFRESH')
- layout.separator()
layout.operator_context = 'EXEC_DEFAULT'
layout.operator("file.directory_new", icon='NEWFOLDER', text="")
- layout.separator()
layout.operator_context = 'INVOKE_DEFAULT'
@@ -53,20 +50,17 @@ class FILEBROWSER_HT_header(Header):
if params:
is_lib_browser = params.use_library_browsing
- layout.prop(params, "recursion_level", text="")
-
layout.prop(params, "display_type", expand=True, text="")
-
- layout.prop(params, "display_size", text="")
-
layout.prop(params, "sort_method", expand=True, text="")
-
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
+
+ layout.separator_spacer()
+
+ if params:
layout.prop(params, "use_filter", text="", icon='FILTER')
row = layout.row(align=True)
row.active = params.use_filter
-
row.prop(params, "use_filter_folder", text="")
if params.filter_glob:
@@ -95,7 +89,7 @@ class FILEBROWSER_HT_header(Header):
layout.template_running_jobs()
-class FILEBROWSER_UL_dir(bpy.types.UIList):
+class FILEBROWSER_UL_dir(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
direntry = item
# space = context.space_data
@@ -248,6 +242,22 @@ class FILEBROWSER_PT_advanced_filter(Panel):
col.prop(params, "filter_id")
+class FILEBROWSER_MT_view(Menu):
+ bl_label = "View"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+ params = st.params
+
+ layout.prop_menu_enum(params, "display_size")
+ layout.prop_menu_enum(params, "recursion_level")
+
+ layout.separator()
+
+ layout.menu("INFO_MT_area")
+
+
classes = (
FILEBROWSER_HT_header,
FILEBROWSER_UL_dir,
@@ -257,6 +267,7 @@ classes = (
FILEBROWSER_PT_bookmarks,
FILEBROWSER_PT_recent_folders,
FILEBROWSER_PT_advanced_filter,
+ FILEBROWSER_MT_view,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 5ed58a57e47..eacfb364130 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -19,15 +19,17 @@
# <pep8 compliant>
import bpy
-from bpy.types import Header, Menu
+from bpy.types import Header, Menu, Panel
+from .space_dopesheet import (
+ DopesheetFilterPopoverBase,
+ dopesheet_filter,
+)
class GRAPH_HT_header(Header):
bl_space_type = 'GRAPH_EDITOR'
def draw(self, context):
- from .space_dopesheet import dopesheet_filter
-
layout = self.layout
toolsettings = context.tool_settings
@@ -36,11 +38,10 @@ class GRAPH_HT_header(Header):
row = layout.row(align=True)
row.template_header()
- GRAPH_MT_editor_menus.draw_collapsible(context, layout)
-
- layout.prop(st, "mode", text="")
+ # Now a exposed as a sub-space type
+ # layout.prop(st, "mode", text="")
- dopesheet_filter(layout, context)
+ GRAPH_MT_editor_menus.draw_collapsible(context, layout)
row = layout.row(align=True)
row.prop(st, "use_normalization", icon='NORMALIZE_FCURVES', text="Normalize", toggle=True)
@@ -48,15 +49,30 @@ class GRAPH_HT_header(Header):
sub.active = st.use_normalization
sub.prop(st, "use_auto_normalization", icon='FILE_REFRESH', text="", toggle=True)
+ layout.separator_spacer()
+
+ dopesheet_filter(layout, context)
+
row = layout.row(align=True)
+ if st.has_ghost_curves:
+ row.operator("graph.ghost_curves_clear", text="", icon='GHOST_DISABLED')
+ else:
+ row.operator("graph.ghost_curves_create", text="", icon='GHOST_ENABLED')
- row.prop(toolsettings, "use_proportional_fcurve",
- text="", icon_only=True)
- if toolsettings.use_proportional_fcurve:
- row.prop(toolsettings, "proportional_edit_falloff",
- text="", icon_only=True)
+ layout.popover(
+ panel="GRAPH_PT_filters",
+ text="",
+ icon='FILTER',
+ )
layout.prop(st, "auto_snap", text="")
+
+ row = layout.row(align=True)
+ row.prop(toolsettings, "use_proportional_fcurve", text="", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = toolsettings.use_proportional_fcurve
+ sub.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True)
+
layout.prop(st, "pivot_point", icon_only=True)
row = layout.row(align=True)
@@ -64,11 +80,20 @@ class GRAPH_HT_header(Header):
row.operator("graph.paste", text="", icon='PASTEDOWN')
row.operator("graph.paste", text="", icon='PASTEFLIPDOWN').flipped = True
- row = layout.row(align=True)
- if st.has_ghost_curves:
- row.operator("graph.ghost_curves_clear", text="", icon='GHOST_DISABLED')
- else:
- row.operator("graph.ghost_curves_create", text="", icon='GHOST_ENABLED')
+
+class GRAPH_PT_filters(DopesheetFilterPopoverBase, Panel):
+ bl_space_type = 'GRAPH_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = "Filters"
+
+ def draw(self, context):
+ layout = self.layout
+
+ DopesheetFilterPopoverBase.draw_generic_filters(context, layout)
+ layout.separator()
+ DopesheetFilterPopoverBase.draw_search_filters(context, layout)
+ layout.separator()
+ DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
class GRAPH_MT_editor_menus(Menu):
@@ -129,9 +154,7 @@ class GRAPH_MT_view(Menu):
layout.operator("graph.view_frame")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class GRAPH_MT_select(Menu):
@@ -140,11 +163,12 @@ class GRAPH_MT_select(Menu):
def draw(self, context):
layout = self.layout
- # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None
- layout.operator("graph.select_all_toggle").invert = False
- layout.operator("graph.select_all_toggle", text="Invert Selection").invert = True
+ layout.operator("graph.select_all", text="All").action = 'SELECT'
+ layout.operator("graph.select_all", text="None").action = 'DESELECT'
+ layout.operator("graph.select_all", text="Invert").action = 'INVERT'
layout.separator()
+
props = layout.operator("graph.select_border")
props.axis_range = False
props.include_handles = False
@@ -302,6 +326,75 @@ class GRAPH_MT_delete(Menu):
layout.operator("graph.clean", text="Clean Channels").channels = True
+class GRAPH_MT_specials(Menu):
+ bl_label = "F-Curve Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("graph.copy", text="Copy")
+ layout.operator("graph.paste", text="Paste")
+ layout.operator("graph.paste", text="Paste Flipped").flipped = True
+
+ layout.separator()
+
+ layout.operator_menu_enum("graph.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("graph.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
+
+ layout.separator()
+
+ layout.operator("graph.keyframe_insert").type = 'SEL'
+ layout.operator("graph.duplicate_move")
+ layout.operator("graph.delete")
+
+ layout.separator()
+
+ layout.operator_menu_enum("graph.mirror", "type", text="Mirror")
+ layout.operator_menu_enum("graph.snap", "type", text="Snap")
+
+
+class GRAPH_MT_channel_specials(Menu):
+ bl_label = "F-Curve Channel Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+
+ layout.separator()
+ layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
+ layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
+ layout.separator()
+ layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT'
+ layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT'
+
+ layout.separator()
+ layout.operator("anim.channels_group")
+ layout.operator("anim.channels_ungroup")
+
+ layout.separator()
+ layout.operator("anim.channels_editable_toggle")
+ layout.operator_menu_enum("graph.extrapolation_type", "type", text="Extrapolation Mode")
+
+ layout.separator()
+ layout.operator("graph.hide", text="Hide Selected Curves").unselected = False
+ layout.operator("graph.hide", text="Hide Unselected Curves").unselected = True
+ layout.operator("graph.reveal")
+
+ layout.separator()
+ layout.operator("anim.channels_expand")
+ layout.operator("anim.channels_collapse")
+
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+ layout.separator()
+
+ layout.operator("anim.channels_delete")
+ if st.mode == 'DRIVERS':
+ layout.operator("graph.driver_delete_invalid")
+
+
classes = (
GRAPH_HT_header,
GRAPH_MT_editor_menus,
@@ -312,6 +405,9 @@ classes = (
GRAPH_MT_key,
GRAPH_MT_key_transform,
GRAPH_MT_delete,
+ GRAPH_MT_specials,
+ GRAPH_MT_channel_specials,
+ GRAPH_PT_filters,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 9a2215969cf..1303e46ab6c 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
import math
-from bpy.types import Header, Menu, Panel
+from bpy.types import Header, Menu, Panel, UIList
from .properties_paint_common import (
UnifiedPaintPanel,
brush_texture_settings,
@@ -130,9 +130,7 @@ class IMAGE_MT_view(Menu):
layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class IMAGE_MT_select(Menu):
@@ -141,14 +139,20 @@ class IMAGE_MT_select(Menu):
def draw(self, context):
layout = self.layout
+ layout.operator("uv.select_all", text="All").action = 'SELECT'
+ layout.operator("uv.select_all", text="None").action = 'DESELECT'
+ layout.operator("uv.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("uv.select_border").pinned = False
layout.operator("uv.select_border", text="Border Select Pinned").pinned = True
layout.operator("uv.circle_select")
layout.separator()
- layout.operator("uv.select_all").action = 'TOGGLE'
- layout.operator("uv.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("uv.select_less", text="Less")
+ layout.operator("uv.select_more", text="More")
layout.separator()
@@ -157,11 +161,6 @@ class IMAGE_MT_select(Menu):
layout.separator()
- layout.operator("uv.select_less", text="Less")
- layout.operator("uv.select_more", text="More")
-
- layout.separator()
-
layout.operator("uv.select_split")
@@ -192,30 +191,33 @@ class IMAGE_MT_image(Menu):
sima = context.space_data
ima = sima.image
-
- layout.operator("image.new")
- layout.operator("image.open")
-
show_render = sima.show_render
- layout.operator("image.read_renderlayers")
+ layout.operator("image.new", text="New")
+ layout.operator("image.open", text="Open...")
- layout.operator("image.save_dirty", text="Save All Images")
+ layout.operator("image.read_viewlayers")
if ima:
if not show_render:
- layout.operator("image.replace")
- layout.operator("image.reload")
+ layout.operator("image.replace", text="Replace...")
+ layout.operator("image.reload", text="Reload")
- layout.operator("image.save")
- layout.operator("image.save_as")
- layout.operator("image.save_as", text="Save a Copy").copy = True
+ layout.operator("image.external_edit", "Edit Externally")
- if ima.source == 'SEQUENCE':
- layout.operator("image.save_sequence")
+ layout.separator()
- layout.operator("image.external_edit", "Edit Externally")
+ if ima:
+ layout.operator("image.save", text="Save")
+ layout.operator("image.save_as", text="Save As...")
+ layout.operator("image.save_as", text="Save a Copy...").copy = True
+ if ima and ima.source == 'SEQUENCE':
+ layout.operator("image.save_sequence")
+
+ layout.operator("image.save_dirty", text="Save All Images")
+
+ if ima:
layout.separator()
layout.menu("IMAGE_MT_image_invert")
@@ -223,7 +225,7 @@ class IMAGE_MT_image(Menu):
if not show_render:
if not ima.packed_file:
layout.separator()
- layout.operator("image.pack")
+ layout.operator("image.pack", text="Pack")
# only for dirty && specific image types, perhaps
# this could be done in operator poll too
@@ -428,6 +430,43 @@ class IMAGE_MT_uvs_select_mode(Menu):
props.data_path = "tool_settings.uv_select_mode"
+class IMAGE_MT_specials(Menu):
+ bl_label = "UV Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ sima = context.space_data
+
+ # UV Edit Mode
+ if sima.show_uvedit:
+ layout.operator("uv.unwrap")
+ layout.operator("uv.follow_active_quads")
+
+ layout.separator()
+
+ layout.operator("uv.pin").clear = False
+ layout.operator("uv.pin", text="Unpin").clear = True
+
+ layout.separator()
+
+ layout.operator("uv.weld")
+ layout.operator("uv.stitch")
+
+ layout.separator()
+
+ layout.operator_enum("uv.align", "axis") # W, 2/3/4
+
+ layout.separator()
+
+ layout.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True
+ layout.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True
+
+ layout.separator()
+
+ layout.menu("IMAGE_MT_uvs_snap")
+
+
class IMAGE_HT_header(Header):
bl_space_type = 'IMAGE_EDITOR'
@@ -447,20 +486,8 @@ class IMAGE_HT_header(Header):
row = layout.row(align=True)
row.template_header()
- MASK_MT_editor_menus.draw_collapsible(context, layout)
-
- layout.template_ID(sima, "image", new="image.new", open="image.open")
- if not show_render:
- layout.prop(sima, "use_image_pin", text="")
-
layout.prop(sima, "mode", text="")
- if show_maskedit:
- row = layout.row()
- row.template_ID(sima, "mask", new="mask.new")
-
- layout.prop(sima, "pivot_point", icon_only=True)
-
# uv editing
if show_uvedit:
uvedit = sima.uv_editor
@@ -473,19 +500,45 @@ class IMAGE_HT_header(Header):
layout.prop(toolsettings, "uv_select_mode", text="", expand=True)
layout.prop(uvedit, "sticky_select_mode", icon_only=True)
- row = layout.row(align=True)
- row.prop(toolsettings, "proportional_edit", icon_only=True)
- if toolsettings.proportional_edit != 'DISABLED':
- row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
+ MASK_MT_editor_menus.draw_collapsible(context, layout)
+
+ layout.separator_spacer()
+
+ layout.template_ID(sima, "image", new="image.new", open="image.open")
+
+ if show_maskedit:
+ row = layout.row()
+ row.template_ID(sima, "mask", new="mask.new")
+ layout.separator_spacer()
+
+ if show_uvedit or show_maskedit or mode == 'PAINT':
+ layout.prop(sima, "use_realtime_update", icon_only=True, icon='FILE_REFRESH')
+
+ if not show_render:
+ layout.prop(sima, "use_image_pin", text="")
+
+ if show_uvedit:
+ uvedit = sima.uv_editor
+
+ mesh = context.edit_object.data
+ layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="")
+
+ # Snap
row = layout.row(align=True)
row.prop(toolsettings, "use_snap", text="")
row.prop(toolsettings, "snap_uv_element", icon_only=True)
if toolsettings.snap_uv_element != 'INCREMENT':
row.prop(toolsettings, "snap_target", text="")
- mesh = context.edit_object.data
- layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")
+ row = layout.row(align=True)
+ row.prop(toolsettings, "proportional_edit", icon_only=True)
+ # if toolsettings.proportional_edit != 'DISABLED':
+ sub = row.row(align=True)
+ sub.active = toolsettings.proportional_edit != 'DISABLED'
+ sub.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
+
+ layout.prop(sima, "pivot_point", icon_only=True)
if ima:
if ima.is_stereo_3d:
@@ -505,9 +558,6 @@ class IMAGE_HT_header(Header):
if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}:
row.operator("image.play_composite", icon='PLAY')
- if show_uvedit or show_maskedit or mode == 'PAINT':
- layout.prop(sima, "use_realtime_update", icon_only=True, icon='LOCKED')
-
class MASK_MT_editor_menus(Menu):
bl_idname = "MASK_MT_editor_menus"
@@ -619,50 +669,6 @@ class IMAGE_PT_image_properties(Panel):
layout.template_image(sima, "image", iuser, multiview=True)
-class IMAGE_PT_game_properties(Panel):
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'UI'
- bl_label = "Game Properties"
-
- @classmethod
- def poll(cls, context):
- sima = context.space_data
- # display even when not in game mode because these settings effect the 3d view
- return (sima and sima.image and not sima.show_maskedit) # and (rd.engine == 'BLENDER_GAME')
-
- def draw(self, context):
- layout = self.layout
-
- sima = context.space_data
- ima = sima.image
-
- split = layout.split()
- col = split.column()
- col.prop(ima, "use_animation")
- sub = col.column(align=True)
- sub.active = ima.use_animation
- sub.prop(ima, "frame_start", text="Start")
- sub.prop(ima, "frame_end", text="End")
- sub.prop(ima, "fps", text="Speed")
-
- col = split.column()
- col.prop(ima, "use_tiles")
- sub = col.column(align=True)
- sub.active = ima.use_tiles or ima.use_animation
- sub.prop(ima, "tiles_x", text="X")
- sub.prop(ima, "tiles_y", text="Y")
-
- split = layout.split()
- col = split.column()
- col.label(text="Clamp:")
- col.prop(ima, "use_clamp_x", text="X")
- col.prop(ima, "use_clamp_y", text="Y")
-
- col = split.column()
- col.label(text="Mapping:")
- col.prop(ima, "mapping", expand=True)
-
-
class IMAGE_PT_view_properties(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
@@ -694,11 +700,11 @@ class IMAGE_PT_view_properties(Panel):
col.label(text="Coordinates:")
col.prop(sima, "show_repeat", text="Repeat")
if show_uvedit:
- col.prop(uvedit, "show_normalized_coords", text="Normalized")
+ col.prop(uvedit, "show_pixel_coords", text="Pixel")
elif show_uvedit:
col.label(text="Coordinates:")
- col.prop(uvedit, "show_normalized_coords", text="Normalized")
+ col.prop(uvedit, "show_pixel_coords", text="Pixel")
if show_uvedit or show_maskedit:
col = layout.column()
@@ -730,10 +736,41 @@ class IMAGE_PT_view_properties(Panel):
row.active = uvedit.show_other_objects
row.prop(uvedit, "other_uv_filter", text="Filter")
- if show_render and ima:
- layout.separator()
- render_slot = ima.render_slots.active
- layout.prop(render_slot, "name", text="Slot Name")
+
+class IMAGE_UL_render_slots(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ slot = item
+ layout.prop(slot, "name", text="", emboss=False)
+
+
+class IMAGE_PT_render_slots(Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'UI'
+ bl_label = "Render Slots"
+
+ @classmethod
+ def poll(cls, context):
+ sima = context.space_data
+ return (sima and sima.image and sima.show_render)
+
+ def draw(self, context):
+ layout = self.layout
+
+ sima = context.space_data
+ ima = sima.image
+
+ row = layout.row()
+
+ col = row.column()
+ col.template_list("IMAGE_UL_render_slots", "render_slots", ima, "render_slots", ima.render_slots, "active_index", rows=3)
+
+ col = row.column(align=True)
+ col.operator("image.add_render_slot", icon='ZOOMIN', text="")
+ col.operator("image.remove_render_slot", icon='ZOOMOUT', text="")
+
+ col.separator()
+
+ col.operator("image.clear_render_slot", icon='X', text="")
class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel):
@@ -1357,6 +1394,7 @@ classes = (
IMAGE_MT_uvs_mirror,
IMAGE_MT_uvs_weldalign,
IMAGE_MT_uvs_select_mode,
+ IMAGE_MT_specials,
IMAGE_HT_header,
MASK_MT_editor_menus,
IMAGE_PT_mask,
@@ -1366,7 +1404,8 @@ classes = (
IMAGE_PT_active_mask_spline,
IMAGE_PT_active_mask_point,
IMAGE_PT_image_properties,
- IMAGE_PT_game_properties,
+ IMAGE_UL_render_slots,
+ IMAGE_PT_render_slots,
IMAGE_PT_view_properties,
IMAGE_PT_tools_transform_uvs,
IMAGE_PT_tools_align_uvs,
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index edae5e2f452..e5ef5f9a0da 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -26,346 +26,29 @@ class INFO_HT_header(Header):
def draw(self, context):
layout = self.layout
+ layout.template_header()
- window = context.window
- scene = context.scene
- rd = scene.render
+ # Empty for now until info editor gets turned into log editor
+ pass
- row = layout.row(align=True)
- row.template_header()
- INFO_MT_editor_menus.draw_collapsible(context, layout)
-
- if window.screen.show_fullscreen:
- layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous")
- layout.separator()
- else:
- layout.template_ID(context.window, "screen", new="screen.new", unlink="screen.delete")
- layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete")
-
- layout.separator()
-
- if rd.has_multiple_engines:
- layout.prop(rd, "engine", text="")
-
- layout.separator()
-
- layout.template_running_jobs()
-
- layout.template_reports_banner()
-
- row = layout.row(align=True)
-
- if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False:
- row.label("Auto-run disabled", icon='ERROR')
- if bpy.data.is_saved:
- props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted")
- props.use_scripts = True
-
- row.operator("script.autoexec_warn_clear", text="Ignore")
-
- # include last so text doesn't push buttons out of the header
- row.label(bpy.app.autoexec_fail_message)
- return
-
- row.operator("wm.splash", text="", icon='BLENDER', emboss=False)
- row.label(text=scene.statistics(), translate=False)
-
-
-class INFO_MT_editor_menus(Menu):
- bl_idname = "INFO_MT_editor_menus"
- bl_label = ""
-
- def draw(self, context):
- self.draw_menus(self.layout, context)
-
- @staticmethod
- def draw_menus(layout, context):
- scene = context.scene
- rd = scene.render
-
- layout.menu("INFO_MT_file")
-
- if rd.use_game_engine:
- layout.menu("INFO_MT_game")
- else:
- layout.menu("INFO_MT_render")
-
- layout.menu("INFO_MT_window")
- layout.menu("INFO_MT_help")
-
-
-class INFO_MT_file(Menu):
- bl_label = "File"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator_context = 'INVOKE_AREA'
- layout.operator("wm.read_homefile", text="New", icon='NEW')
- layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
- layout.menu("INFO_MT_file_open_recent", icon='OPEN_RECENT')
- layout.operator("wm.revert_mainfile", icon='FILE_REFRESH')
- layout.operator("wm.recover_last_session", icon='RECOVER_LAST')
- layout.operator("wm.recover_auto_save", text="Recover Auto Save...", icon='RECOVER_AUTO')
-
- layout.separator()
-
- layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA'
- layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK')
-
- layout.operator_context = 'INVOKE_AREA'
- layout.operator("wm.save_as_mainfile", text="Save As...", icon='SAVE_AS')
- layout.operator_context = 'INVOKE_AREA'
- layout.operator("wm.save_as_mainfile", text="Save Copy...", icon='SAVE_COPY').copy = True
-
- layout.separator()
-
- layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES')
-
- layout.operator_context = 'INVOKE_AREA'
- layout.operator("wm.save_homefile", icon='SAVE_PREFS')
- layout.operator("wm.read_factory_settings", icon='LOAD_FACTORY')
-
- if any(bpy.utils.app_template_paths()):
- app_template = context.user_preferences.app_template
- if app_template:
- layout.operator(
- "wm.read_factory_settings",
- text="Load Factory Template Settings",
- icon='LOAD_FACTORY',
- ).app_template = app_template
- del app_template
-
- layout.menu("USERPREF_MT_app_templates", icon='FILE_BLEND')
-
- layout.separator()
-
- layout.operator_context = 'INVOKE_AREA'
- layout.operator("wm.link", text="Link", icon='LINK_BLEND')
- layout.operator("wm.append", text="Append", icon='APPEND_BLEND')
- layout.menu("INFO_MT_file_previews")
-
- layout.separator()
-
- layout.menu("INFO_MT_file_import", icon='IMPORT')
- layout.menu("INFO_MT_file_export", icon='EXPORT')
-
- layout.separator()
-
- layout.menu("INFO_MT_file_external_data", icon='EXTERNAL_DATA')
- layout.operator("wm.blend_strings_utf8_validate", icon='FILE_BLEND')
-
- layout.separator()
-
- layout.operator_context = 'EXEC_AREA'
- if bpy.data.is_dirty and context.user_preferences.view.use_quit_dialog:
- layout.operator_context = 'INVOKE_SCREEN' # quit dialog
- layout.operator("wm.quit_blender", text="Quit", icon='QUIT')
-
-
-class INFO_MT_file_import(Menu):
- bl_idname = "INFO_MT_file_import"
- bl_label = "Import"
-
- def draw(self, context):
- if bpy.app.build_options.collada:
- self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
- if bpy.app.build_options.alembic:
- self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
-
-
-class INFO_MT_file_export(Menu):
- bl_idname = "INFO_MT_file_export"
- bl_label = "Export"
-
- def draw(self, context):
- if bpy.app.build_options.collada:
- self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
- if bpy.app.build_options.alembic:
- self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
-
-
-class INFO_MT_file_external_data(Menu):
- bl_label = "External Data"
+# Not really info, just add to re-usable location.
+class INFO_MT_area(Menu):
+ bl_label = "Area"
def draw(self, context):
layout = self.layout
- icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT'
- layout.operator("file.autopack_toggle", icon=icon)
-
- layout.separator()
-
- pack_all = layout.row()
- pack_all.operator("file.pack_all")
- pack_all.active = not bpy.data.use_autopack
-
- unpack_all = layout.row()
- unpack_all.operator("file.unpack_all")
- unpack_all.active = not bpy.data.use_autopack
-
- layout.separator()
-
- layout.operator("file.make_paths_relative")
- layout.operator("file.make_paths_absolute")
- layout.operator("file.report_missing_files")
- layout.operator("file.find_missing_files")
-
-
-class INFO_MT_file_previews(Menu):
- bl_label = "Data Previews"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("wm.previews_ensure")
- layout.operator("wm.previews_batch_generate")
-
- layout.separator()
-
- layout.operator("wm.previews_clear")
- layout.operator("wm.previews_batch_clear")
-
-
-class INFO_MT_game(Menu):
- bl_label = "Game"
-
- def draw(self, context):
- layout = self.layout
-
- gs = context.scene.game_settings
-
- layout.operator("view3d.game_start")
-
- layout.separator()
-
- layout.prop(gs, "show_debug_properties")
- layout.prop(gs, "show_framerate_profile")
- layout.prop(gs, "show_physics_visualization")
- layout.prop(gs, "use_deprecation_warnings")
- layout.prop(gs, "use_animation_record")
- layout.separator()
- layout.prop(gs, "use_auto_start")
-
-
-class INFO_MT_render(Menu):
- bl_label = "Render"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
- props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
- props.animation = True
- props.use_viewport = True
-
- layout.separator()
-
- layout.operator("render.opengl", text="OpenGL Render Image")
- layout.operator("render.opengl", text="OpenGL Render Animation").animation = True
- layout.menu("INFO_MT_opengl_render")
-
- layout.separator()
-
- layout.operator("render.view_show")
- layout.operator("render.play_rendered_anim", icon='PLAY')
-
-
-class INFO_MT_opengl_render(Menu):
- bl_label = "OpenGL Render Options"
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.render
- layout.prop(rd, "use_antialiasing")
- layout.prop(rd, "use_full_sample")
-
- layout.prop_menu_enum(rd, "antialiasing_samples")
- layout.prop_menu_enum(rd, "alpha_mode")
-
-
-class INFO_MT_window(Menu):
- bl_label = "Window"
-
- def draw(self, context):
- import sys
-
- layout = self.layout
-
- layout.operator("wm.window_duplicate")
- layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
-
- layout.separator()
-
- layout.operator("screen.screenshot")
-
- if sys.platform[:3] == "win":
- layout.separator()
- layout.operator("wm.console_toggle", icon='CONSOLE')
-
- if context.scene.render.use_multiview:
- layout.separator()
- layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO')
-
-
-class INFO_MT_help(Menu):
- bl_label = "Help"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator(
- "wm.url_open", text="Manual", icon='HELP',
- ).url = "https://docs.blender.org/manual/en/dev/"
- layout.operator(
- "wm.url_open", text="Release Log", icon='URL',
- ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
- layout.separator()
-
- layout.operator(
- "wm.url_open", text="Blender Website", icon='URL',
- ).url = "https://www.blender.org"
- layout.operator(
- "wm.url_open", text="Blender Store", icon='URL',
- ).url = "https://store.blender.org"
- layout.operator(
- "wm.url_open", text="Developer Community", icon='URL',
- ).url = "https://www.blender.org/get-involved/"
- layout.operator(
- "wm.url_open", text="User Community", icon='URL',
- ).url = "https://www.blender.org/support/user-community"
- layout.separator()
- layout.operator(
- "wm.url_open", text="Report a Bug", icon='URL',
- ).url = "https://developer.blender.org/maniphest/task/edit/form/1"
- layout.separator()
-
- layout.operator(
- "wm.url_open", text="Python API Reference", icon='URL',
- ).url = bpy.types.WM_OT_doc_view._prefix
-
- layout.operator("wm.operator_cheat_sheet", icon='TEXT')
- layout.operator("wm.sysinfo", icon='TEXT')
- layout.separator()
-
- layout.operator("wm.splash", icon='BLENDER')
+ layout.operator("screen.area_dupli")
+ if context.space_data.type == 'VIEW_3D':
+ layout.operator("screen.region_quadview")
+ layout.operator("screen.screen_full_area")
+ layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
classes = (
INFO_HT_header,
- INFO_MT_editor_menus,
- INFO_MT_file,
- INFO_MT_file_import,
- INFO_MT_file_export,
- INFO_MT_file_external_data,
- INFO_MT_file_previews,
- INFO_MT_game,
- INFO_MT_render,
- INFO_MT_opengl_render,
- INFO_MT_window,
- INFO_MT_help,
+ INFO_MT_area,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py
deleted file mode 100644
index b552181f491..00000000000
--- a/release/scripts/startup/bl_ui/space_logic.py
+++ /dev/null
@@ -1,145 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-import bpy
-from bpy.types import Header, Menu, Panel
-
-
-class LOGIC_PT_properties(Panel):
- bl_space_type = 'LOGIC_EDITOR'
- bl_region_type = 'UI'
- bl_label = "Properties"
-
- @classmethod
- def poll(cls, context):
- ob = context.active_object
- return ob and ob.game
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.active_object
- game = ob.game
- is_font = (ob.type == 'FONT')
-
- if is_font:
- prop_index = game.properties.find("Text")
- if prop_index != -1:
- layout.operator("object.game_property_remove", text="Remove Text Game Property", icon='X').index = prop_index
- row = layout.row()
- sub = row.row()
- sub.enabled = 0
- prop = game.properties[prop_index]
- sub.prop(prop, "name", text="")
- row.prop(prop, "type", text="")
- # get the property from the body, not the game property
- # note, don't do this - it's too slow and body can potentially be a really long string.
- #~ row.prop(ob.data, "body", text="")
- row.label("See Text Object")
- else:
- props = layout.operator("object.game_property_new", text="Add Text Game Property", icon='ZOOMIN')
- props.name = "Text"
- props.type = 'STRING'
-
- props = layout.operator("object.game_property_new", text="Add Game Property", icon='ZOOMIN')
- props.name = ""
-
- for i, prop in enumerate(game.properties):
-
- if is_font and i == prop_index:
- continue
-
- box = layout.box()
- row = box.row()
- row.prop(prop, "name", text="")
- row.prop(prop, "type", text="")
- row.prop(prop, "value", text="")
- row.prop(prop, "show_debug", text="", toggle=True, icon='INFO')
- sub = row.row(align=True)
- props = sub.operator("object.game_property_move", text="", icon='TRIA_UP')
- props.index = i
- props.direction = 'UP'
- props = sub.operator("object.game_property_move", text="", icon='TRIA_DOWN')
- props.index = i
- props.direction = 'DOWN'
- row.operator("object.game_property_remove", text="", icon='X', emboss=False).index = i
-
-
-class LOGIC_MT_logicbricks_add(Menu):
- bl_label = "Add"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator_menu_enum("logic.sensor_add", "type", text="Sensor")
- layout.operator_menu_enum("logic.controller_add", "type", text="Controller")
- layout.operator_menu_enum("logic.actuator_add", "type", text="Actuator")
-
-
-class LOGIC_HT_header(Header):
- bl_space_type = 'LOGIC_EDITOR'
-
- def draw(self, context):
- layout = self.layout.row(align=True)
-
- layout.template_header()
-
- LOGIC_MT_editor_menus.draw_collapsible(context, layout)
-
-
-class LOGIC_MT_editor_menus(Menu):
- bl_idname = "LOGIC_MT_editor_menus"
- bl_label = ""
-
- def draw(self, context):
- self.draw_menus(self.layout, context)
-
- @staticmethod
- def draw_menus(layout, context):
- layout.menu("LOGIC_MT_view")
- layout.menu("LOGIC_MT_logicbricks_add")
-
-
-class LOGIC_MT_view(Menu):
- bl_label = "View"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("logic.properties", icon='MENU_PANEL')
-
- layout.separator()
-
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
-
-
-classes = (
- LOGIC_PT_properties,
- LOGIC_MT_logicbricks_add,
- LOGIC_HT_header,
- LOGIC_MT_editor_menus,
- LOGIC_MT_view,
-)
-
-if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 8a933570c5e..4e20001b133 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -19,15 +19,17 @@
# <pep8 compliant>
import bpy
-from bpy.types import Header, Menu
+from bpy.types import Header, Menu, Panel
+from .space_dopesheet import (
+ DopesheetFilterPopoverBase,
+ dopesheet_filter,
+)
class NLA_HT_header(Header):
bl_space_type = 'NLA_EDITOR'
def draw(self, context):
- from .space_dopesheet import dopesheet_filter
-
layout = self.layout
st = context.space_data
@@ -37,11 +39,34 @@ class NLA_HT_header(Header):
NLA_MT_editor_menus.draw_collapsible(context, layout)
+ layout.separator_spacer()
+
dopesheet_filter(layout, context)
+ layout.popover(
+ panel="NLA_PT_filters",
+ text="",
+ icon='FILTER',
+ )
+
layout.prop(st, "auto_snap", text="")
+class NLA_PT_filters(DopesheetFilterPopoverBase, Panel):
+ bl_space_type = 'NLA_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = "Filters"
+
+ def draw(self, context):
+ layout = self.layout
+
+ DopesheetFilterPopoverBase.draw_generic_filters(context, layout)
+ layout.separator()
+ DopesheetFilterPopoverBase.draw_search_filters(context, layout)
+ layout.separator()
+ DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
+
+
class NLA_MT_editor_menus(Menu):
bl_idname = "NLA_MT_editor_menus"
bl_label = ""
@@ -90,9 +115,7 @@ class NLA_MT_view(Menu):
layout.operator("nla.view_frame")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class NLA_MT_select(Menu):
@@ -101,9 +124,9 @@ class NLA_MT_select(Menu):
def draw(self, context):
layout = self.layout
- # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None
- layout.operator("nla.select_all_toggle").invert = False
- layout.operator("nla.select_all_toggle", text="Invert Selection").invert = True
+ layout.operator("nla.select_all", text="All").action = 'SELECT'
+ layout.operator("nla.select_all", text="None").action = 'DESELECT'
+ layout.operator("nla.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("nla.select_border").axis_range = False
@@ -219,6 +242,7 @@ classes = (
NLA_MT_marker,
NLA_MT_add,
NLA_MT_edit_transform,
+ NLA_PT_filters,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index c2735998d2c..9d8c14ba9c3 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -21,6 +21,7 @@ import bpy
import nodeitems_utils
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
+from bl_operators.presets import PresetMenu
from .properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
@@ -48,78 +49,107 @@ class NODE_HT_header(Header):
row = layout.row(align=True)
row.template_header()
- NODE_MT_editor_menus.draw_collapsible(context, layout)
-
- layout.prop(snode, "tree_type", text="", expand=True)
+ # Now expanded via the 'ui_type'
+ # layout.prop(snode, "tree_type", text="")
if snode.tree_type == 'ShaderNodeTree':
- if scene.render.use_shading_nodes:
- layout.prop(snode, "shader_type", text="", expand=True)
+ layout.prop(snode, "shader_type", text="")
ob = context.object
- if (not scene.render.use_shading_nodes or snode.shader_type == 'OBJECT') and ob:
+ if snode.shader_type == 'OBJECT' and ob:
+
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+
+ # No shader nodes for Eevee lamps
+ if snode_id and not (context.engine == 'BLENDER_EEVEE' and ob.type == 'LIGHT'):
+ row = layout.row()
+ row.prop(snode_id, "use_nodes")
+
+ layout.separator_spacer()
+
row = layout.row()
# disable material slot buttons when pinned, cannot find correct slot within id_from (#36589)
row.enabled = not snode.pin
# Show material.new when no active ID/slot exists
if not id_from and ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'METABALL'}:
row.template_ID(ob, "active_material", new="material.new")
- # Material ID, but not for Lamps
- if id_from and ob.type != 'LAMP':
+ # Material ID, but not for Lights
+ if id_from and ob.type != 'LIGHT':
row.template_ID(id_from, "active_material", new="material.new")
- # Don't show "Use Nodes" Button when Engine is BI for Lamps
- if snode_id and not (scene.render.use_shading_nodes == 0 and ob.type == 'LAMP'):
- layout.prop(snode_id, "use_nodes")
+ if snode.shader_type == 'WORLD':
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+
+ if snode_id:
+ row = layout.row()
+ row.prop(snode_id, "use_nodes")
+
+ layout.separator_spacer()
- if scene.render.use_shading_nodes and snode.shader_type == 'WORLD':
row = layout.row()
row.enabled = not snode.pin
row.template_ID(scene, "world", new="world.new")
- if snode_id:
- row.prop(snode_id, "use_nodes")
- if scene.render.use_shading_nodes and snode.shader_type == 'LINESTYLE':
- rl = context.scene.render.layers.active
- lineset = rl.freestyle_settings.linesets.active
+ if snode.shader_type == 'LINESTYLE':
+ view_layer = context.view_layer
+ lineset = view_layer.freestyle_settings.linesets.active
+
if lineset is not None:
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+
+ if snode_id:
+ row = layout.row()
+ row.prop(snode_id, "use_nodes")
+
+ layout.separator_spacer()
+
row = layout.row()
row.enabled = not snode.pin
row.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new")
- if snode_id:
- row.prop(snode_id, "use_nodes")
elif snode.tree_type == 'TextureNodeTree':
- layout.prop(snode, "texture_type", text="", expand=True)
+ layout.prop(snode, "texture_type", text="")
+
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+
+ if snode_id:
+ layout.prop(snode_id, "use_nodes")
+
+ layout.separator_spacer()
if id_from:
if snode.texture_type == 'BRUSH':
layout.template_ID(id_from, "texture", new="texture.new")
else:
layout.template_ID(id_from, "active_texture", new="texture.new")
- if snode_id:
- layout.prop(snode_id, "use_nodes")
elif snode.tree_type == 'CompositorNodeTree':
+
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+
if snode_id:
layout.prop(snode_id, "use_nodes")
+
+ layout.prop(snode, "use_auto_render")
layout.prop(snode, "show_backdrop")
if snode.show_backdrop:
row = layout.row(align=True)
row.prop(snode, "backdrop_channels", text="", expand=True)
- layout.prop(snode, "use_auto_render")
else:
# Custom node tree is edited as independent ID block
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+
+ layout.separator_spacer()
+
layout.template_ID(snode, "node_tree", new="node.new_node_tree")
- layout.prop(snode, "pin", text="")
- layout.operator("node.tree_path_parent", text="", icon='FILE_PARENT')
+ layout.separator_spacer()
- layout.separator()
+ layout.template_running_jobs()
- # Auto-offset nodes (called "insert_offset" in code)
- layout.prop(snode, "use_insert_offset", text="")
+ layout.prop(snode, "pin", text="")
+ layout.operator("node.tree_path_parent", text="", icon='FILE_PARENT')
# Snap
row = layout.row(align=True)
@@ -132,8 +162,6 @@ class NODE_HT_header(Header):
row.operator("node.clipboard_copy", text="", icon='COPYDOWN')
row.operator("node.clipboard_paste", text="", icon='PASTEDOWN')
- layout.template_running_jobs()
-
class NODE_MT_editor_menus(Menu):
bl_idname = "NODE_MT_editor_menus"
@@ -171,11 +199,18 @@ class NODE_MT_view(Menu):
def draw(self, context):
layout = self.layout
+ snode = context.space_data
+
layout.operator("node.properties", icon='MENU_PANEL')
layout.operator("node.toolbar", icon='MENU_PANEL')
layout.separator()
+ # Auto-offset nodes (called "insert_offset" in code)
+ layout.prop(snode, "use_insert_offset")
+
+ layout.separator()
+
layout.operator("view2d.zoom_in")
layout.operator("view2d.zoom_out")
@@ -194,9 +229,7 @@ class NODE_MT_view(Menu):
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class NODE_MT_select(Menu):
@@ -271,16 +304,16 @@ class NODE_MT_node(Menu):
layout.separator()
- layout.operator("node.read_renderlayers")
+ layout.operator("node.read_viewlayers")
layout.operator("node.read_fullsamplelayers")
-class NODE_MT_node_color_presets(Menu):
+class NODE_PT_node_color_presets(PresetMenu):
"""Predefined node color"""
bl_label = "Color Presets"
preset_subdir = "node_color"
preset_operator = "script.execute_preset"
- draw = Menu.draw_preset
+ preset_add_operator = "node.node_color_preset_add"
class NODE_MT_node_color_specials(Menu):
@@ -292,6 +325,41 @@ class NODE_MT_node_color_specials(Menu):
layout.operator("node.node_copy_color", icon='COPY_ID')
+class NODE_MT_specials(Menu):
+ bl_label = "Node Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_DEFAULT'
+ layout.operator("node.duplicate_move")
+ layout.operator("node.delete")
+ layout.operator_context = 'EXEC_DEFAULT'
+
+ layout.operator("node.delete_reconnect")
+
+ layout.separator()
+
+ layout.operator("node.link_make").replace = False
+ layout.operator("node.link_make", text="Make and Replace Links").replace = True
+ layout.operator("node.links_detach")
+
+ layout.separator()
+
+ layout.operator("node.group_make", text="Group")
+ layout.operator("node.group_ungroup", text="Ungroup")
+ layout.operator("node.group_edit").exit = False
+
+ layout.separator()
+
+ layout.operator("node.hide_toggle")
+ layout.operator("node.mute_toggle")
+ layout.operator("node.preview_toggle")
+ layout.operator("node.hide_socket_toggle")
+ layout.operator("node.options_toggle")
+ layout.operator("node.collapse_hide_unused_toggle")
+
+
class NODE_PT_active_node_generic(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
@@ -324,6 +392,9 @@ class NODE_PT_active_node_color(Panel):
node = context.active_node
self.layout.prop(node, "use_custom_color", text="")
+ def draw_header_preset(self, context):
+ NODE_PT_node_color_presets.draw_panel_header(self.layout)
+
def draw(self, context):
layout = self.layout
node = context.active_node
@@ -331,13 +402,8 @@ class NODE_PT_active_node_color(Panel):
layout.enabled = node.use_custom_color
row = layout.row()
- col = row.column()
- col.menu("NODE_MT_node_color_presets")
- col.prop(node, "color", text="")
- col = row.column(align=True)
- col.operator("node.node_color_preset_add", text="", icon='ZOOMIN').remove_active = False
- col.operator("node.node_color_preset_add", text="", icon='ZOOMOUT').remove_active = True
- col.menu("NODE_MT_node_color_specials", text="", icon='DOWNARROW_HLT')
+ row.prop(node, "color", text="")
+ row.menu("NODE_MT_node_color_specials", text="", icon='DOWNARROW_HLT')
class NODE_PT_active_node_properties(Panel):
@@ -395,8 +461,7 @@ class NODE_PT_backdrop(Panel):
col = layout.column(align=True)
col.label(text="Offset:")
- col.prop(snode, "backdrop_x", text="X")
- col.prop(snode, "backdrop_y", text="Y")
+ col.prop(snode, "backdrop_offset", text="")
col.operator("node.backimage_move", text="Move")
layout.operator("node.backimage_fit", text="Fit")
@@ -537,8 +602,9 @@ classes = (
NODE_MT_view,
NODE_MT_select,
NODE_MT_node,
- NODE_MT_node_color_presets,
+ NODE_PT_node_color_presets,
NODE_MT_node_color_specials,
+ NODE_MT_specials,
NODE_PT_active_node_generic,
NODE_PT_active_node_color,
NODE_PT_active_node_properties,
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 4951ef83ad0..97fae2690fd 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -18,7 +18,7 @@
# <pep8 compliant>
import bpy
-from bpy.types import Header, Menu
+from bpy.types import Header, Menu, Panel
class OUTLINER_HT_header(Header):
@@ -28,21 +28,47 @@ class OUTLINER_HT_header(Header):
layout = self.layout
space = context.space_data
+ display_mode = space.display_mode
scene = context.scene
ks = context.scene.keying_sets.active
row = layout.row(align=True)
row.template_header()
- OUTLINER_MT_editor_menus.draw_collapsible(context, layout)
+ layout.prop(space, "display_mode", icon_only=True)
- layout.prop(space, "display_mode", text="")
+ if display_mode == 'DATA_API':
+ OUTLINER_MT_editor_menus.draw_collapsible(context, layout)
- layout.prop(space, "filter_text", icon='VIEWZOOM', text="")
+ layout.separator_spacer()
- layout.separator()
+ row = layout.row(align=True)
+ row.prop(space, "filter_text", icon='VIEWZOOM', text="")
+
+ layout.separator_spacer()
+
+ row = layout.row(align=True)
+ if display_mode in {'VIEW_LAYER'}:
+ row.popover(
+ panel="OUTLINER_PT_filter",
+ text="",
+ icon='FILTER',
+ )
+ elif display_mode in {'LIBRARIES', 'ORPHAN_DATA'}:
+ row.prop(space, "use_filter_id_type", text="", icon='FILTER')
+ sub = row.row(align=True)
+ sub.active = space.use_filter_id_type
+ sub.prop(space, "filter_id_type", text="", icon_only=True)
+
+ if display_mode == 'VIEW_LAYER':
+ layout.operator("outliner.collection_new", text="", icon='GROUP').nested = True
+
+ elif display_mode == 'ORPHAN_DATA':
+ layout.operator("outliner.orphans_purge", text="Purge")
+
+ elif space.display_mode == 'DATA_API':
+ layout.separator()
- if space.display_mode == 'DATABLOCKS':
row = layout.row(align=True)
row.operator("outliner.keyingset_add_selected", icon='ZOOMIN', text="")
row.operator("outliner.keyingset_remove_selected", icon='ZOOMOUT', text="")
@@ -57,8 +83,6 @@ class OUTLINER_HT_header(Header):
else:
row = layout.row()
row.label(text="No Keying Set Active")
- elif space.display_mode == 'ORPHAN_DATA':
- layout.operator("outliner.orphans_purge")
class OUTLINER_MT_editor_menus(Menu):
@@ -72,71 +96,213 @@ class OUTLINER_MT_editor_menus(Menu):
def draw_menus(layout, context):
space = context.space_data
- layout.menu("OUTLINER_MT_view")
- layout.menu("OUTLINER_MT_search")
-
- if space.display_mode == 'DATABLOCKS':
+ if space.display_mode == 'DATA_API':
layout.menu("OUTLINER_MT_edit_datablocks")
-class OUTLINER_MT_view(Menu):
- bl_label = "View"
+class OUTLINER_MT_context(Menu):
+ bl_label = "Outliner"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("outliner.show_one_level", text="Show One Level")
+ layout.operator("outliner.show_one_level", text="Hide One Level").open = False
+ layout.operator("outliner.show_hierarchy")
+
+ layout.separator()
+
+ layout.operator("outliner.show_active")
+
+ layout.separator()
+
+ layout.menu("INFO_MT_area")
+
+
+class OUTLINER_MT_edit_datablocks(Menu):
+ bl_label = "Edit"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("outliner.keyingset_add_selected")
+ layout.operator("outliner.keyingset_remove_selected")
+
+ layout.separator()
+
+ layout.operator("outliner.drivers_add_selected")
+ layout.operator("outliner.drivers_delete_selected")
+
+
+class OUTLINER_MT_collection_view_layer(Menu):
+ bl_label = "View Layer"
def draw(self, context):
layout = self.layout
space = context.space_data
- if space.display_mode not in {'DATABLOCKS', 'USER_PREFERENCES'}:
- layout.prop(space, "use_sort_alpha")
- layout.prop(space, "show_restrict_columns")
+ layout.operator("outliner.collection_exclude_set", text="Exclude")
+ layout.operator("outliner.collection_include_set", text="Include")
+
+
+class OUTLINER_MT_collection(Menu):
+ bl_label = "Collection"
+
+ def draw(self, context):
+ layout = self.layout
+
+ space = context.space_data
+
+ layout.operator("outliner.collection_new", text="New").nested = True
+ layout.operator("outliner.collection_duplicate", text="Duplicate")
+ layout.operator("outliner.collection_delete", text="Delete").hierarchy = False
+ layout.operator("outliner.collection_delete", text="Delete Hierarchy").hierarchy = True
+
+ layout.separator()
+
+ layout.operator("outliner.collection_objects_select", text="Select Objects")
+ layout.operator("outliner.collection_objects_deselect", text="Deselect Objects")
+
+ layout.separator()
+
+ layout.operator("outliner.collection_instance", text="Instance to Scene")
+ if space.display_mode != 'VIEW_LAYER':
+ layout.operator("outliner.collection_link", text="Link to Scene")
+ layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK'
+
+ if space.display_mode == 'VIEW_LAYER':
layout.separator()
- layout.operator("outliner.show_active")
+ layout.menu("OUTLINER_MT_collection_view_layer")
- layout.operator("outliner.show_one_level", text="Show One Level")
- layout.operator("outliner.show_one_level", text="Hide One Level").open = False
- layout.operator("outliner.show_hierarchy")
+ layout.separator()
+ layout.operator_menu_enum("outliner.id_operation", "type", text="ID Data")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ OUTLINER_MT_context.draw(self, context)
-class OUTLINER_MT_search(Menu):
- bl_label = "Search"
+class OUTLINER_MT_collection_new(Menu):
+ bl_label = "Collection"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("outliner.collection_new", text="New").nested = False
+
+ layout.separator()
+
+ OUTLINER_MT_context.draw(self, context)
+
+
+class OUTLINER_MT_object(Menu):
+ bl_label = "Object"
def draw(self, context):
layout = self.layout
space = context.space_data
+ obj = context.active_object
+ object_mode = 'OBJECT' if obj is None else obj.mode
- layout.prop(space, "use_filter_case_sensitive")
- layout.prop(space, "use_filter_complete")
+ layout.operator("outliner.object_operation", text="Delete").type = 'DELETE'
+ if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection:
+ layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY'
+ layout.separator()
-class OUTLINER_MT_edit_datablocks(Menu):
- bl_label = "Edit"
+ layout.operator("outliner.object_operation", text="Select").type = 'SELECT'
+ layout.operator("outliner.object_operation", text="Select Hierarchy").type = 'SELECT_HIERARCHY'
+ layout.operator("outliner.object_operation", text="Deselect").type = 'DESELECT'
+
+ layout.separator()
+
+ if object_mode in {'EDIT', 'POSE'}:
+ name = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode].name
+ layout.operator("outliner.object_operation", text=f"{name} Set").type = 'OBJECT_MODE_ENTER'
+ layout.operator("outliner.object_operation", text=f"{name} Clear").type = 'OBJECT_MODE_EXIT'
+ del name
+
+ layout.separator()
+
+ if not (space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection):
+ layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK'
+ layout.separator()
+
+ layout.operator_menu_enum("outliner.id_operation", "type", text="ID Data")
+
+ layout.separator()
+
+ OUTLINER_MT_context.draw(self, context)
+
+
+class OUTLINER_PT_filter(Panel):
+ bl_space_type = 'OUTLINER'
+ bl_region_type = 'HEADER'
+ bl_label = "Filter"
def draw(self, context):
layout = self.layout
- layout.operator("outliner.keyingset_add_selected")
- layout.operator("outliner.keyingset_remove_selected")
+ space = context.space_data
+ display_mode = space.display_mode
+
+ layout.prop(space, "use_filter_complete", text="Exact Match Search")
+ layout.prop(space, "use_filter_case_sensitive", text="Case Sensitive Search")
layout.separator()
- layout.operator("outliner.drivers_add_selected")
- layout.operator("outliner.drivers_delete_selected")
+ if space.display_mode != 'DATA_API':
+ layout.prop(space, "use_sort_alpha")
+ layout.prop(space, "show_restrict_columns")
+ layout.separator()
+
+ col = layout.column(align=True)
+
+ col.prop(space, "use_filter_collection", text="Collections", icon='GROUP')
+ col.prop(space, "use_filter_object", text="Objects", icon='OBJECT_DATAMODE')
+
+ sub = col.column(align=True)
+ sub.active = space.use_filter_object
+
+ if bpy.data.meshes:
+ sub.prop(space, "use_filter_object_mesh", text="Meshes", icon='MESH_DATA')
+ if bpy.data.armatures:
+ sub.prop(space, "use_filter_object_armature", text="Armatures", icon='ARMATURE_DATA')
+ if bpy.data.lights:
+ sub.prop(space, "use_filter_object_light", text="Lights", icon='LIGHT_DATA')
+ if bpy.data.cameras:
+ sub.prop(space, "use_filter_object_camera", text="Cameras", icon='CAMERA_DATA')
+
+ sub.prop(space, "use_filter_object_empty", text="Empties", icon='EMPTY_DATA')
+
+ if (
+ bpy.data.curves or
+ bpy.data.metaballs or
+ bpy.data.lightprobes or
+ bpy.data.lattices or
+ bpy.data.fonts or
+ bpy.data.speakers
+ ):
+ sub.prop(space, "use_filter_object_others", text="Others")
+
+ subsub = sub.column(align=False)
+ subsub.prop(space, "filter_state", text="")
+ subsub.prop(space, "use_filter_object_content", text="Object Contents")
+ subsub.prop(space, "use_filter_children", text="Object Children")
classes = (
OUTLINER_HT_header,
OUTLINER_MT_editor_menus,
- OUTLINER_MT_view,
- OUTLINER_MT_search,
OUTLINER_MT_edit_datablocks,
+ OUTLINER_MT_collection,
+ OUTLINER_MT_collection_new,
+ OUTLINER_MT_collection_view_layer,
+ OUTLINER_MT_object,
+ OUTLINER_MT_context,
+ OUTLINER_PT_filter,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index 20cb5719e20..2d1725b2087 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -31,6 +31,7 @@ class PROPERTIES_HT_header(Header):
row = layout.row()
row.template_header()
+
row.prop(view, "context", expand=True, icon_only=True)
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index d156f822606..0bdfcc39ed9 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -79,30 +79,29 @@ class SEQUENCER_HT_header(Header):
row = layout.row(align=True)
row.template_header()
+ layout.prop(st, "view_type", text="")
+
SEQUENCER_MT_editor_menus.draw_collapsible(context, layout)
- row = layout.row(align=True)
- row.prop(scene, "use_preview_range", text="", toggle=True)
- row.prop(scene, "lock_frame_selection_to_range", text="", toggle=True)
+ if st.view_type == 'SEQUENCER':
+ layout.prop(st, "show_backdrop", text="Backdrop")
- layout.prop(st, "view_type", expand=True, text="")
+ layout.separator_spacer()
- if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
- layout.prop(st, "display_mode", expand=True, text="")
+ layout.template_running_jobs()
if st.view_type == 'SEQUENCER':
- row = layout.row(align=True)
- row.operator("sequencer.copy", text="", icon='COPYDOWN')
- row.operator("sequencer.paste", text="", icon='PASTEDOWN')
+ layout.separator()
+ layout.operator("sequencer.refresh_all")
+ if st.view_type == 'SEQUENCER_PREVIEW':
layout.separator()
layout.operator("sequencer.refresh_all")
- layout.prop(st, "show_backdrop")
- else:
- if st.view_type == 'SEQUENCER_PREVIEW':
- layout.separator()
- layout.operator("sequencer.refresh_all")
+ if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
+ layout.prop(st, "display_mode", expand=True, text="")
+
+ if st.view_type != 'SEQUENCER':
layout.prop(st, "preview_channels", expand=True, text="")
layout.prop(st, "display_channel", text="Channel")
@@ -134,7 +133,11 @@ class SEQUENCER_HT_header(Header):
props.animation = True
props.sequencer = True
- layout.template_running_jobs()
+ if st.view_type == 'SEQUENCER':
+
+ row = layout.row(align=True)
+ row.operator("sequencer.copy", text="", icon='COPYDOWN')
+ row.operator("sequencer.paste", text="", icon='PASTEDOWN')
class SEQUENCER_MT_editor_menus(Menu):
@@ -237,9 +240,7 @@ class SEQUENCER_MT_view(Menu):
layout.prop(st, "use_marker_sync")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class SEQUENCER_MT_select(Menu):
@@ -248,6 +249,12 @@ class SEQUENCER_MT_select(Menu):
def draw(self, context):
layout = self.layout
+ layout.operator("sequencer.select_all", text="All").action = 'SELECT'
+ layout.operator("sequencer.select_all", text="None").action = 'DESELECT'
+ layout.operator("sequencer.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT'
layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT'
props = layout.operator("sequencer.select", text="All Strips to the Left")
@@ -266,8 +273,6 @@ class SEQUENCER_MT_select(Menu):
layout.operator("sequencer.select_linked")
layout.operator("sequencer.select_less")
layout.operator("sequencer.select_more")
- layout.operator("sequencer.select_all").action = 'TOGGLE'
- layout.operator("sequencer.select_all", text="Inverse").action = 'INVERT'
class SEQUENCER_MT_marker(Menu):
@@ -431,10 +436,6 @@ class SEQUENCER_MT_strip(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("ed.undo")
- layout.operator("ed.redo")
- layout.operator("ed.undo_history")
-
layout.separator()
layout.menu("SEQUENCER_MT_strip_transform")
layout.operator("sequencer.snap")
@@ -1288,7 +1289,7 @@ class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsP
class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
_context_path = "scene.sequence_editor.active_strip"
_property_type = (bpy.types.Sequence,)
bl_category = "Strip"
diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py
new file mode 100644
index 00000000000..dbcfbf165ce
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_statusbar.py
@@ -0,0 +1,68 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Header
+
+
+class STATUSBAR_HT_header(Header):
+ bl_space_type = 'STATUSBAR'
+
+ def draw(self, context):
+ layout = self.layout
+
+ # input status
+ layout.template_input_status()
+
+ layout.separator_spacer()
+
+ # messages
+ layout.template_reports_banner()
+
+ row = layout.row(align=True)
+ if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False:
+ row.label("Auto-run disabled", icon='ERROR')
+ if bpy.data.is_saved:
+ props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted")
+ props.use_scripts = True
+
+ row.operator("script.autoexec_warn_clear", text="Ignore")
+
+ # include last so text doesn't push buttons out of the header
+ row.label(bpy.app.autoexec_fail_message)
+
+ layout.template_running_jobs()
+
+ layout.separator_spacer()
+
+ # stats
+ scene = context.scene
+ view_layer = context.view_layer
+
+ layout.label(text=scene.statistics(view_layer), translate=False)
+
+
+classes = (
+ STATUSBAR_HT_header,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index fc93956b14b..8e370326d8c 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -41,9 +41,13 @@ class TEXT_HT_header(Header):
sub.alert = True
sub.operator("text.resolve_conflict", text="", icon='HELP')
+ layout.separator_spacer()
+
row = layout.row(align=True)
row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open")
+ layout.separator_spacer()
+
row = layout.row(align=True)
row.prop(st, "show_line_numbers", text="")
row.prop(st, "show_word_wrap", text="")
@@ -52,17 +56,6 @@ class TEXT_HT_header(Header):
if text:
is_osl = text.name.endswith((".osl", ".osl"))
- if is_osl:
- row = layout.row()
- row.operator("node.shader_script_update")
- else:
- row = layout.row()
- row.operator("text.run_script")
-
- row = layout.row()
- row.active = text.name.endswith(".py")
- row.prop(text, "use_module")
-
row = layout.row()
if text.filepath:
if text.is_dirty:
@@ -81,6 +74,16 @@ class TEXT_HT_header(Header):
if text.library
else "Text: Internal"
)
+ if is_osl:
+ row = layout.row()
+ row.operator("node.shader_script_update")
+ else:
+ row = layout.row()
+ row.active = text.name.endswith(".py")
+ row.prop(text, "use_module")
+
+ row = layout.row()
+ row.operator("text.run_script")
class TEXT_MT_editor_menus(Menu):
@@ -186,9 +189,7 @@ class TEXT_MT_view(Menu):
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class TEXT_MT_text(Menu):
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 9026a93aa99..99e5f6b08e5 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -18,43 +18,27 @@
# <pep8 compliant>
import bpy
-from bpy.types import Header, Menu
+from bpy.types import Header, Menu, Panel
-class TIME_HT_header(Header):
- bl_space_type = 'TIMELINE'
+# Header buttons for timeline header (play, etc.)
+class TIME_HT_editor_buttons(Header):
+ bl_idname = "TIME_HT_editor_buttons"
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_label = ""
def draw(self, context):
- layout = self.layout
+ pass
+ @staticmethod
+ def draw_header(context, layout):
scene = context.scene
toolsettings = context.tool_settings
screen = context.screen
- userprefs = context.user_preferences
- row = layout.row(align=True)
- row.template_header()
-
- TIME_MT_editor_menus.draw_collapsible(context, layout)
-
- row = layout.row(align=True)
- row.prop(scene, "use_preview_range", text="", toggle=True)
- row.prop(scene, "lock_frame_selection_to_range", text="", toggle=True)
-
- row = layout.row(align=True)
- if not scene.use_preview_range:
- row.prop(scene, "frame_start", text="Start")
- row.prop(scene, "frame_end", text="End")
- else:
- row.prop(scene, "frame_preview_start", text="Start")
- row.prop(scene, "frame_preview_end", text="End")
-
- if scene.show_subframe:
- layout.prop(scene, "frame_float", text="")
- else:
- layout.prop(scene, "frame_current", text="")
+ layout.separator_spacer()
- layout.separator()
+ layout.prop(toolsettings, "use_keyframe_insert_auto", text="", toggle=True)
row = layout.row(align=True)
row.operator("screen.frame_jump", text="", icon='REW').end = False
@@ -65,37 +49,37 @@ class TIME_HT_header(Header):
# since JACK transport doesn't support reversed playback
if scene.sync_mode == 'AUDIO_SYNC' and context.user_preferences.system.audio_device == 'JACK':
sub = row.row(align=True)
- sub.scale_x = 2.0
+ sub.scale_x = 1.4
sub.operator("screen.animation_play", text="", icon='PLAY')
else:
row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
row.operator("screen.animation_play", text="", icon='PLAY')
else:
sub = row.row(align=True)
- sub.scale_x = 2.0
+ sub.scale_x = 1.4
sub.operator("screen.animation_play", text="", icon='PAUSE')
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
row.operator("screen.frame_jump", text="", icon='FF').end = True
- layout.prop(scene, "sync_mode", text="")
-
- layout.separator()
-
- row = layout.row(align=True)
- row.prop(toolsettings, "use_keyframe_insert_auto", text="", toggle=True)
- if toolsettings.use_keyframe_insert_auto:
- row.prop(toolsettings, "use_keyframe_insert_keyingset", text="", toggle=True)
-
- if screen.is_animation_playing and not userprefs.edit.use_keyframe_insert_available:
- subsub = row.row(align=True)
- subsub.prop(toolsettings, "use_record_with_nla", toggle=True)
+ layout.separator_spacer()
- layout.prop(toolsettings, "keyframe_type", text="", icon_only=True)
+ row = layout.row()
+ row.scale_x = 0.95
+ if scene.show_subframe:
+ row.prop(scene, "frame_float", text="")
+ else:
+ row.prop(scene, "frame_current", text="")
row = layout.row(align=True)
- row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="")
- row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
- row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT')
+ row.prop(scene, "use_preview_range", text="", toggle=True)
+ sub = row.row(align=True)
+ sub.scale_x = 0.8
+ if not scene.use_preview_range:
+ sub.prop(scene, "frame_start", text="Start")
+ sub.prop(scene, "frame_end", text="End")
+ else:
+ sub.prop(scene, "frame_preview_start", text="Start")
+ sub.prop(scene, "frame_preview_end", text="End")
class TIME_MT_editor_menus(Menu):
@@ -107,10 +91,20 @@ class TIME_MT_editor_menus(Menu):
@staticmethod
def draw_menus(layout, context):
- layout.menu("TIME_MT_view")
- layout.menu("TIME_MT_marker")
- layout.menu("TIME_MT_frame")
- layout.menu("TIME_MT_playback")
+ row = layout.row()
+ sub = row.row(align=True)
+ sub.popover(
+ panel="TIME_PT_playback",
+ text="Playback",
+ )
+ sub.popover(
+ panel="TIME_PT_keyframing_settings",
+ text="Keying",
+ )
+
+ sub = row.row(align=True)
+ sub.menu("TIME_MT_view")
+ sub.menu("TIME_MT_marker")
class TIME_MT_marker(Menu):
@@ -138,7 +132,6 @@ class TIME_MT_view(Menu):
layout.prop(st, "show_frame_indicator")
layout.prop(scene, "show_keys_from_selected_only")
- layout.prop(scene, "show_subframe")
layout.separator()
@@ -146,18 +139,13 @@ class TIME_MT_view(Menu):
layout.separator()
- layout.operator("time.view_all")
- layout.operator("time.view_frame")
-
- layout.separator()
-
- layout.operator("marker.camera_bind")
+ # NOTE: "action" now, since timeline is in the dopesheet editor, instead of as own editor
+ layout.operator("action.view_all")
+ layout.operator("action.view_frame")
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class TIME_MT_cache(Menu):
@@ -182,25 +170,56 @@ class TIME_MT_cache(Menu):
col.prop(st, "cache_rigidbody")
-class TIME_MT_frame(Menu):
- bl_label = "Frame"
+def marker_menu_generic(layout):
+ from bpy import context
- def draw(self, context):
- layout = self.layout
+ # layout.operator_context = 'EXEC_REGION_WIN'
- layout.operator("anim.previewrange_clear")
- layout.operator("anim.previewrange_set")
- layout.separator()
- layout.operator("time.end_frame_set")
- layout.operator("time.start_frame_set")
+ layout.column()
+ layout.operator("marker.add", "Add Marker")
+ layout.operator("marker.duplicate", text="Duplicate Marker")
- layout.separator()
+ if len(bpy.data.scenes) > 10:
+ layout.operator_context = 'INVOKE_DEFAULT'
+ layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY')
+ else:
+ layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene")
- layout.menu("TIME_MT_autokey")
+ layout.operator("marker.delete", text="Delete Marker")
+ layout.separator()
-class TIME_MT_playback(Menu):
+ layout.operator("marker.rename", text="Rename Marker")
+ layout.operator("marker.move", text="Grab/Move Marker")
+
+ layout.separator()
+
+ layout.operator("marker.camera_bind")
+
+ layout.separator()
+
+ layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
+ layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
+
+ layout.separator()
+ ts = context.tool_settings
+ layout.prop(ts, "lock_markers")
+
+###################################
+
+
+class TimelinePanelButtons:
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_region_type = 'UI'
+
+ @staticmethod
+ def has_timeline(context):
+ return context.space_data.mode == 'TIMELINE'
+
+
+class TIME_PT_playback(TimelinePanelButtons, Panel):
bl_label = "Playback"
+ bl_region_type = 'HEADER'
def draw(self, context):
layout = self.layout
@@ -208,7 +227,20 @@ class TIME_MT_playback(Menu):
screen = context.screen
scene = context.scene
- layout.prop(screen, "use_play_top_left_3d_editor")
+ layout.prop(scene, "sync_mode", text="")
+ layout.prop(scene, "use_audio_scrub")
+ layout.prop(scene, "use_audio", text="Mute Audio")
+
+ 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.separator()
+
+ col = layout.column()
+ col.label("Play Animation In:")
+ layout.prop(screen, "use_play_top_left_3d_editor", text="Active Editor Only")
layout.prop(screen, "use_play_3d_editors")
layout.prop(screen, "use_play_animation_editors")
layout.prop(screen, "use_play_properties_editors")
@@ -218,67 +250,59 @@ class TIME_MT_playback(Menu):
layout.prop(screen, "use_play_clip_editors")
layout.separator()
- layout.prop(screen, "use_follow")
- layout.separator()
- layout.prop(scene, "use_frame_drop", text="Frame Dropping")
- layout.prop(scene, "use_audio_sync", text="AV-sync", icon='SPEAKER')
- layout.prop(scene, "use_audio")
- layout.prop(scene, "use_audio_scrub")
+ row = layout.row(align=True)
+ row.operator("anim.start_frame_set")
+ row.operator("anim.end_frame_set")
-class TIME_MT_autokey(Menu):
- bl_label = "Auto-Keyframing Mode"
+class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel):
+ bl_label = "Keyframing Settings"
+ bl_options = {'HIDE_HEADER'}
+ bl_region_type = 'HEADER'
+
+ @classmethod
+ def poll(cls, context):
+ # only for timeline editor
+ return cls.has_timeline(context)
def draw(self, context):
layout = self.layout
- toolsettings = context.tool_settings
-
- layout.prop_enum(toolsettings, "auto_keying_mode", 'ADD_REPLACE_KEYS')
- layout.prop_enum(toolsettings, "auto_keying_mode", 'REPLACE_KEYS')
-
-
-def marker_menu_generic(layout):
- from bpy import context
- # layout.operator_context = 'EXEC_REGION_WIN'
-
- layout.column()
- layout.operator("marker.add", "Add Marker")
- layout.operator("marker.duplicate", text="Duplicate Marker")
-
- if len(bpy.data.scenes) > 10:
- layout.operator_context = 'INVOKE_DEFAULT'
- layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY')
- else:
- layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene")
-
- layout.operator("marker.delete", text="Delete Marker")
-
- layout.separator()
+ scene = context.scene
+ toolsettings = context.tool_settings
+ userprefs = context.user_preferences
- layout.operator("marker.rename", text="Rename Marker")
- layout.operator("marker.move", text="Grab/Move Marker")
+ col = layout.column(align=True)
+ col.label("Active Keying Set:")
+ row = col.row(align=True)
+ row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="")
+ row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
+ row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT')
- layout.separator()
+ col = layout.column(align=True)
+ col.label("New Keyframe Type:")
+ col.prop(toolsettings, "keyframe_type", text="")
- layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
- layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
+ col = layout.column(align=True)
+ col.label("Auto Keyframing:")
+ row = col.row()
+ row.prop(toolsettings, "auto_keying_mode", text="")
+ row.prop(toolsettings, "use_keyframe_insert_keyingset", text="")
+ if not userprefs.edit.use_keyframe_insert_available:
+ col.prop(toolsettings, "use_record_with_nla", text="Layered Recording")
- layout.separator()
- ts = context.tool_settings
- layout.prop(ts, "lock_markers")
+###################################
classes = (
- TIME_HT_header,
+ TIME_HT_editor_buttons,
TIME_MT_editor_menus,
TIME_MT_marker,
TIME_MT_view,
TIME_MT_cache,
- TIME_MT_frame,
- TIME_MT_playback,
- TIME_MT_autokey,
+ TIME_PT_playback,
+ TIME_PT_keyframing_settings,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
new file mode 100644
index 00000000000..ffd95ec7c64
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -0,0 +1,725 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import (
+ Menu,
+)
+
+__all__ = (
+ "ToolSelectPanelHelper",
+ "ToolDef",
+)
+
+# Support reloading icons.
+if "_icon_cache" in locals():
+ release = bpy.app.icons.release
+ for icon_value in _icon_cache.values():
+ if icon_value != 0:
+ release(icon_value)
+ del release
+
+
+# (filename -> icon_value) map
+_icon_cache = {}
+
+
+def _keymap_fn_from_seq(keymap_data):
+
+ # standalone
+ def _props_assign_recursive(rna_props, py_props):
+ for prop_id, value in py_props.items():
+ if isinstance(value, dict):
+ _props_assign_recursive(getattr(rna_props, prop_id), value)
+ else:
+ setattr(rna_props, prop_id, value)
+
+ def keymap_fn(km):
+ for op_idname, op_props_dict, kmi_kwargs in keymap_fn.keymap_data:
+ kmi = km.keymap_items.new(op_idname, **kmi_kwargs)
+ kmi_props = kmi.properties
+ if op_props_dict:
+ _props_assign_recursive(kmi.properties, op_props_dict)
+ keymap_fn.keymap_data = keymap_data
+ return keymap_fn
+
+
+def _item_is_fn(item):
+ return (not (type(item) is ToolDef) and callable(item))
+
+
+from collections import namedtuple
+ToolDef = namedtuple(
+ "ToolDef",
+ (
+ # The name to display in the interface.
+ "text",
+ # The name of the icon to use (found in ``release/datafiles/icons``) or None for no icon.
+ "icon",
+ # An optional cursor to use when this tool is active.
+ "cursor",
+ # An optional manipulator group to activate when the tool is set or None for no widget.
+ "widget",
+ # Optional keymap for tool, either:
+ # - A function that populates a keymaps passed in as an argument.
+ # - A tuple filled with triple's of:
+ # ``(operator_id, operator_properties, keymap_item_args)``.
+ #
+ # Warning: currently 'from_dict' this is a list of one item,
+ # so internally we can swap the keymap function for the keymap it's self.
+ # This isn't very nice and may change, tool definitions shouldn't care about this.
+ "keymap",
+ # Optional data-block assosiated with this tool.
+ # (Typically brush name, usage depends on mode, we could use for non-brush ID's in other modes).
+ "data_block",
+ # Optional primary operator (for introspection only).
+ "operator",
+ # Optional draw settings (operator options, toolsettings).
+ "draw_settings",
+ )
+)
+del namedtuple
+
+
+def from_dict(kw_args):
+ """
+ Use so each tool can avoid defining all members of the named tuple.
+ Also convert the keymap from a tuple into a function
+ (since keymap is a callback).
+ """
+ kw = {
+ "icon": None,
+ "cursor": None,
+ "widget": None,
+ "keymap": None,
+ "data_block": None,
+ "operator": None,
+ "draw_settings": None,
+ }
+ kw.update(kw_args)
+
+ keymap = kw["keymap"]
+ if kw["keymap"] is None:
+ pass
+ elif type(keymap) is tuple:
+ keymap = [_keymap_fn_from_seq(keymap)]
+ else:
+ keymap = [keymap]
+ kw["keymap"] = keymap
+ return ToolDef(**kw)
+
+
+def from_fn(fn):
+ """
+ Use as decorator so we can define functions.
+ """
+ return ToolDef.from_dict(fn())
+
+
+ToolDef.from_dict = from_dict
+ToolDef.from_fn = from_fn
+del from_dict
+del from_fn
+
+
+class ToolSelectPanelHelper:
+ """
+ Generic Class, can be used for any toolbar.
+
+ - keymap_prefix:
+ The text prefix for each key-map for this spaces tools.
+ - tools_all():
+ Returns (context_mode, tools) tuple pair for all tools defined.
+ - tools_from_context(context, mode=None):
+ Returns tools available in this context.
+
+ Each tool is a 'ToolDef' or None for a separator in the toolbar, use ``None``.
+ """
+
+ @staticmethod
+ def _tool_class_from_space_type(space_type):
+ return next(
+ (cls for cls in ToolSelectPanelHelper.__subclasses__()
+ if cls.bl_space_type == space_type),
+ None
+ )
+
+ @staticmethod
+ def _icon_value_from_icon_handle(icon_name):
+ import os
+ if icon_name is not None:
+ assert(type(icon_name) is str)
+ icon_value = _icon_cache.get(icon_name)
+ if icon_value is None:
+ dirname = bpy.utils.resource_path('LOCAL')
+ if not os.path.exists(dirname):
+ # TODO(campbell): use a better way of finding datafiles.
+ dirname = bpy.utils.resource_path('SYSTEM')
+ filename = os.path.join(dirname, "datafiles", "icons", icon_name + ".dat")
+ try:
+ icon_value = bpy.app.icons.new_triangles_from_file(filename)
+ except Exception as ex:
+ if not os.path.exists(filename):
+ print("Missing icons:", filename, ex)
+ else:
+ print("Corrupt icon:", filename, ex)
+ # Use none as a fallback (avoids layout issues).
+ if icon_name != "none":
+ icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle("none")
+ else:
+ icon_value = 0
+ _icon_cache[icon_name] = icon_value
+ return icon_value
+ else:
+ return 0
+
+ @staticmethod
+ def _tools_flatten(tools):
+ """
+ Flattens, skips None and calls generators.
+ """
+ for item in tools:
+ if item is None:
+ yield None
+ elif type(item) is tuple:
+ for sub_item in item:
+ if sub_item is None:
+ yield None
+ elif _item_is_fn(sub_item):
+ yield from sub_item(context)
+ else:
+ yield sub_item
+ else:
+ if _item_is_fn(item):
+ yield from item(context)
+ else:
+ yield item
+
+ @staticmethod
+ def _tools_flatten_with_tool_index(tools):
+ for item in tools:
+ if item is None:
+ yield None, -1
+ elif type(item) is tuple:
+ i = 0
+ for sub_item in item:
+ if sub_item is None:
+ yield None
+ elif _item_is_fn(sub_item):
+ for item_dyn in sub_item(context):
+ yield item_dyn, i
+ i += 1
+ else:
+ yield sub_item, i
+ i += 1
+ else:
+ if _item_is_fn(item):
+ for item_dyn in item(context):
+ yield item_dyn, -1
+ else:
+ yield item, -1
+
+ @staticmethod
+ def _tool_get_active(context, space_type, mode, with_icon=False):
+ """
+ Return the active Python tool definition and icon name.
+ """
+ workspace = context.workspace
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is not None:
+ tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode)
+ tool_active_text = getattr(tool_active, "name", None)
+ for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)):
+ if item is not None:
+ if item.text == tool_active_text:
+ if with_icon:
+ icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
+ else:
+ icon_value = 0
+ return (item, tool_active, icon_value)
+ return None, None, 0
+
+ @staticmethod
+ def _tool_get_by_name(context, space_type, text):
+ """
+ Return the active Python tool definition and index (if in sub-group, else -1).
+ """
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ if cls is not None:
+ for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)):
+ if item is not None:
+ if item.text == text:
+ return (cls, item, index)
+ return None, None, -1
+
+ @staticmethod
+ def _tool_active_from_context(context, space_type, mode=None, create=False):
+ if space_type == 'VIEW_3D':
+ if mode is None:
+ mode = context.mode
+ tool = context.workspace.tools.from_space_view3d_mode(mode, create)
+ if tool is not None:
+ return tool
+ elif space_type == 'IMAGE_EDITOR':
+ space_data = context.space_data
+ if mode is None:
+ mode = space_data.mode
+ tool = context.workspace.tools.from_space_image_mode(mode, create)
+ if tool is not None:
+ return tool
+ return None
+
+ @staticmethod
+ def _tool_text_from_button(context):
+ return context.button_operator.name
+
+ @classmethod
+ def _km_action_simple(cls, kc, context_mode, text, keymap_fn):
+ if context_mode is None:
+ context_mode = "All"
+ km_idname = f"{cls.keymap_prefix} {context_mode}, {text}"
+ km = kc.keymaps.get(km_idname)
+ if km is None:
+ km = kc.keymaps.new(km_idname, space_type=cls.bl_space_type, region_type='WINDOW')
+ keymap_fn[0](km)
+ keymap_fn[0] = km
+
+ @classmethod
+ def register(cls):
+ wm = bpy.context.window_manager
+
+ # XXX, should we be manipulating the user-keyconfig on load?
+ # Perhaps this should only add when keymap items don't already exist.
+ #
+ # This needs some careful consideration.
+ kc = wm.keyconfigs.user
+
+ # Track which tool-group was last used for non-active groups.
+ # Blender stores the active tool-group index.
+ #
+ # {tool_name_first: index_in_group, ...}
+ cls._tool_group_active = {}
+
+ # ignore in background mode
+ if kc is None:
+ return
+
+ for context_mode, tools in cls.tools_all():
+ for item_parent in tools:
+ if item_parent is None:
+ continue
+ for item in item_parent if (type(item_parent) is tuple) else (item_parent,):
+ # skip None or generator function
+ if item is None or _item_is_fn(item):
+ continue
+ keymap_data = item.keymap
+ if keymap_data is not None and callable(keymap_data[0]):
+ text = item.text
+ icon_name = item.icon
+ cls._km_action_simple(kc, context_mode, text, keymap_data)
+
+ # -------------------------------------------------------------------------
+ # Layout Generators
+ #
+ # Meaning of recieved values:
+ # - Bool: True for a separator, otherwise False for regular tools.
+ # - None: Signal to finish (complete any final operations, e.g. add padding).
+
+ @staticmethod
+ def _layout_generator_single_column(layout, scale_y):
+ col = layout.column(align=True)
+ col.scale_y = scale_y
+ is_sep = False
+ while True:
+ if is_sep is True:
+ col = layout.column(align=True)
+ col.scale_y = scale_y
+ elif is_sep is None:
+ yield None
+ return
+ is_sep = yield col
+
+ @staticmethod
+ def _layout_generator_multi_columns(layout, column_count, scale_y):
+ scale_x = scale_y * 1.1
+ column_last = column_count - 1
+
+ col = layout.column(align=True)
+
+ row = col.row(align=True)
+
+ row.scale_x = scale_x
+ row.scale_y = scale_y
+
+ is_sep = False
+ column_index = 0
+ while True:
+ if is_sep is True:
+ if column_index != column_last:
+ row.label("")
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.scale_x = scale_x
+ row.scale_y = scale_y
+ column_index = 0
+
+ is_sep = yield row
+ if is_sep is None:
+ if column_index == column_last:
+ row.label("")
+ yield None
+ return
+
+ if column_index == column_count:
+ column_index = 0
+ row = col.row(align=True)
+ row.scale_x = scale_x
+ row.scale_y = scale_y
+ column_index += 1
+
+ @staticmethod
+ def _layout_generator_detect_from_region(layout, region, scale_y):
+ """
+ Choose an appropriate layout for the toolbar.
+ """
+ # Currently this just checks the width,
+ # we could have different layouts as preferences too.
+ system = bpy.context.user_preferences.system
+ view2d = region.view2d
+ view2d_scale = (
+ view2d.region_to_view(1.0, 0.0)[0] -
+ view2d.region_to_view(0.0, 0.0)[0]
+ )
+ width_scale = region.width * view2d_scale / system.ui_scale
+
+ if width_scale > 120.0:
+ show_text = True
+ column_count = 1
+ else:
+ show_text = False
+ # 2 column layout, disabled
+ if width_scale > 80.0:
+ column_count = 2
+ use_columns = True
+ else:
+ column_count = 1
+
+ if column_count == 1:
+ ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y=scale_y)
+ else:
+ ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count, scale_y=scale_y)
+
+ return ui_gen, show_text
+
+ @classmethod
+ def draw_cls(cls, layout, context, detect_layout=True, scale_y=1.75):
+ # Use a classmethod so it can be called outside of a panel context.
+
+ # XXX, this UI isn't very nice.
+ # We might need to create new button types for this.
+ # Since we probably want:
+ # - tool-tips that include multiple key shortcuts.
+ # - ability to click and hold to expose sub-tools.
+
+ space_type = context.space_data.type
+ tool_active_text = getattr(
+ ToolSelectPanelHelper._tool_active_from_context(context, space_type),
+ "name", None,
+ )
+
+ if detect_layout:
+ ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region, scale_y)
+ else:
+ ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y)
+ show_text = True
+
+ # Start iteration
+ ui_gen.send(None)
+
+ for item in cls.tools_from_context(context):
+ if item is None:
+ ui_gen.send(True)
+ continue
+
+ if type(item) is tuple:
+ is_active = False
+ i = 0
+ for i, sub_item in enumerate(item):
+ if sub_item is None:
+ continue
+ is_active = (sub_item.text == tool_active_text)
+ if is_active:
+ index = i
+ break
+ del i, sub_item
+
+ if is_active:
+ # not ideal, write this every time :S
+ cls._tool_group_active[item[0].text] = index
+ else:
+ index = cls._tool_group_active.get(item[0].text, 0)
+
+ item = item[index]
+ use_menu = True
+ else:
+ index = -1
+ use_menu = False
+
+ is_active = (item.text == tool_active_text)
+ icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
+
+ sub = ui_gen.send(False)
+
+ if use_menu:
+ sub.operator_menu_hold(
+ "wm.tool_set_by_name",
+ text=item.text if show_text else "",
+ depress=is_active,
+ menu="WM_MT_toolsystem_submenu",
+ icon_value=icon_value,
+ ).name = item.text
+ else:
+ sub.operator(
+ "wm.tool_set_by_name",
+ text=item.text if show_text else "",
+ depress=is_active,
+ icon_value=icon_value,
+ ).name = item.text
+ # Signal to finish any remaining layout edits.
+ ui_gen.send(None)
+
+ def draw(self, context):
+ self.draw_cls(self.layout, context)
+
+ @staticmethod
+ def draw_active_tool_header(context, layout):
+ # BAD DESIGN WARNING: last used tool
+ workspace = context.workspace
+ space_type = workspace.tools_space_type
+ mode = workspace.tools_mode
+ item, tool, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True)
+ if item is None:
+ return
+ # Note: we could show 'item.text' here but it makes the layout jitter when switcuing tools.
+ layout.label(" ", icon_value=icon_value)
+ draw_settings = item.draw_settings
+ if draw_settings is not None:
+ draw_settings(context, layout, tool)
+
+
+# The purpose of this menu is to be a generic popup to select between tools
+# in cases when a single tool allows to select alternative tools.
+class WM_MT_toolsystem_submenu(Menu):
+ bl_label = ""
+
+ @staticmethod
+ def _tool_group_from_button(context):
+ # Lookup the tool definitions based on the space-type.
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(context.space_data.type)
+ if cls is not None:
+ button_text = ToolSelectPanelHelper._tool_text_from_button(context)
+ for item_group in cls.tools_from_context(context):
+ if type(item_group) is tuple:
+ for sub_item in item_group:
+ if sub_item.text == button_text:
+ return cls, item_group
+ return None, None
+
+ def draw(self, context):
+ layout = self.layout
+ layout.scale_y = 2.0
+
+ cls, item_group = self._tool_group_from_button(context)
+ if item_group is None:
+ # Should never happen, just in case
+ layout.label("Unable to find toolbar group")
+ return
+
+ for item in item_group:
+ if item is None:
+ layout.separator()
+ continue
+ icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
+ layout.operator(
+ "wm.tool_set_by_name",
+ text=item.text,
+ icon_value=icon_value,
+ ).name = item.text
+
+
+def _activate_by_item(context, space_type, item, index):
+ tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True)
+ tool.setup(
+ name=item.text,
+ keymap=item.keymap[0].name if item.keymap is not None else "",
+ cursor=item.cursor or 'DEFAULT',
+ manipulator_group=item.widget or "",
+ data_block=item.data_block or "",
+ operator=item.operator or "",
+ index=index,
+ )
+
+
+def activate_by_name(context, space_type, text):
+ cls, item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text)
+ if item is None:
+ return False
+ _activate_by_item(context, space_type, item, index)
+ return True
+
+
+def activate_by_name_or_cycle(context, space_type, text, offset=1):
+
+ # Only cycle when the active tool is activated again.
+ cls, item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text)
+ if item is None:
+ return False
+
+ tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type)
+ text_active = getattr(tool_active, "name", None)
+
+ text_current = ""
+ for item_group in cls.tools_from_context(context):
+ if type(item_group) is tuple:
+ index_current = cls._tool_group_active.get(item_group[0].text, 0)
+ ok = False
+ for i, sub_item in enumerate(item_group):
+ if sub_item.text == text:
+ text_current = item_group[index_current].text
+ break
+ if text_current:
+ break
+
+ if text_current == "":
+ return activate_by_name(context, space_type, text)
+ if text_active != text_current:
+ return activate_by_name(context, space_type, text_current)
+
+ index_found = (tool_active.index + offset) % len(item_group)
+
+ cls._tool_group_active[item_group[0].text] = index_found
+
+ item_found = item_group[index_found]
+ _activate_by_item(context, space_type, item_found, index_found)
+ return True
+
+
+def keymap_from_context(context, space_type):
+ """
+ Keymap for popup toolbar, currently generated each time.
+ """
+
+ def modifier_keywords_from_item(kmi):
+ return {
+ "any": kmi.any,
+ "shift": kmi.shift,
+ "ctrl": kmi.ctrl,
+ "alt": kmi.alt,
+ "oskey": kmi.oskey,
+ "key_modifier": kmi.key_modifier,
+ }
+
+ use_search = False # allows double tap
+ use_simple_keymap = False
+
+ km_name = "Toolbar Popup"
+ wm = context.window_manager
+ keyconf = wm.keyconfigs.active
+ keymap = keyconf.keymaps.get(km_name)
+ if keymap is None:
+ keymap = keyconf.keymaps.new(km_name, space_type='EMPTY', region_type='TEMPORARY')
+ for kmi in keymap.keymap_items:
+ keymap.keymap_items.remove(kmi)
+
+ if use_search:
+ kmi_search = wm.keyconfigs.find_item_from_operator(idname="wm.toolbar")[1]
+ kmi_search_type = None if not kmi_search else kmi_search.type
+
+ items = []
+ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
+ for i, item in enumerate(
+ ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context))
+ ):
+ if item is not None:
+ if use_simple_keymap:
+ # Simply assign a key from A-Z
+ items.append(((chr(ord('A') + i)), item.text))
+ kmi = keymap.keymap_items.new("wm.tool_set_by_name", key, 'PRESS')
+ kmi.properties.name = item.text
+ continue
+
+ # Only check the first item in the tools key-map (a little arbitrary).
+ if item.operator is not None:
+ kmi_found = wm.keyconfigs.find_item_from_operator(
+ idname=item.operator,
+ )[1]
+ elif item.keymap is not None:
+ kmi_first = item.keymap[0].keymap_items[0]
+ kmi_found = wm.keyconfigs.find_item_from_operator(
+ idname=kmi_first.idname,
+ # properties=kmi_first.properties, # prevents matches, don't use.
+ )[1]
+ del kmi_first
+ else:
+ kmi_found = None
+
+ if kmi_found is not None:
+ kmi_found_type = kmi_found.type
+ # Only for single keys.
+ if len(kmi_found_type) == 1:
+ kmi = keymap.keymap_items.new(
+ idname="wm.tool_set_by_name",
+ type=kmi_found_type,
+ value='PRESS',
+ **modifier_keywords_from_item(kmi_found),
+ )
+ kmi.properties.name = item.text
+
+ if use_search:
+ # Disallow overlap
+ if kmi_search_type == kmi_found_type:
+ kmi_search_type = None
+
+ if use_search:
+ # Support double-tap for search.
+ if kmi_search_type:
+ keymap.keymap_items.new("wm.search_menu", type=kmi_search_type, value='PRESS')
+ else:
+ # The shortcut will show, so we better support running it.
+ kmi_search = wm.keyconfigs.find_item_from_operator(idname="wm.search_menu")[1]
+ if kmi_search:
+ keymap.keymap_items.new(
+ "wm.search_menu",
+ type=kmi_search.type,
+ value='PRESS',
+ **modifier_keywords_from_item(kmi_search),
+ )
+
+ wm.keyconfigs.update()
+ return keymap
+
+
+classes = (
+ WM_MT_toolsystem_submenu,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
new file mode 100644
index 00000000000..527dfdc3c6f
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -0,0 +1,1089 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# For now group all tools together
+# we may want to move these into per space-type files.
+#
+# For now keep this in a single file since it's an area that may change,
+# so avoid making changes all over the place.
+
+from bpy.types import Panel
+
+from .space_toolsystem_common import (
+ ToolSelectPanelHelper,
+ ToolDef,
+)
+
+
+def generate_from_brushes_ex(
+ context, *,
+ icon_prefix,
+ brush_test_attr,
+ brush_category_attr,
+ brush_category_layout,
+):
+ # Categories
+ brush_categories = {}
+ for brush in context.blend_data.brushes:
+ if getattr(brush, brush_test_attr):
+ category = getattr(brush, brush_category_attr)
+ name = brush.name
+ brush_categories.setdefault(category, []).append(
+ ToolDef.from_dict(
+ dict(
+ text=name,
+ icon=icon_prefix + category.lower(),
+ data_block=name,
+ )
+ )
+ )
+
+ def tools_from_brush_group(groups):
+ assert(type(groups) is tuple)
+ if len(groups) == 1:
+ tool_defs = tuple(brush_categories.pop(groups[0], ()))
+ else:
+ tool_defs = tuple(item for g in groups for item in brush_categories.pop(g, ()))
+ if len(tool_defs) > 1:
+ return (tool_defs,)
+ else:
+ return tool_defs
+
+ # Each item below is a single toolbar entry:
+ # Grouped for multiple or none if no brushes are found.
+ tool_defs = tuple(
+ tool_def
+ for category in brush_category_layout
+ for tool_def in tools_from_brush_group(category)
+ )
+ # Ensure we use all types.
+ if brush_categories:
+ print(brush_categories)
+ assert(len(brush_categories) == 0)
+ return tool_defs
+
+
+class _defs_view3d_generic:
+ @ToolDef.from_fn
+ def cursor():
+ def draw_settings(context, layout, tool):
+ wm = context.window_manager
+ props = tool.operator_properties("view3d.cursor3d")
+ layout.prop(props, "use_depth")
+ layout.prop(props, "orientation")
+
+ return dict(
+ text="Cursor",
+ icon="ops.generic.cursor",
+ keymap=(
+ ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ("transform.translate",
+ dict(release_confirm=True, cursor_transform=True),
+ dict(type='EVT_TWEAK_A', value='ANY'),
+ ),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def cursor_click():
+ return dict(
+ text="None",
+ icon="ops.generic.cursor",
+ keymap=(
+ # This is a dummy keymap entry, until particle system is properly working with toolsystem.
+ ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK', ctrl=True, alt=True, shift=True)),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def ruler():
+ return dict(
+ text="Ruler",
+ icon="ops.view3d.ruler",
+ widget="VIEW3D_WGT_ruler",
+ keymap=(
+ ("view3d.ruler_add", dict(), dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+
+class _defs_transform:
+
+ @ToolDef.from_fn
+ def translate():
+ return dict(
+ text="Grab",
+ # cursor='SCROLL_XY',
+ icon="ops.transform.translate",
+ widget="TRANSFORM_WGT_manipulator",
+ operator="transform.translate",
+ # TODO, implement as optional fallback manipulator
+ # keymap=(
+ # ("transform.translate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),
+ # ),
+ )
+
+ @ToolDef.from_fn
+ def rotate():
+ return dict(
+ text="Rotate",
+ # cursor='SCROLL_XY',
+ icon="ops.transform.rotate",
+ widget="TRANSFORM_WGT_manipulator",
+ operator="transform.rotate",
+ # TODO, implement as optional fallback manipulator
+ # keymap=(
+ # ("transform.rotate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),
+ # ),
+ )
+
+ @ToolDef.from_fn
+ def scale():
+ return dict(
+ text="Scale",
+ # cursor='SCROLL_XY',
+ icon="ops.transform.resize",
+ widget="TRANSFORM_WGT_manipulator",
+ operator="transform.resize",
+ # TODO, implement as optional fallback manipulator
+ # keymap=(
+ # ("transform.resize", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),
+ # ),
+ )
+
+ @ToolDef.from_fn
+ def scale_cage():
+ return dict(
+ text="Scale Cage",
+ icon="ops.transform.resize.cage",
+ widget="VIEW3D_WGT_xform_cage",
+ operator="transform.resize",
+ )
+
+ @ToolDef.from_fn
+ def transform():
+ def draw_settings(context, layout, tool):
+ tool_settings = context.tool_settings
+ layout.prop(tool_settings, "use_manipulator_mode")
+
+ return dict(
+ text="Transform",
+ icon="ops.transform.transform",
+ widget="TRANSFORM_WGT_manipulator",
+ # No keymap default action, only for manipulators!
+ draw_settings=draw_settings,
+ )
+
+
+class _defs_view3d_select:
+
+ @ToolDef.from_fn
+ def border():
+ return dict(
+ text="Select Border",
+ icon="ops.generic.select_border",
+ widget=None,
+ keymap=(
+ ("view3d.select_border",
+ dict(deselect=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ("view3d.select_border",
+ dict(deselect=True),
+ dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def circle():
+ return dict(
+ text="Select Circle",
+ icon="ops.generic.select_circle",
+ widget=None,
+ keymap=(
+ ("view3d.select_circle",
+ dict(deselect=False),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ("view3d.select_circle",
+ dict(deselect=True),
+ dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def lasso():
+ return dict(
+ text="Select Lasso",
+ icon="ops.generic.select_lasso",
+ widget=None,
+ keymap=(
+ ("view3d.select_lasso",
+ dict(deselect=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ("view3d.select_lasso",
+ dict(deselect=True),
+ dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
+ ),
+ )
+# -----------------------------------------------------------------------------
+# Object Modes (named based on context.mode)
+
+
+class _defs_edit_armature:
+
+ @ToolDef.from_fn
+ def roll():
+ return dict(
+ text="Roll",
+ icon="ops.armature.bone.roll",
+ widget=None,
+ keymap=(
+ ("transform.transform",
+ dict(release_confirm=True, mode='BONE_ROLL'),
+ dict(type='EVT_TWEAK_A', value='ANY'),),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def bone_envelope():
+ return dict(
+ text="Bone Envelope",
+ icon="ops.transform.bone_envelope",
+ widget=None,
+ keymap=(
+ ("transform.transform",
+ dict(release_confirm=True, mode='BONE_ENVELOPE'),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def bone_size():
+ return dict(
+ text="Bone Size",
+ icon="ops.transform.bone_size",
+ widget=None,
+ keymap=(
+ ("transform.transform",
+ dict(release_confirm=True, mode='BONE_SIZE'),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def extrude():
+ return dict(
+ text="Extrude",
+ icon="ops.armature.extrude_move",
+ widget=None,
+ keymap=(
+ ("armature.click_extrude", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def extrude_cursor():
+ return dict(
+ text="Extrude to Cursor",
+ icon="ops.armature.extrude_cursor",
+ widget=None,
+ keymap=(
+ ("armature.click_extrude", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+
+class _defs_edit_mesh:
+
+ @ToolDef.from_fn
+ def cube_add():
+ return dict(
+ text="Add Cube",
+ icon="ops.mesh.primitive_cube_add_manipulator",
+ widget=None,
+ keymap=(
+ ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK')),
+ ("mesh.primitive_cube_add_manipulator", dict(), dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def rip_region():
+ def draw_settings(context, layout, tool):
+ wm = context.window_manager
+ props = tool.operator_properties("mesh.rip_move")
+ props_macro = props.MESH_OT_rip
+ layout.prop(props_macro, "use_fill")
+
+ return dict(
+ text="Rip Region",
+ icon="ops.mesh.rip",
+ widget=None,
+ keymap=(
+ ("mesh.rip_move",
+ dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def rip_edge():
+ return dict(
+ text="Rip Edge",
+ icon="ops.mesh.rip_edge",
+ widget=None,
+ keymap=(
+ ("mesh.rip_edge_edge_move", dict(),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def poly_build():
+ return dict(
+ text="Poly Build",
+ icon="ops.mesh.polybuild_hover",
+ widget=None,
+ keymap=(
+ ("mesh.polybuild_face_at_cursor_move",
+ dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ("mesh.polybuild_split_at_cursor_move",
+ dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
+ dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
+ ("mesh.polybuild_dissolve_at_cursor", dict(), dict(type='ACTIONMOUSE', value='CLICK', alt=True)),
+ ("mesh.polybuild_hover", dict(use_boundary=False), dict(type='MOUSEMOVE', value='ANY', alt=True)),
+ ("mesh.polybuild_hover", dict(use_boundary=True), dict(type='MOUSEMOVE', value='ANY', any=True)),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def edge_slide():
+ return dict(
+ text="Edge Slide",
+ icon="ops.transform.edge_slide",
+ widget=None,
+ keymap=(
+ ("transform.edge_slide", dict(release_confirm=True),
+ dict(type='ACTIONMOUSE', value='PRESS')
+ ),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def vert_slide():
+ return dict(
+ text="Vertex Slide",
+ icon="ops.transform.vert_slide",
+ widget=None,
+ keymap=(
+ ("transform.vert_slide", dict(release_confirm=True),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def spin():
+ return dict(
+ text="Spin",
+ icon="ops.mesh.spin",
+ widget=None,
+ keymap=(
+ ("mesh.spin", dict(),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def spin_duplicate():
+ return dict(
+ text="Spin (Duplicate)",
+ icon="ops.mesh.spin.duplicate",
+ widget=None,
+ keymap=(
+ ("mesh.spin", dict(dupli=True),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def inset():
+ def draw_settings(context, layout, tool):
+ wm = context.window_manager
+ props = tool.operator_properties("mesh.inset")
+ layout.prop(props, "use_outset")
+ layout.prop(props, "use_individual")
+ layout.prop(props, "use_even_offset")
+ layout.prop(props, "use_relative_offset")
+
+ return dict(
+ text="Inset Faces",
+ icon="ops.mesh.inset",
+ widget=None,
+ keymap=(
+ ("mesh.inset", dict(release_confirm=True),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def bevel():
+ return dict(
+ text="Bevel",
+ icon="ops.mesh.bevel",
+ widget=None,
+ keymap=(
+ ("mesh.bevel", dict(),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def extrude():
+ return dict(
+ text="Extrude Region",
+ icon="ops.mesh.extrude_region_move",
+ widget="MESH_WGT_extrude",
+ operator="view3d.edit_mesh_extrude_move_normal",
+ keymap=(
+ ("mesh.extrude_context_move", dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def extrude_individual():
+ return dict(
+ text="Extrude Individual",
+ icon="ops.mesh.extrude_faces_move",
+ widget=None,
+ keymap=(
+ ("mesh.extrude_faces_move", dict(TRANSFORM_OT_shrink_fatten=dict(release_confirm=True)),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def extrude_cursor():
+ return dict(
+ text="Extrude to Cursor",
+ icon="ops.mesh.dupli_extrude_cursor",
+ widget=None,
+ keymap=(
+ ("mesh.dupli_extrude_cursor", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def loopcut_slide():
+ return dict(
+ text="Loop Cut",
+ icon="ops.mesh.loopcut_slide",
+ widget=None,
+ keymap=(
+ ("mesh.loopcut_slide", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def offset_edge_loops_slide():
+ return dict(
+ text="Offset Edge Loop Cut",
+ icon="ops.mesh.offset_edge_loops_slide",
+ widget=None,
+ keymap=(
+ ("mesh.offset_edge_loops_slide", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def vertex_smooth():
+ return dict(
+ text="Smooth",
+ icon="ops.mesh.vertices_smooth",
+ widget=None,
+ keymap=(
+ ("mesh.vertices_smooth", dict(),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def vertex_randomize():
+ return dict(
+ text="Randomize",
+ icon="ops.transform.vertex_random",
+ widget=None,
+ keymap=(
+ ("transform.vertex_random", dict(),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def shrink_fatten():
+ def draw_settings(context, layout, tool):
+ wm = context.window_manager
+ props = tool.operator_properties("transform.shrink_fatten")
+ layout.prop(props, "use_even_offset")
+
+ return dict(
+ text="Shrink/Fatten",
+ icon="ops.transform.shrink_fatten",
+ widget=None,
+ keymap=(
+ ("transform.shrink_fatten", dict(release_confirm=True),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def push_pull():
+ return dict(
+ text="Push/Pull",
+ icon="ops.transform.push_pull",
+ widget=None,
+ keymap=(
+ ("transform.push_pull", dict(release_confirm=True),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def knife():
+ def draw_settings(context, layout, tool):
+ wm = context.window_manager
+ props = tool.operator_properties("mesh.knife_tool")
+ layout.prop(props, "use_occlude_geometry")
+ layout.prop(props, "only_selected")
+
+ return dict(
+ text="Knife",
+ icon="ops.mesh.knife_tool",
+ widget=None,
+ keymap=(
+ ("mesh.knife_tool",
+ dict(wait_for_input=False),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def bisect():
+ return dict(
+ text="Bisect",
+ icon="ops.mesh.bisect",
+ widget=None,
+ keymap=(
+ ("mesh.bisect",
+ dict(),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ )
+
+
+class _defs_edit_curve:
+
+ @ToolDef.from_fn
+ def draw():
+ def draw_settings(context, layout, tool):
+ # Tool settings initialize operator options.
+ tool_settings = context.tool_settings
+ cps = tool_settings.curve_paint_settings
+
+ col = layout.row()
+
+ col.prop(cps, "curve_type")
+
+ if cps.curve_type == 'BEZIER':
+ col.prop(cps, "error_threshold")
+ col.prop(cps, "fit_method")
+ col.prop(cps, "use_corners_detect")
+
+ col = layout.row()
+ col.active = cps.use_corners_detect
+ col.prop(cps, "corner_angle")
+
+ return dict(
+ text="Draw",
+ cursor='PAINT_BRUSH',
+ icon=None,
+ widget=None,
+ keymap=(
+ ("curve.draw", dict(wait_for_input=False), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+ @ToolDef.from_fn
+ def extrude_cursor():
+ return dict(
+ text="Extrude Cursor",
+ icon=None,
+ widget=None,
+ keymap=(
+ ("curve.vertex_add", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+
+class _defs_pose:
+
+ @ToolDef.from_fn
+ def breakdown():
+ return dict(
+ text="Breakdowner",
+ icon="ops.pose.breakdowner",
+ widget=None,
+ keymap=(
+ ("pose.breakdown", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def push():
+ return dict(
+ text="Push",
+ icon="ops.pose.push",
+ widget=None,
+ keymap=(
+ ("pose.push", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def relax():
+ return dict(
+ text="Relax",
+ icon="ops.pose.relax",
+ widget=None,
+ keymap=(
+ ("pose.relax", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+
+class _defs_sculpt:
+
+ @staticmethod
+ def generate_from_brushes(context):
+ return generate_from_brushes_ex(
+ context,
+ icon_prefix="brush.sculpt.",
+ brush_test_attr="use_paint_sculpt",
+ brush_category_attr="sculpt_tool",
+ brush_category_layout=(
+ ('DRAW',),
+ ('GRAB', 'THUMB'),
+ ('SNAKE_HOOK',),
+ ('BLOB', 'INFLATE'),
+ ('SMOOTH', 'SCRAPE', 'FLATTEN'),
+ ('CREASE', 'PINCH'),
+ ('CLAY', 'CLAY_STRIPS'),
+ ('LAYER',),
+ ('NUDGE', 'ROTATE'),
+ ('FILL',),
+ ('SIMPLIFY',),
+ ('MASK',),
+ )
+ )
+
+
+class _defs_vertex_paint:
+
+ @staticmethod
+ def generate_from_brushes(context):
+ return generate_from_brushes_ex(
+ context,
+ icon_prefix="brush.paint_vertex.",
+ brush_test_attr="use_paint_vertex",
+ brush_category_attr="vertex_tool",
+ brush_category_layout=(
+ ('MIX',),
+ ('BLUR', 'AVERAGE'),
+ ('SMEAR',),
+ (
+ 'ADD', 'SUB', 'MUL', 'LIGHTEN', 'DARKEN',
+ 'COLORDODGE', 'DIFFERENCE', 'SCREEN', 'HARDLIGHT',
+ 'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY',
+ 'SATURATION', 'HUE', 'ERASE_ALPHA', 'ADD_ALPHA',
+ ),
+ )
+ )
+
+
+class _defs_texture_paint:
+
+ @staticmethod
+ def generate_from_brushes(context):
+ return generate_from_brushes_ex(
+ context,
+ icon_prefix="brush.paint_texture.",
+ brush_test_attr="use_paint_image",
+ brush_category_attr="image_tool",
+ brush_category_layout=(
+ ('DRAW',),
+ ('SOFTEN',),
+ ('SMEAR',),
+ ('CLONE',),
+ ('FILL',),
+ ('MASK',),
+ )
+ )
+
+
+class _defs_weight_paint:
+
+ @staticmethod
+ def generate_from_brushes(context):
+ return generate_from_brushes_ex(
+ context,
+ icon_prefix="brush.paint_weight.",
+ brush_test_attr="use_paint_weight",
+ brush_category_attr="vertex_tool",
+ brush_category_layout=(
+ ('MIX',),
+ ('BLUR', 'AVERAGE'),
+ ('SMEAR',),
+ (
+ 'ADD', 'SUB', 'MUL', 'LIGHTEN', 'DARKEN',
+ 'COLORDODGE', 'DIFFERENCE', 'SCREEN', 'HARDLIGHT',
+ 'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY',
+ 'SATURATION', 'HUE',
+ ),
+ )
+ )
+
+ @ToolDef.from_fn
+ def sample_weight():
+ return dict(
+ text="Sample Weight",
+ icon="ops.paint.weight_sample",
+ widget=None,
+ keymap=(
+ ("paint.weight_sample", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def sample_weight_group():
+ return dict(
+ text="Sample Vertex Group",
+ icon="ops.paint.weight_sample_group",
+ widget=None,
+ keymap=(
+ ("paint.weight_sample_group", dict(), dict(type='ACTIONMOUSE', value='PRESS')),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def gradient():
+ def draw_settings(context, layout, tool):
+ wm = context.window_manager
+ props = tool.operator_properties("paint.weight_gradient")
+ layout.prop(props, "type")
+
+ return dict(
+ text="Gradient",
+ icon="ops.paint.weight_gradient",
+ widget=None,
+ keymap=(
+ ("paint.weight_gradient", dict(), dict(type='EVT_TWEAK_A', value='ANY')),
+ ),
+ draw_settings=draw_settings,
+ )
+
+
+class _defs_uv_select:
+
+ @ToolDef.from_fn
+ def border():
+ return dict(
+ text="Select Border",
+ icon="ops.generic.select_border",
+ widget=None,
+ keymap=(
+ ("uv.select_border",
+ dict(deselect=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ # ("uv.select_border",
+ # dict(deselect=True),
+ # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def circle():
+ return dict(
+ text="Select Circle",
+ icon="ops.generic.select_circle",
+ widget=None,
+ keymap=(
+ ("uv.select_circle",
+ dict(), # dict(deselect=False),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ # ("uv.select_circle",
+ # dict(deselect=True),
+ # dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
+ ),
+ )
+
+ @ToolDef.from_fn
+ def lasso():
+ return dict(
+ text="Select Lasso",
+ icon="ops.generic.select_lasso",
+ widget=None,
+ keymap=(
+ ("uv.select_lasso",
+ dict(deselect=False),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ # ("uv.select_lasso",
+ # dict(deselect=True),
+ # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
+ ),
+ )
+
+
+class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'TOOLS'
+ bl_category = "Tools"
+ bl_label = "Tools" # not visible
+ bl_options = {'HIDE_HEADER'}
+
+ # Satisfy the 'ToolSelectPanelHelper' API.
+ keymap_prefix = "Image Editor Tool:"
+
+ @classmethod
+ def tools_from_context(cls, context, mode=None):
+ if mode is None:
+ mode = context.space_data.mode
+ for tools in (cls._tools[None], cls._tools.get(mode, ())):
+ for item in tools:
+ if not (type(item) is ToolDef) and callable(item):
+ yield from item(context)
+ else:
+ yield item
+
+ @classmethod
+ def tools_all(cls):
+ yield from cls._tools.items()
+
+ # for reuse
+ _tools_select = (
+ (
+ _defs_uv_select.border,
+ _defs_uv_select.circle,
+ _defs_uv_select.lasso,
+ ),
+ )
+
+ _tools = {
+ None: [
+ # for all modes
+ ],
+ 'VIEW': [
+ *_tools_select,
+
+ ],
+ 'MASK': [
+ None,
+ ],
+ 'PAINT': [
+ _defs_texture_paint.generate_from_brushes,
+ ],
+ }
+
+
+class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_category = "Tools"
+ bl_label = "Tools" # not visible
+ bl_options = {'HIDE_HEADER'}
+
+ # Satisfy the 'ToolSelectPanelHelper' API.
+ keymap_prefix = "3D View Tool:"
+
+ @classmethod
+ def tools_from_context(cls, context, mode=None):
+ if mode is None:
+ mode = context.mode
+ for tools in (cls._tools[None], cls._tools.get(mode, ())):
+ for item in tools:
+ if not (type(item) is ToolDef) and callable(item):
+ yield from item(context)
+ else:
+ yield item
+
+ @classmethod
+ def tools_all(cls):
+ yield from cls._tools.items()
+
+ # for reuse
+ _tools_transform = (
+ _defs_transform.transform,
+ _defs_transform.translate,
+ _defs_transform.rotate,
+ (
+ _defs_transform.scale,
+ _defs_transform.scale_cage,
+ ),
+ None,
+ _defs_view3d_generic.ruler,
+ )
+
+ _tools_select = (
+ (
+ _defs_view3d_select.border,
+ _defs_view3d_select.circle,
+ _defs_view3d_select.lasso,
+ ),
+ )
+
+ _tools = {
+ None: [
+ _defs_view3d_generic.cursor,
+ # End group.
+ ],
+ 'OBJECT': [
+ *_tools_select,
+ None,
+ *_tools_transform,
+ ],
+ 'POSE': [
+ *_tools_select,
+ *_tools_transform,
+ None,
+ (
+ _defs_pose.breakdown,
+ _defs_pose.push,
+ _defs_pose.relax,
+ )
+ ],
+ 'EDIT_ARMATURE': [
+ *_tools_select,
+ None,
+ *_tools_transform,
+ _defs_edit_armature.roll,
+ (
+ _defs_edit_armature.bone_size,
+ _defs_edit_armature.bone_envelope,
+ ),
+ None,
+ (
+ _defs_edit_armature.extrude,
+ _defs_edit_armature.extrude_cursor,
+ )
+ ],
+ 'EDIT_MESH': [
+ *_tools_select,
+ None,
+ *_tools_transform,
+ None,
+ _defs_edit_mesh.cube_add,
+ None,
+ (
+ _defs_edit_mesh.extrude,
+ _defs_edit_mesh.extrude_individual,
+ _defs_edit_mesh.extrude_cursor,
+ ),
+ _defs_edit_mesh.inset,
+ _defs_edit_mesh.bevel,
+ (
+ _defs_edit_mesh.loopcut_slide,
+ _defs_edit_mesh.offset_edge_loops_slide,
+ ),
+ (
+ _defs_edit_mesh.knife,
+ _defs_edit_mesh.bisect,
+ ),
+ _defs_edit_mesh.poly_build,
+ (
+ _defs_edit_mesh.spin,
+ _defs_edit_mesh.spin_duplicate,
+ ),
+ (
+ _defs_edit_mesh.vertex_smooth,
+ _defs_edit_mesh.vertex_randomize,
+ ),
+ (
+ _defs_edit_mesh.edge_slide,
+ _defs_edit_mesh.vert_slide,
+ ),
+ (
+ _defs_edit_mesh.shrink_fatten,
+ _defs_edit_mesh.push_pull,
+ ),
+ (
+ _defs_edit_mesh.rip_region,
+ _defs_edit_mesh.rip_edge,
+ ),
+ ],
+ 'EDIT_CURVE': [
+ *_tools_select,
+ None,
+ *_tools_transform,
+ None,
+ _defs_edit_curve.draw,
+ _defs_edit_curve.extrude_cursor,
+ ],
+ 'PARTICLE': [
+ # TODO(campbell): use cursor click tool to allow paint tools to run,
+ # we need to integrate particle system tools properly.
+ _defs_view3d_generic.cursor_click,
+ ],
+ 'SCULPT': [
+ _defs_sculpt.generate_from_brushes,
+ ],
+ 'PAINT_TEXTURE': [
+ _defs_texture_paint.generate_from_brushes,
+ ],
+ 'PAINT_VERTEX': [
+ _defs_vertex_paint.generate_from_brushes,
+ ],
+ 'PAINT_WEIGHT': [
+ _defs_weight_paint.generate_from_brushes,
+ None,
+ _defs_weight_paint.sample_weight,
+ _defs_weight_paint.sample_weight_group,
+ None,
+ # TODO, override brush events
+ *_tools_select,
+ None,
+ _defs_weight_paint.gradient,
+ ],
+ }
+
+
+classes = (
+ IMAGE_PT_tools_active,
+ VIEW3D_PT_tools_active,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
new file mode 100644
index 00000000000..96ef2e51e60
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -0,0 +1,600 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Header, Menu, Panel
+
+
+class TOPBAR_HT_upper_bar(Header):
+ bl_space_type = 'TOPBAR'
+
+ def draw(self, context):
+ region = context.region
+
+ if region.alignment == 'RIGHT':
+ self.draw_right(context)
+ else:
+ self.draw_left(context)
+
+ def draw_left(self, context):
+ layout = self.layout
+
+ window = context.window
+ screen = context.screen
+
+ layout.operator("wm.splash", text="", icon='BLENDER', emboss=False)
+
+ INFO_MT_editor_menus.draw_collapsible(context, layout)
+
+ layout.separator()
+
+ if not screen.show_fullscreen:
+ layout.template_ID_tabs(
+ window, "workspace",
+ new="workspace.workspace_add_menu",
+ unlink="workspace.workspace_delete",
+ )
+ else:
+ layout.operator(
+ "screen.back_to_previous",
+ icon='SCREEN_BACK',
+ text="Back to Previous",
+ )
+
+ def draw_right(self, context):
+ layout = self.layout
+
+ window = context.window
+ scene = window.scene
+
+ # Active workspace view-layer is retrieved through window, not through workspace.
+ layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete")
+
+ row = layout.row(align=True)
+ row.template_search(
+ window, "view_layer",
+ scene, "view_layers",
+ new="scene.view_layer_add",
+ unlink="scene.view_layer_remove")
+
+
+class TOPBAR_HT_lower_bar(Header):
+ bl_space_type = 'TOPBAR'
+ bl_region_type = 'WINDOW'
+
+ def draw(self, context):
+ layout = self.layout
+ region = context.region
+
+ if region.alignment == 'LEFT':
+ self.draw_left(context)
+ elif region.alignment == 'RIGHT':
+ self.draw_right(context)
+ else:
+ self.draw_center(context)
+
+ def draw_left(self, context):
+ layout = self.layout
+ mode = context.mode
+
+ # Active Tool
+ # -----------
+ from .space_toolsystem_common import ToolSelectPanelHelper
+ ToolSelectPanelHelper.draw_active_tool_header(context, layout)
+
+ # Object Mode Options
+ # -------------------
+
+ # Example of how toolsettings can be accessed as pop-overs.
+
+ # TODO(campbell): editing options should be after active tool options
+ # (obviously separated for from the users POV)
+ draw_fn = getattr(_draw_left_context_mode, mode, None)
+ if draw_fn is not None:
+ draw_fn(context, layout)
+
+ # Note: general mode options should be added to 'draw_right'.
+ if mode == 'SCULPT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+ elif mode == 'PAINT_VERTEX':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+ elif mode == 'PAINT_WEIGHT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+ elif mode == 'PAINT_TEXTURE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+ elif mode == 'EDIT_ARMATURE':
+ pass
+ elif mode == 'EDIT_CURVE':
+ pass
+ elif mode == 'EDIT_MESH':
+ pass
+ elif mode == 'POSE':
+ pass
+ elif mode == 'PARTICLE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+
+ def draw_center(self, context):
+ pass
+
+ def draw_right(self, context):
+ layout = self.layout
+
+ # General options, note, these _could_ display at the RHS of the draw_left callback.
+ # we just want them not to be confused with tool options.
+ mode = context.mode
+
+ if mode == 'SCULPT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".sculpt_mode", category="")
+ elif mode == 'PAINT_VERTEX':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".vertexpaint", category="")
+ elif mode == 'PAINT_WEIGHT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".weightpaint", category="")
+ elif mode == 'PAINT_TEXTURE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".imagepaint", category="")
+ elif mode == 'EDIT_TEXT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".text_edit", category="")
+ elif mode == 'EDIT_ARMATURE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".armature_edit", category="")
+ elif mode == 'EDIT_METABALL':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mball_edit", category="")
+ elif mode == 'EDIT_LATTICE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".lattice_edit", category="")
+ elif mode == 'EDIT_CURVE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".curve_edit", category="")
+ elif mode == 'EDIT_MESH':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mesh_edit", category="")
+ elif mode == 'POSE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".posemode", category="")
+ elif mode == 'PARTICLE':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="")
+ elif mode == 'OBJECT':
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="")
+
+
+class _draw_left_context_mode:
+ @staticmethod
+ def SCULPT(context, layout):
+ brush = context.tool_settings.sculpt.brush
+ if brush is None:
+ return
+
+ from .properties_paint_common import UnifiedPaintPanel
+
+ UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius")
+ UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength")
+ layout.prop(brush, "direction", text="", expand=True)
+
+ def PAINT_TEXTURE(context, layout):
+ brush = context.tool_settings.vertex_paint.brush
+ if brush is None:
+ return
+
+ from .properties_paint_common import UnifiedPaintPanel
+
+ layout.prop(brush, "color", text="")
+ UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius")
+ UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength")
+
+ def PAINT_VERTEX(context, layout):
+ brush = context.tool_settings.vertex_paint.brush
+ if brush is None:
+ return
+
+ from .properties_paint_common import UnifiedPaintPanel
+
+ layout.prop(brush, "color", text="")
+ UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius")
+ UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength")
+
+ def PAINT_WEIGHT(context, layout):
+ brush = context.tool_settings.weight_paint.brush
+ if brush is None:
+ return
+
+ from .properties_paint_common import UnifiedPaintPanel
+
+ UnifiedPaintPanel.prop_unified_weight(layout, context, brush, "weight", slider=True, text="Weight")
+ UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius")
+ UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength")
+
+
+class INFO_MT_editor_menus(Menu):
+ bl_idname = "INFO_MT_editor_menus"
+ bl_label = ""
+
+ def draw(self, context):
+ self.draw_menus(self.layout, context)
+
+ @staticmethod
+ def draw_menus(layout, context):
+ layout.menu("INFO_MT_file")
+ layout.menu("INFO_MT_edit")
+
+ layout.menu("INFO_MT_render")
+
+ layout.menu("INFO_MT_window")
+ layout.menu("INFO_MT_help")
+
+
+class INFO_MT_file(Menu):
+ bl_label = "File"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_AREA'
+ layout.operator("wm.read_homefile", text="New", icon='NEW')
+ layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
+ layout.menu("INFO_MT_file_open_recent")
+ layout.operator("wm.revert_mainfile")
+ layout.operator("wm.recover_last_session")
+ layout.operator("wm.recover_auto_save", text="Recover Auto Save...")
+
+ layout.separator()
+
+ layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA'
+ layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK')
+
+ layout.operator_context = 'INVOKE_AREA'
+ layout.operator("wm.save_as_mainfile", text="Save As...")
+ layout.operator_context = 'INVOKE_AREA'
+ layout.operator("wm.save_as_mainfile", text="Save Copy...").copy = True
+
+ layout.separator()
+
+ layout.operator_context = 'INVOKE_AREA'
+ layout.operator("wm.save_homefile")
+ layout.operator("wm.read_factory_settings")
+
+ layout.separator()
+
+ layout.operator_context = 'INVOKE_AREA'
+ layout.operator("wm.link", text="Link", icon='LINK_BLEND')
+ layout.operator("wm.append", text="Append", icon='APPEND_BLEND')
+ layout.menu("INFO_MT_file_previews")
+
+ layout.separator()
+
+ layout.menu("INFO_MT_file_import", icon='IMPORT')
+ layout.menu("INFO_MT_file_export", icon='EXPORT')
+
+ layout.separator()
+
+ layout.menu("INFO_MT_file_external_data")
+
+ layout.separator()
+
+ layout.operator_context = 'EXEC_AREA'
+ if bpy.data.is_dirty and context.user_preferences.view.use_quit_dialog:
+ layout.operator_context = 'INVOKE_SCREEN' # quit dialog
+ layout.operator("wm.quit_blender", text="Quit", icon='QUIT')
+
+
+class INFO_MT_file_import(Menu):
+ bl_idname = "INFO_MT_file_import"
+ bl_label = "Import"
+
+ def draw(self, context):
+ if bpy.app.build_options.collada:
+ self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
+ if bpy.app.build_options.alembic:
+ self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
+
+
+class INFO_MT_file_export(Menu):
+ bl_idname = "INFO_MT_file_export"
+ bl_label = "Export"
+
+ def draw(self, context):
+ if bpy.app.build_options.collada:
+ self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
+ if bpy.app.build_options.alembic:
+ self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
+
+
+class INFO_MT_file_external_data(Menu):
+ bl_label = "External Data"
+
+ def draw(self, context):
+ layout = self.layout
+
+ icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT'
+ layout.operator("file.autopack_toggle", icon=icon)
+
+ layout.separator()
+
+ pack_all = layout.row()
+ pack_all.operator("file.pack_all")
+ pack_all.active = not bpy.data.use_autopack
+
+ unpack_all = layout.row()
+ unpack_all.operator("file.unpack_all")
+ unpack_all.active = not bpy.data.use_autopack
+
+ layout.separator()
+
+ layout.operator("file.make_paths_relative")
+ layout.operator("file.make_paths_absolute")
+ layout.operator("file.report_missing_files")
+ layout.operator("file.find_missing_files")
+
+
+class INFO_MT_file_previews(Menu):
+ bl_label = "Data Previews"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("wm.previews_ensure")
+ layout.operator("wm.previews_batch_generate")
+
+ layout.separator()
+
+ layout.operator("wm.previews_clear")
+ layout.operator("wm.previews_batch_clear")
+
+
+class INFO_MT_game(Menu):
+ bl_label = "Game"
+
+ def draw(self, context):
+ layout = self.layout
+
+ gs = context.scene.game_settings
+
+ layout.operator("view3d.game_start")
+
+ layout.separator()
+
+ layout.prop(gs, "show_debug_properties")
+ layout.prop(gs, "show_framerate_profile")
+ layout.prop(gs, "show_physics_visualization")
+ layout.prop(gs, "use_deprecation_warnings")
+ layout.prop(gs, "use_animation_record")
+ layout.separator()
+ layout.prop(gs, "use_auto_start")
+
+
+class INFO_MT_render(Menu):
+ bl_label = "Render"
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+
+ layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
+ props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
+ props.animation = True
+ props.use_viewport = True
+ layout.operator("sound.mixdown", text="Render Audio", icon='PLAY_AUDIO')
+
+ layout.separator()
+
+ layout.prop_menu_enum(rd, "display_mode", text="Display Mode")
+ layout.prop(rd, "use_lock_interface", text="Lock Interface")
+
+ layout.separator()
+
+ props = layout.operator("render.opengl", text="OpenGL Render Image", icon='RENDER_STILL')
+ props.view_context = False
+ props = layout.operator("render.opengl", text="OpenGL Render Animation", icon='RENDER_ANIMATION')
+ props.view_context = False
+ props.animation = True
+ layout.menu("INFO_MT_opengl_render")
+
+ layout.separator()
+
+ layout.operator("render.view_show")
+ layout.operator("render.play_rendered_anim", icon='PLAY')
+
+
+class INFO_MT_opengl_render(Menu):
+ bl_label = "OpenGL Render Options"
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+ layout.prop(rd, "use_antialiasing")
+ layout.prop(rd, "use_full_sample")
+
+ layout.prop_menu_enum(rd, "antialiasing_samples")
+ layout.prop_menu_enum(rd, "alpha_mode")
+
+
+class INFO_MT_edit(Menu):
+ bl_label = "Edit"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("ed.undo")
+ layout.operator("ed.redo")
+
+ layout.separator()
+
+ layout.operator("ed.undo_history", text="Undo History...")
+
+ layout.separator()
+
+ layout.operator("screen.repeat_last")
+ layout.operator("screen.repeat_history", text="Repeat History...")
+
+ layout.separator()
+
+ layout.operator("screen.redo_last", text="Adjust Last Operation...")
+
+ layout.separator()
+
+ layout.operator("wm.search_menu", text="Operator Search...")
+
+ layout.separator()
+
+ # Should move elsewhere (impacts outliner & 3D view).
+ tool_settings = context.tool_settings
+ layout.prop(tool_settings, "lock_object_mode")
+
+ layout.separator()
+
+ layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES')
+
+
+class INFO_MT_window(Menu):
+ bl_label = "Window"
+
+ def draw(self, context):
+ import sys
+
+ layout = self.layout
+
+ layout.operator("wm.window_new")
+ layout.operator("wm.window_new_main")
+
+ layout.separator()
+
+ layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
+
+ layout.separator()
+
+ layout.operator("screen.workspace_cycle", text="Next Workspace").direction = 'NEXT'
+ layout.operator("screen.workspace_cycle", text="Previous Workspace").direction = 'PREV'
+
+ layout.separator()
+
+ layout.operator("screen.screenshot")
+
+ if sys.platform[:3] == "win":
+ layout.separator()
+ layout.operator("wm.console_toggle", icon='CONSOLE')
+
+ if context.scene.render.use_multiview:
+ layout.separator()
+ layout.operator("wm.set_stereo_3d")
+
+
+class INFO_MT_help(Menu):
+ bl_label = "Help"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator(
+ "wm.url_open", text="Manual", icon='HELP',
+ ).url = "https://docs.blender.org/manual/en/dev/"
+ layout.operator(
+ "wm.url_open", text="Release Log", icon='URL',
+ ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
+ layout.separator()
+
+ layout.operator(
+ "wm.url_open", text="Blender Website", icon='URL',
+ ).url = "https://www.blender.org"
+ layout.operator(
+ "wm.url_open", text="Blender Store", icon='URL',
+ ).url = "https://store.blender.org"
+ layout.operator(
+ "wm.url_open", text="Developer Community", icon='URL',
+ ).url = "https://www.blender.org/get-involved/"
+ layout.operator(
+ "wm.url_open", text="User Community", icon='URL',
+ ).url = "https://www.blender.org/support/user-community"
+ layout.separator()
+ layout.operator(
+ "wm.url_open", text="Report a Bug", icon='URL',
+ ).url = "https://developer.blender.org/maniphest/task/edit/form/1"
+ layout.separator()
+
+ layout.operator(
+ "wm.url_open", text="Python API Reference", icon='URL',
+ ).url = bpy.types.WM_OT_doc_view._prefix
+
+ layout.operator("wm.operator_cheat_sheet", icon='TEXT')
+ layout.operator("wm.sysinfo", icon='TEXT')
+ layout.separator()
+
+ layout.operator("wm.splash", icon='BLENDER')
+
+
+class TOPBAR_MT_file_specials(Menu):
+ bl_label = "File Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_AREA'
+ layout.operator("wm.link", text="Link", icon='LINK_BLEND')
+ layout.operator("wm.append", text="Append", icon='APPEND_BLEND')
+
+ layout.separator()
+
+ layout.menu("INFO_MT_file_import", icon='IMPORT')
+ layout.menu("INFO_MT_file_export", icon='EXPORT')
+
+
+class TOPBAR_MT_window_specials(Menu):
+ bl_label = "Window Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'EXEC_AREA'
+
+ layout.operator("wm.window_new")
+ layout.operator("wm.window_new_main")
+
+ layout.operator_context = 'INVOKE_AREA'
+
+ layout.operator("screen.area_dupli")
+
+ layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
+
+ layout.separator()
+
+ layout.operator("screen.area_split", text="Horizontal Split").direction = 'HORIZONTAL'
+ layout.operator("screen.area_split", text="Vertical Split").direction = 'VERTICAL'
+
+ layout.separator()
+
+ layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES')
+
+
+classes = (
+ TOPBAR_HT_upper_bar,
+ TOPBAR_HT_lower_bar,
+ TOPBAR_MT_file_specials,
+ TOPBAR_MT_window_specials,
+ INFO_MT_editor_menus,
+ INFO_MT_file,
+ INFO_MT_file_import,
+ INFO_MT_file_export,
+ INFO_MT_file_external_data,
+ INFO_MT_file_previews,
+ INFO_MT_edit,
+ INFO_MT_game,
+ INFO_MT_render,
+ INFO_MT_opengl_render,
+ INFO_MT_window,
+ INFO_MT_help,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index ee1dcae29a1..806b57e0297 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -22,28 +22,29 @@ from bpy.types import (
Header,
Menu,
Panel,
+ Operator,
)
from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
-def opengl_lamp_buttons(column, lamp):
+def opengl_light_buttons(column, light):
split = column.row()
- split.prop(lamp, "use", text="", icon='OUTLINER_OB_LAMP' if lamp.use else 'LAMP_DATA')
+ split.prop(light, "use", text="", icon='OUTLINER_OB_LIGHT' if light.use else 'LIGHT_DATA')
col = split.column()
- col.active = lamp.use
+ col.active = light.use
row = col.row()
row.label(text="Diffuse:")
- row.prop(lamp, "diffuse_color", text="")
+ row.prop(light, "diffuse_color", text="")
row = col.row()
row.label(text="Specular:")
- row.prop(lamp, "specular_color", text="")
+ row.prop(light, "specular_color", text="")
col = split.column()
- col.active = lamp.use
- col.prop(lamp, "direction", text="")
+ col.active = light.use
+ col.prop(light, "direction", text="")
class USERPREF_HT_header(Header):
@@ -52,7 +53,8 @@ class USERPREF_HT_header(Header):
def draw(self, context):
layout = self.layout
- layout.template_header()
+ # No need to show type selector.
+ # layout.template_header()
userpref = context.user_preferences
@@ -61,13 +63,19 @@ class USERPREF_HT_header(Header):
layout.operator_context = 'INVOKE_DEFAULT'
- if userpref.active_section == 'INPUT':
+ if userpref.active_section == 'INTERFACE':
+ layout.operator("wm.save_workspace_file")
+ elif userpref.active_section == 'INPUT':
layout.operator("wm.keyconfig_import")
layout.operator("wm.keyconfig_export")
elif userpref.active_section == 'ADDONS':
layout.operator("wm.addon_install", icon='FILESEL')
layout.operator("wm.addon_refresh", icon='FILE_REFRESH')
layout.menu("USERPREF_MT_addons_online_resources")
+ elif userpref.active_section == 'LIGHTS':
+ layout.operator('wm.studiolight_install', text="Install MatCap").orientation = 'MATCAP'
+ layout.operator('wm.studiolight_install', text="Install World HDRI").orientation = 'WORLD'
+ layout.operator('wm.studiolight_install', text="Install Camera HDRI").orientation = 'CAMERA'
elif userpref.active_section == 'THEMES':
layout.operator("ui.reset_default_theme")
layout.operator("wm.theme_install")
@@ -222,29 +230,44 @@ class USERPREF_PT_interface(Panel):
col.prop(view, "ui_scale", text="Scale")
col.prop(view, "ui_line_width", text="Line Width")
col.prop(view, "show_tooltips")
- col.prop(view, "show_tooltips_python")
- col.prop(view, "show_developer_ui")
col.prop(view, "show_object_info", text="Object Info")
col.prop(view, "show_large_cursors")
col.prop(view, "show_view_name", text="View Name")
col.prop(view, "show_playback_fps", text="Playback FPS")
- col.prop(view, "use_global_scene")
col.prop(view, "object_origin_size")
col.separator()
- col.separator()
- col.separator()
- col.prop(view, "show_mini_axis", text="Display Mini Axis")
- sub = col.column()
- sub.active = view.show_mini_axis
+ # col.prop(view, "show_manipulator_navigate")
+
+ sub = col.column(align=True)
+
+ sub.label("3D Viewport Axis:")
+ sub.row().prop(view, "mini_axis_type", expand=True)
+
+ sub = col.column(align=True)
+ sub.active = view.mini_axis_type == 'MINIMAL'
sub.prop(view, "mini_axis_size", text="Size")
sub.prop(view, "mini_axis_brightness", text="Brightness")
col.separator()
- col.label("Warnings")
- col.prop(view, "use_quit_dialog")
+ # Toolbox doesn't exist yet
+ # col.label(text="Toolbox:")
+ #col.prop(view, "show_column_layout")
+ #col.label(text="Open Toolbox Delay:")
+ #col.prop(view, "open_left_mouse_delay", text="Hold LMB")
+ #col.prop(view, "open_right_mouse_delay", text="Hold RMB")
+ col.prop(view, "show_manipulator", text="Manipulators")
+ sub = col.column()
+ sub.active = view.show_manipulator
+ sub.prop(view, "manipulator_size", text="Size")
+
+ col.separator()
+
+ col.label("Development:")
+ col.prop(view, "show_tooltips_python")
+ col.prop(view, "show_developer_ui")
row.separator()
row.separator()
@@ -256,7 +279,6 @@ class USERPREF_PT_interface(Panel):
col.prop(view, "use_mouse_depth_navigate")
col.prop(view, "use_zoom_to_mouse")
col.prop(view, "use_rotate_around_active")
- col.prop(view, "use_global_pivot")
col.prop(view, "use_camera_lock_parent")
col.separator()
@@ -281,22 +303,6 @@ class USERPREF_PT_interface(Panel):
row.separator()
col = row.column()
- # Toolbox doesn't exist yet
- # col.label(text="Toolbox:")
- #col.prop(view, "show_column_layout")
- #col.label(text="Open Toolbox Delay:")
- #col.prop(view, "open_left_mouse_delay", text="Hold LMB")
- #col.prop(view, "open_right_mouse_delay", text="Hold RMB")
- col.prop(view, "show_manipulator")
- sub = col.column()
- sub.active = view.show_manipulator
- sub.prop(view, "manipulator_size", text="Size")
- sub.prop(view, "manipulator_handle_size", text="Handle Size")
- sub.prop(view, "manipulator_hotspot", text="Hotspot")
-
- col.separator()
- col.separator()
- col.separator()
col.label(text="Menus:")
col.prop(view, "use_mouse_over_open")
@@ -317,6 +323,10 @@ class USERPREF_PT_interface(Panel):
col.separator()
col.prop(view, "show_splash")
+
+ col.label("Warnings:")
+ col.prop(view, "use_quit_dialog")
+
col.separator()
col.label(text="App Template:")
@@ -424,6 +434,7 @@ class USERPREF_PT_edit(Panel):
col.label(text="Transform:")
col.prop(edit, "use_drag_immediately")
+ col.prop(edit, "use_numeric_input_advanced")
row.separator()
row.separator()
@@ -442,7 +453,7 @@ class USERPREF_PT_edit(Panel):
col.prop(edit, "use_duplicate_text", text="Text")
col.prop(edit, "use_duplicate_metaball", text="Metaball")
col.prop(edit, "use_duplicate_armature", text="Armature")
- col.prop(edit, "use_duplicate_lamp", text="Lamp")
+ col.prop(edit, "use_duplicate_light", text="Light")
col.prop(edit, "use_duplicate_material", text="Material")
col.prop(edit, "use_duplicate_texture", text="Texture")
#col.prop(edit, "use_duplicate_fcurve", text="F-Curve")
@@ -477,7 +488,6 @@ class USERPREF_PT_system(Panel):
col = colsplit.column()
col.label(text="General:")
- col.prop(system, "frame_server_port")
col.prop(system, "scrollback", text="Console Scrollback")
col.separator()
@@ -511,24 +521,21 @@ class USERPREF_PT_system(Panel):
col = colsplit.column()
col.label(text="OpenGL:")
col.prop(system, "gl_clip_alpha", slider=True)
- col.prop(system, "use_mipmaps")
col.prop(system, "use_gpu_mipmap")
col.prop(system, "use_16bit_textures")
col.separator()
- col.label(text="Selection")
+ col.label(text="Selection:")
col.prop(system, "select_method", text="")
col.prop(system, "use_select_pick_depth")
col.separator()
- col.label(text="Anisotropic Filtering")
+ col.label(text="Anisotropic Filtering:")
col.prop(system, "anisotropic_filter", text="")
col.separator()
- col.label(text="Window Draw Method:")
- col.prop(system, "window_draw_method", text="")
col.prop(system, "multi_sample", text="")
if sys.platform == "linux" and system.multi_sample != 'NONE':
col.label(text="Might fail for Mesh editing selection!")
@@ -536,6 +543,9 @@ class USERPREF_PT_system(Panel):
col.prop(system, "use_region_overlap")
col.separator()
+ col.prop(system, "gpu_viewport_quality")
+
+ col.separator()
col.label(text="Text Draw Options:")
col.prop(system, "use_text_antialiasing")
@@ -569,14 +579,14 @@ class USERPREF_PT_system(Panel):
split.label(text="Colors:")
split.label(text="Direction:")
- lamp = system.solid_lights[0]
- opengl_lamp_buttons(column, lamp)
+ light = system.solid_lights[0]
+ opengl_light_buttons(column, light)
- lamp = system.solid_lights[1]
- opengl_lamp_buttons(column, lamp)
+ light = system.solid_lights[1]
+ opengl_light_buttons(column, light)
- lamp = system.solid_lights[2]
- opengl_lamp_buttons(column, lamp)
+ light = system.solid_lights[2]
+ opengl_light_buttons(column, light)
column.separator()
@@ -718,6 +728,7 @@ class USERPREF_PT_theme(Panel):
colsub.row().prop(widget_style, "item", slider=True)
colsub.row().prop(widget_style, "inner", slider=True)
colsub.row().prop(widget_style, "inner_sel", slider=True)
+ colsub.row().prop(widget_style, "roundness")
subsplit = row.split(percentage=0.85)
@@ -797,6 +808,9 @@ class USERPREF_PT_theme(Panel):
col.label(text="Tool:")
self._theme_widget_style(col, ui.wcol_tool)
+ col.label(text="Toolbar Item:")
+ self._theme_widget_style(col, ui.wcol_toolbar_item)
+
col.label(text="Radio Buttons:")
self._theme_widget_style(col, ui.wcol_radio)
@@ -845,6 +859,9 @@ class USERPREF_PT_theme(Panel):
col.label(text="List Item:")
self._theme_widget_style(col, ui.wcol_list_item)
+ col.label(text="Tab:")
+ self._theme_widget_style(col, ui.wcol_tab)
+
ui_state = theme.user_interface.wcol_state
col.label(text="State:")
@@ -859,6 +876,7 @@ class USERPREF_PT_theme(Panel):
colsub.row().prop(ui_state, "inner_anim_sel")
colsub.row().prop(ui_state, "inner_driven")
colsub.row().prop(ui_state, "inner_driven_sel")
+ colsub.row().prop(ui_state, "blend")
subsplit = row.split(percentage=0.85)
@@ -867,7 +885,8 @@ class USERPREF_PT_theme(Panel):
colsub = padding.column()
colsub.row().prop(ui_state, "inner_key")
colsub.row().prop(ui_state, "inner_key_sel")
- colsub.row().prop(ui_state, "blend")
+ colsub.row().prop(ui_state, "inner_overridden")
+ colsub.row().prop(ui_state, "inner_overridden_sel")
col.separator()
col.separator()
@@ -882,34 +901,22 @@ class USERPREF_PT_theme(Panel):
colsub = padding.column()
colsub = padding.column()
colsub.row().prop(ui, "menu_shadow_fac")
-
- subsplit = row.split(percentage=0.85)
-
- padding = subsplit.split(percentage=0.15)
- colsub = padding.column()
- colsub = padding.column()
- colsub.row().prop(ui, "menu_shadow_width")
-
- row = col.row()
-
- subsplit = row.split(percentage=0.95)
-
- padding = subsplit.split(percentage=0.15)
- colsub = padding.column()
- colsub = padding.column()
colsub.row().prop(ui, "icon_alpha")
+ colsub.row().prop(ui, "icon_saturation")
+ colsub.row().prop(ui, "editor_outline")
subsplit = row.split(percentage=0.85)
padding = subsplit.split(percentage=0.15)
colsub = padding.column()
colsub = padding.column()
+ colsub.row().prop(ui, "menu_shadow_width")
colsub.row().prop(ui, "widget_emboss")
col.separator()
col.separator()
- col.label("Axis Colors:")
+ col.label("Axis & Manipulator Colors:")
row = col.row()
@@ -927,9 +934,13 @@ class USERPREF_PT_theme(Panel):
padding = subsplit.split(percentage=0.15)
colsub = padding.column()
colsub = padding.column()
+ colsub.row().prop(ui, "manipulator_primary")
+ colsub.row().prop(ui, "manipulator_secondary")
+ colsub.row().prop(ui, "manipulator_a")
+ colsub.row().prop(ui, "manipulator_b")
- layout.separator()
- layout.separator()
+ col.separator()
+ col.separator()
elif theme.theme_area == 'BONE_COLOR_SETS':
col = split.column()
@@ -1426,12 +1437,13 @@ class USERPREF_PT_addons(Panel):
continue
# check if addon should be visible with current filters
- if ((filter == "All") or
- (filter == info["category"]) or
- (filter == "Enabled" and is_enabled) or
+ if (
+ (filter == "All") or
+ (filter == info["category"]) or
+ (filter == "Enabled" and is_enabled) or
(filter == "Disabled" and not is_enabled) or
(filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder))))
- ):
+ ):
if search and search not in info["name"].lower():
if info["author"]:
if search not in info["author"].lower():
@@ -1460,7 +1472,14 @@ class USERPREF_PT_addons(Panel):
sub = row.row()
sub.active = is_enabled
sub.label(text="%s: %s" % (info["category"], info["name"]))
- if info["warning"]:
+
+ # WARNING: 2.8x exception, may be removed
+ # use disabled state for old add-ons, chances are they are broken.
+ if info.get("blender", (0,)) < (2, 80):
+ sub.label(text="upgrade to 2.8x required")
+ sub.label(icon='ERROR')
+ # Remove code above after 2.8x migration is complete.
+ elif info["warning"]:
sub.label(icon='ERROR')
# icon showing support level.
@@ -1565,6 +1584,62 @@ class USERPREF_PT_addons(Panel):
row.label(text=module_name, translate=False)
+class StudioLightPanelMixin():
+ bl_space_type = 'USER_PREFERENCES'
+ bl_region_type = 'WINDOW'
+
+ @classmethod
+ def poll(cls, context):
+ userpref = context.user_preferences
+ return (userpref.active_section == 'LIGHTS')
+
+ def _get_lights(self, userpref):
+ return [light for light in userpref.studio_lights if light.is_user_defined and light.orientation == self.sl_orientation]
+
+ def draw_header(self, context):
+ layout = self.layout
+ row = layout.row()
+ userpref = context.user_preferences
+ lights = self._get_lights(userpref)
+ row.label("({})".format(len(lights)))
+
+ def draw(self, context):
+ layout = self.layout
+ userpref = context.user_preferences
+ lights = self._get_lights(userpref)
+ if lights:
+ flow = layout.column_flow(4)
+ for studio_light in lights:
+ self.draw_studio_light(flow, studio_light)
+ else:
+ layout.label("No custom {} configured".format(self.bl_label))
+
+ def draw_studio_light(self, layout, studio_light):
+ box = layout.box()
+ row = box.row()
+
+ row.template_icon(layout.icon(studio_light), scale=6.0)
+ op = row.operator('wm.studiolight_uninstall', text="", icon='ZOOMOUT')
+ op.index = studio_light.index
+
+ box.label(text=studio_light.name)
+
+
+class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin):
+ bl_label = "MatCaps"
+ sl_orientation = 'MATCAP'
+
+
+class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin):
+ bl_label = "World HDRI"
+ sl_orientation = 'WORLD'
+
+
+class USERPREF_PT_studiolight_camera(Panel, StudioLightPanelMixin):
+ bl_label = "Camera HDRI"
+ sl_orientation = 'CAMERA'
+
+
classes = (
USERPREF_HT_header,
USERPREF_PT_tabs,
@@ -1585,6 +1660,9 @@ classes = (
USERPREF_PT_input,
USERPREF_MT_addons_online_resources,
USERPREF_PT_addons,
+ USERPREF_PT_studiolight_matcaps,
+ USERPREF_PT_studiolight_world,
+ USERPREF_PT_studiolight_camera,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 0a365c6a20c..f9b69b8de66 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -34,117 +34,192 @@ class VIEW3D_HT_header(Header):
layout = self.layout
view = context.space_data
+ shading = view.shading
# mode_string = context.mode
obj = context.active_object
- toolsettings = context.tool_settings
+ overlay = view.overlay
+ tool_settings = context.tool_settings
row = layout.row(align=True)
row.template_header()
- VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
+ object_mode = 'OBJECT' if obj is None else obj.mode
+
+ act_mode_item = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode]
+ layout.operator_menu_enum("object.mode_set", "mode", text=act_mode_item.name, icon=act_mode_item.icon)
+ del act_mode_item
+
+ layout.template_header_3D_mode()
# Contains buttons like Mode, Pivot, Manipulator, Layer, Mesh Select Mode...
- row = layout
- layout.template_header_3D()
+ shading_type = view.shading.type
+ shading_item = bpy.types.View3DShading.bl_rna.properties["type"].enum_items[shading_type]
if obj:
- mode = obj.mode
+ # Set above:
+ # object_mode = obj.mode
+
# Particle edit
- if mode == 'PARTICLE_EDIT':
- row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True)
+ if object_mode == 'PARTICLE_EDIT':
+ row = layout.row()
+ row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True)
# Occlude geometry
- if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or
- (mode in {'WEIGHT_PAINT', 'VERTEX_PAINT'})):
+ if (
+ (((shading.type not in {'SOLID', 'TEXTURED'}) or not shading.show_xray) and
+ (object_mode == 'PARTICLE_EDIT' or (object_mode == 'EDIT' and obj.type == 'MESH'))) or
+ (object_mode in {'WEIGHT_PAINT', 'VERTEX_PAINT'})
+ ):
+ row = layout.row()
row.prop(view, "use_occlude_geometry", text="")
- # Proportional editing
- if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
- row = layout.row(align=True)
- row.prop(toolsettings, "proportional_edit", icon_only=True)
- if toolsettings.proportional_edit != 'DISABLED':
- row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
- elif mode in {'EDIT', 'PARTICLE_EDIT'}:
- row = layout.row(align=True)
- row.prop(toolsettings, "proportional_edit", icon_only=True)
- if toolsettings.proportional_edit != 'DISABLED':
- row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
- elif mode == 'OBJECT':
- row = layout.row(align=True)
- row.prop(toolsettings, "use_proportional_edit_objects", icon_only=True)
- if toolsettings.use_proportional_edit_objects:
- row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
- else:
- # Proportional editing
- if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
- row = layout.row(align=True)
- row.prop(toolsettings, "proportional_edit", icon_only=True)
- if toolsettings.proportional_edit != 'DISABLED':
- row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
+ # Pose
+ if obj and object_mode == 'POSE':
+ row = layout.row(align=True)
+ row.operator("pose.copy", text="", icon='COPYDOWN')
+ row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False
+ row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True
+
+ # GPencil
+ if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
+ row = layout.row(align=True)
+ row.operator("gpencil.copy", text="", icon='COPYDOWN')
+ row.operator("gpencil.paste", text="", icon='PASTEDOWN')
+
+ # XXX: icon
+ layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH')
+
+ row = layout.row(align=True)
+ row.prop(tool_settings.gpencil_sculpt, "use_select_mask")
+ row.prop(tool_settings.gpencil_sculpt, "selection_alpha", slider=True)
+
+ VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
+
+ layout.separator_spacer()
+
+ # Mode & Transform Settings
+ scene = context.scene
+
+ # Orientation
+ if object_mode in {'OBJECT', 'EDIT', 'POSE'}:
+ orientation = scene.transform_orientation
+ current_orientation = scene.current_orientation
+
+ if not current_orientation:
+ trans_orientation = \
+ bpy.types.Scene.bl_rna.properties["transform_orientation"].enum_items[orientation]
+ trans_icon = getattr(trans_orientation, "icon", "BLANK1")
+ trans_name = getattr(trans_orientation, "name", "Orientation")
+ else:
+ trans_icon = 'VISIBLE_IPO_OFF'
+ trans_name = getattr(current_orientation, "name", "Orientation")
+
+ row = layout.row(align=True)
+ row.popover(
+ panel="VIEW3D_PT_transform_orientations",
+ text=trans_name,
+ icon=trans_icon,
+ )
# Snap
show_snap = False
if obj is None:
show_snap = True
else:
- if mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}:
+ if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}:
show_snap = True
else:
+
+ from .properties_paint_common import UnifiedPaintPanel
paint_settings = UnifiedPaintPanel.paint_settings(context)
+
if paint_settings:
brush = paint_settings.brush
if brush and brush.stroke_method == 'CURVE':
show_snap = True
if show_snap:
- snap_element = toolsettings.snap_element
- row = layout.row(align=True)
- row.prop(toolsettings, "use_snap", text="")
- row.prop(toolsettings, "snap_element", icon_only=True)
- if snap_element == 'INCREMENT':
- row.prop(toolsettings, "use_snap_grid_absolute", text="")
+ snap_items = bpy.types.ToolSettings.bl_rna.properties['snap_elements'].enum_items
+ for elem in tool_settings.snap_elements:
+ # TODO: Display multiple icons.
+ # (Currently only one of the enabled modes icons is displayed)
+ icon = snap_items[elem].icon
+ break
else:
- row.prop(toolsettings, "snap_target", text="")
- if obj:
- if mode == 'EDIT':
- row.prop(toolsettings, "use_snap_self", text="")
- if mode in {'OBJECT', 'POSE', 'EDIT'} and snap_element != 'VOLUME':
- row.prop(toolsettings, "use_snap_align_rotation", text="")
-
- if snap_element == 'VOLUME':
- row.prop(toolsettings, "use_snap_peel_object", text="")
- elif snap_element == 'FACE':
- row.prop(toolsettings, "use_snap_project", text="")
-
- # AutoMerge editing
+ icon = 'NONE'
+
+ row = layout.row(align=True)
+ row.prop(tool_settings, "use_snap", text="")
+
+ sub = row.row(align=True)
+ sub.popover(
+ panel="VIEW3D_PT_snapping",
+ icon=icon,
+ text="",
+ )
+
+ # Proportional editing
if obj:
- if (mode == 'EDIT' and obj.type == 'MESH'):
- layout.prop(toolsettings, "use_mesh_automerge", text="", icon='AUTOMERGE_ON')
+ if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
+ row = layout.row(align=True)
+ row.prop(tool_settings, "proportional_edit", icon_only=True)
- # OpenGL render
- row = layout.row(align=True)
- row.operator("render.opengl", text="", icon='RENDER_STILL')
- row.operator("render.opengl", text="", icon='RENDER_ANIMATION').animation = True
+ sub = row.row(align=True)
+ sub.active = tool_settings.proportional_edit != 'DISABLED'
+ sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
- # Pose
- if obj and mode == 'POSE':
- row = layout.row(align=True)
- row.operator("pose.copy", text="", icon='COPYDOWN')
- row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False
- row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True
+ elif object_mode in {'EDIT', 'PARTICLE_EDIT'}:
+ row = layout.row(align=True)
+ row.prop(tool_settings, "proportional_edit", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = tool_settings.proportional_edit != 'DISABLED'
+ sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
- # GPencil
- if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
+ elif object_mode == 'OBJECT':
+ row = layout.row(align=True)
+ row.prop(tool_settings, "use_proportional_edit_objects", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = tool_settings.use_proportional_edit_objects
+ sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
+ else:
+ if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
+ row = layout.row(align=True)
+ row.prop(tool_settings, "proportional_edit", icon_only=True)
+ sub = row.row(align=True)
+ sub.active = tool_settings.proportional_edit != 'DISABLED'
+ sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
+
+ # Pivot
+ if object_mode in {'OBJECT', 'EDIT', 'POSE'}:
+ pivot_point = tool_settings.transform_pivot_point
+ act_pivot_point = bpy.types.ToolSettings.bl_rna.properties["transform_pivot_point"].enum_items[pivot_point]
row = layout.row(align=True)
- row.operator("gpencil.copy", text="", icon='COPYDOWN')
- row.operator("gpencil.paste", text="", icon='PASTEDOWN')
+ row.popover(
+ panel="VIEW3D_PT_pivot_point",
+ icon=act_pivot_point.icon,
+ text="",
+ )
- # XXX: icon
- layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH')
+ layout.separator_spacer()
- row = layout.row(align=True)
- row.prop(context.tool_settings.gpencil_sculpt, "use_select_mask")
- row.prop(context.tool_settings.gpencil_sculpt, "selection_alpha", slider=True)
+ # Viewport Settings
+ layout.popover(
+ panel="VIEW3D_PT_object_type_visibility",
+ icon_value=view.icon_from_show_object_viewport,
+ text="",
+ )
+
+ row = layout.row(align=True)
+ row.prop(overlay, "show_overlays", icon='WIRE', text="")
+ sub = row.row(align=True)
+ sub.active = overlay.show_overlays
+ sub.popover(panel="VIEW3D_PT_overlay")
+
+ row = layout.row(align=True)
+ row.prop(shading, "type", text="", expand=True)
+ sub = row.row(align=True)
+ sub.enabled = shading.type != 'RENDERED'
+ sub.popover(panel="VIEW3D_PT_shading")
class VIEW3D_MT_editor_menus(Menu):
@@ -194,6 +269,12 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_edit_gpencil")
elif edit_object:
layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
+
+ if mode_string == 'EDIT_MESH':
+ layout.menu("VIEW3D_MT_edit_mesh_vertices")
+ layout.menu("VIEW3D_MT_edit_mesh_edges")
+ layout.menu("VIEW3D_MT_edit_mesh_faces")
+
elif obj:
if mode_string != 'PAINT_TEXTURE':
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
@@ -232,15 +313,6 @@ class VIEW3D_MT_transform_base(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("transform.translate", text="Grab/Move")
- # TODO: sub-menu for grab per axis
- layout.operator("transform.rotate", text="Rotate")
- # TODO: sub-menu for rot per axis
- layout.operator("transform.resize", text="Scale")
- # TODO: sub-menu for scale per axis
-
- layout.separator()
-
layout.operator("transform.tosphere", text="To Sphere")
layout.operator("transform.shear", text="Shear")
layout.operator("transform.bend", text="Bend")
@@ -301,6 +373,12 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
layout.operator("object.randomize_transform")
layout.operator("object.align")
+ # TODO: there is a strange context bug here.
+ """
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("object.transform_axis_target")
+ """
+
# Armature EditMode extensions to Transform menu
class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
@@ -416,6 +494,11 @@ class VIEW3D_MT_uv_map(Menu):
layout.operator("uv.reset")
+ layout.separator()
+
+ layout.operator("mesh.uvs_rotate")
+ layout.operator("mesh.uvs_reverse")
+
class VIEW3D_MT_edit_proportional(Menu):
bl_label = "Proportional Editing"
@@ -423,12 +506,12 @@ class VIEW3D_MT_edit_proportional(Menu):
def draw(self, context):
layout = self.layout
- layout.props_enum(context.tool_settings, "proportional_edit")
+ layout.props_enum(tool_settings, "proportional_edit")
layout.separator()
layout.label("Falloff:")
- layout.props_enum(context.tool_settings, "proportional_edit_falloff")
+ layout.props_enum(tool_settings, "proportional_edit_falloff")
# ********** View menus **********
@@ -441,18 +524,17 @@ class VIEW3D_MT_view(Menu):
layout = self.layout
view = context.space_data
- layout.operator("view3d.properties", icon='MENU_PANEL')
layout.operator("view3d.toolshelf", icon='MENU_PANEL')
+ layout.operator("view3d.properties", icon='MENU_PANEL')
layout.separator()
- layout.operator("view3d.view_selected").use_all_regions = False
+ layout.operator("view3d.view_selected", text="Frame Selected").use_all_regions = False
if view.region_quadviews:
- layout.operator("view3d.view_selected", text="View Selected (Quad View)").use_all_regions = True
+ layout.operator("view3d.view_selected", text="Frame Selected (Quad View)").use_all_regions = True
- layout.operator("view3d.view_all").center = False
- layout.operator("view3d.localview", text="View Global/Local")
- layout.operator("view3d.view_persportho")
+ layout.operator("view3d.view_all", text="Frame All").center = False
+ layout.operator("view3d.view_persportho", text="Perspective/Orthographic")
layout.separator()
@@ -470,18 +552,16 @@ class VIEW3D_MT_view(Menu):
layout.separator()
- layout.operator("view3d.layers", text="Show All Layers").nr = 0
+ layout.operator("screen.animation_play", text="Play Animation")
layout.separator()
- layout.operator("screen.animation_play", text="Playback Animation")
+ layout.operator("render.opengl", icon='RENDER_STILL')
+ layout.operator("render.opengl", text="OpenGL Render Animation", icon='RENDER_ANIMATION').animation = True
layout.separator()
- layout.operator("screen.area_dupli")
- layout.operator("screen.region_quadview")
- layout.operator("screen.screen_full_area")
- layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+ layout.menu("INFO_MT_area")
class VIEW3D_MT_view_cameras(Menu):
@@ -491,7 +571,7 @@ class VIEW3D_MT_view_cameras(Menu):
layout = self.layout
layout.operator("view3d.object_as_camera")
- layout.operator("view3d.viewnumpad", text="Active Camera").type = 'CAMERA'
+ layout.operator("view3d.view_camera", text="Active Camera")
class VIEW3D_MT_view_viewpoint(Menu):
@@ -500,22 +580,22 @@ class VIEW3D_MT_view_viewpoint(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.viewnumpad", text="Camera").type = 'CAMERA'
+ layout.operator("view3d.view_camera", text="Camera")
layout.separator()
- layout.operator("view3d.viewnumpad", text="Top").type = 'TOP'
- layout.operator("view3d.viewnumpad", text="Bottom").type = 'BOTTOM'
+ layout.operator("view3d.view_axis", text="Top").type = 'TOP'
+ layout.operator("view3d.view_axis", text="Bottom").type = 'BOTTOM'
layout.separator()
- layout.operator("view3d.viewnumpad", text="Front").type = 'FRONT'
- layout.operator("view3d.viewnumpad", text="Back").type = 'BACK'
+ layout.operator("view3d.view_axis", text="Front").type = 'FRONT'
+ layout.operator("view3d.view_axis", text="Back").type = 'BACK'
layout.separator()
- layout.operator("view3d.viewnumpad", text="Right").type = 'RIGHT'
- layout.operator("view3d.viewnumpad", text="Left").type = 'LEFT'
+ layout.operator("view3d.view_axis", text="Right").type = 'RIGHT'
+ layout.operator("view3d.view_axis", text="Left").type = 'LEFT'
class VIEW3D_MT_view_navigation(Menu):
@@ -579,27 +659,27 @@ class VIEW3D_MT_view_align_selected(Menu):
def draw(self, context):
layout = self.layout
- props = layout.operator("view3d.viewnumpad", text="Top")
+ props = layout.operator("view3d.view_axis", text="Top")
props.align_active = True
props.type = 'TOP'
- props = layout.operator("view3d.viewnumpad", text="Bottom")
+ props = layout.operator("view3d.view_axis", text="Bottom")
props.align_active = True
props.type = 'BOTTOM'
- props = layout.operator("view3d.viewnumpad", text="Front")
+ props = layout.operator("view3d.view_axis", text="Front")
props.align_active = True
props.type = 'FRONT'
- props = layout.operator("view3d.viewnumpad", text="Back")
+ props = layout.operator("view3d.view_axis", text="Back")
props.align_active = True
props.type = 'BACK'
- props = layout.operator("view3d.viewnumpad", text="Right")
+ props = layout.operator("view3d.view_axis", text="Right")
props.align_active = True
props.type = 'RIGHT'
- props = layout.operator("view3d.viewnumpad", text="Left")
+ props = layout.operator("view3d.view_axis", text="Left")
props.align_active = True
props.type = 'LEFT'
@@ -610,7 +690,7 @@ class VIEW3D_MT_view_borders(Menu):
def draw(self, context):
layout = self.layout
layout.operator("view3d.clip_border", text="Clipping Border...")
- layout.operator("view3d.render_border", text="Render Border...").camera_only = False
+ layout.operator("view3d.render_border", text="Render Border...")
layout.separator()
@@ -657,21 +737,21 @@ class VIEW3D_MT_select_object(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("object.select_all", text="All").action = 'SELECT'
+ layout.operator("object.select_all", text="None").action = 'DESELECT'
+ layout.operator("object.select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("object.select_all").action = 'TOGGLE'
- layout.operator("object.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
- layout.operator("object.select_random", text="Random")
- layout.operator("object.select_mirror", text="Mirror")
- layout.operator("object.select_by_layer", text="Select All by Layer")
layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...")
- layout.operator("object.select_camera", text="Select Camera")
+ layout.operator("object.select_camera", text="Select Active Camera")
+ layout.operator("object.select_mirror", text="Mirror Selection")
+ layout.operator("object.select_random", text="Select Random")
layout.separator()
@@ -679,8 +759,8 @@ class VIEW3D_MT_select_object(Menu):
layout.separator()
- layout.operator_menu_enum("object.select_grouped", "type", text="Grouped")
- layout.operator_menu_enum("object.select_linked", "type", text="Linked")
+ layout.operator_menu_enum("object.select_grouped", "type", text="Select Grouped")
+ layout.operator_menu_enum("object.select_linked", "type", text="Select Linked")
layout.operator("object.select_pattern", text="Select Pattern...")
@@ -717,13 +797,17 @@ class VIEW3D_MT_select_pose(Menu):
def draw(self, context):
layout = self.layout
+ layout.operator("pose.select_all", text="All").action = 'SELECT'
+ layout.operator("pose.select_all", text="None").action = 'DESELECT'
+ layout.operator("pose.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("view3d.select_border")
layout.operator("view3d.select_circle")
layout.separator()
- layout.operator("pose.select_all").action = 'TOGGLE'
- layout.operator("pose.select_all", text="Inverse").action = 'INVERT'
layout.operator("pose.select_mirror", text="Flip Active")
layout.separator()
@@ -747,14 +831,18 @@ class VIEW3D_MT_select_particle(Menu):
def draw(self, context):
layout = self.layout
+ layout.operator("particle.select_all", text="All").action = 'SELECT'
+ layout.operator("particle.select_all", text="None").action = 'DESELECT'
+ layout.operator("particle.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("view3d.select_border")
layout.operator("view3d.select_circle")
layout.separator()
- layout.operator("particle.select_all").action = 'TOGGLE'
layout.operator("particle.select_linked")
- layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
layout.separator()
@@ -789,7 +877,8 @@ class VIEW3D_MT_edit_mesh_select_by_trait(Menu):
def draw(self, context):
layout = self.layout
- if context.scene.tool_settings.mesh_select_mode[2] is False:
+ tool_settings = context.tool_settings
+ if tool_settings.mesh_select_mode[2] is False:
layout.operator("mesh.select_non_manifold", text="Non Manifold")
layout.operator("mesh.select_loose", text="Loose Geometry")
layout.operator("mesh.select_interior_faces", text="Interior Faces")
@@ -847,25 +936,26 @@ class VIEW3D_MT_select_edit_mesh(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ # primitive
+ layout.operator("mesh.select_all", text="All").action = 'SELECT'
+ layout.operator("mesh.select_all", text="None").action = 'DESELECT'
+ layout.operator("mesh.select_all", text="Invert").action = 'INVERT'
layout.separator()
- # primitive
- layout.operator("mesh.select_all").action = 'TOGGLE'
- layout.operator("mesh.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
# numeric
- layout.operator("mesh.select_random", text="Random")
+ layout.operator("mesh.select_random", text="Select Random")
layout.operator("mesh.select_nth")
layout.separator()
# geometric
- layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
+ layout.operator("mesh.edges_select_sharp", text="Select Sharp Edges")
layout.separator()
@@ -891,7 +981,7 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.separator()
layout.operator("mesh.select_axis", text="Side of Active")
- layout.operator("mesh.select_mirror", text="Mirror")
+ layout.operator("mesh.select_mirror", text="Mirror Selection")
class VIEW3D_MT_select_edit_curve(Menu):
@@ -900,13 +990,14 @@ class VIEW3D_MT_select_edit_curve(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("curve.select_all", text="All").action = 'SELECT'
+ layout.operator("curve.select_all", text="None").action = 'DESELECT'
+ layout.operator("curve.select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("curve.select_all").action = 'TOGGLE'
- layout.operator("curve.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -934,13 +1025,14 @@ class VIEW3D_MT_select_edit_surface(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("curve.select_all", text="All").action = 'SELECT'
+ layout.operator("curve.select_all", text="None").action = 'DESELECT'
+ layout.operator("curve.select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("curve.select_all").action = 'TOGGLE'
- layout.operator("curve.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -967,10 +1059,6 @@ class VIEW3D_MT_select_edit_text(Menu):
def draw(self, context):
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
layout.operator("font.text_paste", text="Paste")
layout.operator("font.text_cut", text="Cut")
layout.operator("font.text_copy", text="Copy")
@@ -990,13 +1078,14 @@ class VIEW3D_MT_select_edit_metaball(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("mball.select_all", text="All").action = 'SELECT'
+ layout.operator("mball.select_all", text="None").action = 'DESELECT'
+ layout.operator("mball.select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("mball.select_all").action = 'TOGGLE'
- layout.operator("mball.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -1013,13 +1102,14 @@ class VIEW3D_MT_select_edit_lattice(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("lattice.select_all", text="All").action = 'SELECT'
+ layout.operator("lattice.select_all", text="None").action = 'DESELECT'
+ layout.operator("lattice.select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("lattice.select_all").action = 'TOGGLE'
- layout.operator("lattice.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -1037,13 +1127,17 @@ class VIEW3D_MT_select_edit_armature(Menu):
def draw(self, context):
layout = self.layout
+ layout.operator("armature.select_all", text="All").action = 'SELECT'
+ layout.operator("armature.select_all", text="None").action = 'DESELECT'
+ layout.operator("armature.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("view3d.select_border")
layout.operator("view3d.select_circle")
layout.separator()
- layout.operator("armature.select_all").action = 'TOGGLE'
- layout.operator("armature.select_all", text="Inverse").action = 'INVERT'
layout.operator("armature.select_mirror", text="Mirror").extend = False
layout.separator()
@@ -1081,13 +1175,14 @@ class VIEW3D_MT_select_gpencil(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("gpencil.select_border")
- layout.operator("gpencil.select_circle")
+ layout.operator("gpencil.select_all", text="All").action = 'SELECT'
+ layout.operator("gpencil.select_all", text="None").action = 'DESELECT'
+ layout.operator("gpencil.select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("gpencil.select_all", text="(De)select All").action = 'TOGGLE'
- layout.operator("gpencil.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("gpencil.select_border")
+ layout.operator("gpencil.select_circle")
layout.separator()
@@ -1111,13 +1206,14 @@ class VIEW3D_MT_select_paint_mask(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("paint.face_select_all", text="All").action = 'SELECT'
+ layout.operator("paint.face_select_all", text="None").action = 'DESELECT'
+ layout.operator("paint.face_select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("paint.face_select_all").action = 'TOGGLE'
- layout.operator("paint.face_select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -1130,13 +1226,14 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
+ layout.operator("paint.vert_select_all", text="All").action = 'SELECT'
+ layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
+ layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
layout.separator()
- layout.operator("paint.vert_select_all").action = 'TOGGLE'
- layout.operator("paint.vert_select_all", text="Inverse").action = 'INVERT'
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -1183,13 +1280,23 @@ class INFO_MT_mesh_add(Menu):
bl_label = "Mesh"
def draw(self, context):
- from .space_view3d_toolbar import VIEW3D_PT_tools_add_object
-
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- VIEW3D_PT_tools_add_object.draw_add_mesh(layout)
+ layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE')
+ layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE')
+ layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
+ layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE')
+ layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE')
+ layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER')
+ layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE')
+ layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS')
+
+ layout.separator()
+
+ layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID')
+ layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY')
class INFO_MT_curve_add(Menu):
@@ -1197,12 +1304,22 @@ class INFO_MT_curve_add(Menu):
bl_label = "Curve"
def draw(self, context):
- from .space_view3d_toolbar import VIEW3D_PT_tools_add_object
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- VIEW3D_PT_tools_add_object.draw_add_curve(layout)
+ layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE')
+ layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE')
+
+ layout.separator()
+
+ layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE')
+ layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
+ layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
+
+ layout.separator()
+
+ layout.operator("curve.draw", icon='LINE_DATA')
class INFO_MT_surface_add(Menu):
@@ -1210,12 +1327,17 @@ class INFO_MT_surface_add(Menu):
bl_label = "Surface"
def draw(self, context):
- from .space_view3d_toolbar import VIEW3D_PT_tools_add_object
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- VIEW3D_PT_tools_add_object.draw_add_surface(layout)
+ layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE')
+ layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE')
+ layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE')
+ layout.operator("surface.primitive_nurbs_surface_cylinder_add",
+ text="Nurbs Cylinder", icon='SURFACE_NCYLINDER')
+ layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE')
+ layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS')
class INFO_MT_metaball_add(Menu):
@@ -1267,15 +1389,26 @@ class INFO_MT_armature_add(Menu):
layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA')
-class INFO_MT_lamp_add(Menu):
- bl_idname = "INFO_MT_lamp_add"
- bl_label = "Lamp"
+class INFO_MT_light_add(Menu):
+ bl_idname = "INFO_MT_light_add"
+ bl_label = "Light"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator_enum("object.lamp_add", "type")
+ layout.operator_enum("object.light_add", "type")
+
+
+class INFO_MT_lightprobe_add(Menu):
+ bl_idname = "INFO_MT_lightprobe_add"
+ bl_label = "Light Probe"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator_enum("object.lightprobe_add", "type")
class INFO_MT_camera_add(Menu):
@@ -1324,39 +1457,34 @@ class INFO_MT_add(Menu):
else:
INFO_MT_camera_add.draw(self, context)
- layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP')
+ layout.menu("INFO_MT_light_add", icon='OUTLINER_OB_LIGHT')
+ layout.separator()
+ layout.menu("INFO_MT_lightprobe_add", icon='OUTLINER_OB_LIGHTPROBE')
layout.separator()
layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD')
layout.separator()
- if len(bpy.data.groups) > 10:
- layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("object.group_instance_add", text="Group Instance...", icon='OUTLINER_OB_GROUP_INSTANCE')
+ has_collections = bool(bpy.data.collections)
+ col = layout.column()
+ col.enabled = has_collections
+
+ if not has_collections or len(bpy.data.collections) > 10:
+ col.operator_context = 'INVOKE_REGION_WIN'
+ col.operator(
+ "object.collection_instance_add",
+ text="Collection Instance..." if has_collections else "No Collections to Instance",
+ icon='OUTLINER_OB_GROUP_INSTANCE',
+ )
else:
- layout.operator_menu_enum(
- "object.group_instance_add",
- "group",
- text="Group Instance",
+ col.operator_menu_enum(
+ "object.collection_instance_add",
+ "collection",
+ text="Collection Instance",
icon='OUTLINER_OB_GROUP_INSTANCE',
)
-class VIEW3D_MT_undo_redo(Menu):
- bl_label = "Undo/Redo"
- _operator_name = ""
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("ed.undo")
- layout.operator("ed.redo")
-
- layout.separator()
-
- layout.operator("ed.undo_history")
-
-
class VIEW3D_MT_object_relations(Menu):
bl_label = "Relations"
@@ -1384,26 +1512,11 @@ class VIEW3D_MT_object(Menu):
def draw(self, context):
layout = self.layout
- view = context.space_data
- is_local_view = (view.local_view is not None)
-
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.operator("object.delete", text="Delete...").use_global = False
-
- layout.separator()
layout.menu("VIEW3D_MT_transform_object")
layout.menu("VIEW3D_MT_mirror")
layout.menu("VIEW3D_MT_object_clear")
layout.menu("VIEW3D_MT_object_apply")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_object_parent")
- layout.menu("VIEW3D_MT_object_group")
layout.menu("VIEW3D_MT_snap")
layout.separator()
@@ -1411,22 +1524,30 @@ class VIEW3D_MT_object(Menu):
layout.operator("object.duplicate_move")
layout.operator("object.duplicate_move_linked")
layout.operator("object.join")
- if is_local_view:
- layout.operator_context = 'EXEC_REGION_WIN'
- layout.operator("object.move_to_layer", text="Move out of Local View")
- layout.operator_context = 'INVOKE_REGION_WIN'
- else:
- layout.operator("object.move_to_layer", text="Move to Layer...")
layout.separator()
- layout.menu("VIEW3D_MT_make_links", text="Make Links...")
+
+ layout.operator("view3d.copybuffer", text="Copy Objects")
+ layout.operator("view3d.pastebuffer", text="Paste Objects")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_object_parent")
+ layout.menu("VIEW3D_MT_object_collection")
layout.menu("VIEW3D_MT_object_relations")
layout.menu("VIEW3D_MT_object_constraints")
layout.menu("VIEW3D_MT_object_track")
+ layout.menu("VIEW3D_MT_make_links", text="Make Links...")
+
+ layout.separator()
+
+ layout.operator("object.shade_smooth", text="Smooth Shading")
+ layout.operator("object.shade_flat", text="Flat Shading")
layout.separator()
layout.menu("VIEW3D_MT_object_animation")
+ layout.menu("VIEW3D_MT_object_rigid_body")
layout.separator()
@@ -1434,13 +1555,15 @@ class VIEW3D_MT_object(Menu):
layout.separator()
- layout.menu("VIEW3D_MT_object_game")
+ layout.operator_menu_enum("object.convert", "target")
layout.separator()
layout.menu("VIEW3D_MT_object_showhide")
- layout.operator_menu_enum("object.convert", "target")
+ layout.separator()
+
+ layout.operator("object.delete", text="Delete...").use_global = False
class VIEW3D_MT_object_animation(Menu):
@@ -1459,6 +1582,32 @@ class VIEW3D_MT_object_animation(Menu):
layout.operator("nla.bake", text="Bake Action...")
+class VIEW3D_MT_object_rigid_body(Menu):
+ bl_label = "Rigid Body"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("rigidbody.objects_add", text="Add Active").type = 'ACTIVE'
+ layout.operator("rigidbody.objects_add", text="Add Passive").type = 'PASSIVE'
+
+ layout.separator()
+
+ layout.operator("rigidbody.objects_remove", text="Remove")
+
+ layout.separator()
+
+ layout.operator("rigidbody.shape_change", text="Change Shape")
+ layout.operator("rigidbody.mass_calculate", text="Calculate Mass")
+ layout.operator("rigidbody.object_settings_copy", text="Copy from Active")
+ layout.operator("object.visual_transform_apply", text="Apply Transformation")
+ layout.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
+
+ layout.separator()
+
+ layout.operator("rigidbody.connect", text="Connect")
+
+
class VIEW3D_MT_object_clear(Menu):
bl_label = "Clear"
@@ -1475,7 +1624,7 @@ class VIEW3D_MT_object_clear(Menu):
class VIEW3D_MT_object_specials(Menu):
- bl_label = "Specials"
+ bl_label = "Object Context Menu"
@classmethod
def poll(cls, context):
@@ -1488,6 +1637,42 @@ class VIEW3D_MT_object_specials(Menu):
scene = context.scene
obj = context.object
+ layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN')
+ layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN')
+
+ layout.separator()
+
+ layout.operator("object.duplicate_move")
+ layout.operator("object.duplicate_move_linked")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_snap")
+ layout.menu("VIEW3D_MT_object_parent")
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("object.move_to_collection")
+
+ layout.separator()
+
+ layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
+
+ layout.separator()
+
+ layout.operator("object.delete", text="Delete...").use_global = False
+
+ if obj.type == 'MESH':
+
+ layout.separator()
+
+ layout.operator("object.shade_smooth", text="Smooth Shading")
+ layout.operator("object.shade_flat", text="Flat Shading")
+
+ layout.separator()
+
+ layout.operator("object.origin_set")
+ layout.operator("object.join")
+ layout.operator_menu_enum("object.convert", "target")
+
if obj.type == 'CAMERA':
layout.operator_context = 'INVOKE_REGION_WIN'
@@ -1544,59 +1729,46 @@ class VIEW3D_MT_object_specials(Menu):
props.input_scale = 0.01
props.header_text = "Empty Draw Size: %.3f"
- if obj.type == 'LAMP':
- lamp = obj.data
+ if obj.type == 'LIGHT':
+ light = obj.data
layout.operator_context = 'INVOKE_REGION_WIN'
- if scene.render.use_shading_nodes:
- emission_node = None
- if lamp.node_tree:
- for node in lamp.node_tree.nodes:
- if getattr(node, "type", None) == 'EMISSION':
- emission_node = node
- break
+ emission_node = None
+ if light.node_tree:
+ for node in light.node_tree.nodes:
+ if getattr(node, "type", None) == 'EMISSION':
+ emission_node = node
+ break
- if emission_node is not None:
- props = layout.operator("wm.context_modal_mouse", text="Strength")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.node_tree" \
- ".nodes[\"" + emission_node.name + "\"]" \
- ".inputs[\"Strength\"].default_value"
- props.header_text = "Lamp Strength: %.3f"
- props.input_scale = 0.1
-
- if lamp.type == 'AREA':
- props = layout.operator("wm.context_modal_mouse", text="Size X")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.size"
- props.header_text = "Lamp Size X: %.3f"
-
- if lamp.shape == 'RECTANGLE':
- props = layout.operator("wm.context_modal_mouse", text="Size Y")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.size_y"
- props.header_text = "Lamp Size Y: %.3f"
+ if emission_node is not None:
+ props = layout.operator("wm.context_modal_mouse", text="Strength")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.node_tree" \
+ ".nodes[\"" + emission_node.name + "\"]" \
+ ".inputs[\"Strength\"].default_value"
+ props.header_text = "Light Strength: %.3f"
+ props.input_scale = 0.1
- elif lamp.type in {'SPOT', 'POINT', 'SUN'}:
- props = layout.operator("wm.context_modal_mouse", text="Size")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.shadow_soft_size"
- props.header_text = "Lamp Size: %.3f"
- else:
- props = layout.operator("wm.context_modal_mouse", text="Energy")
+ if light.type == 'AREA':
+ props = layout.operator("wm.context_modal_mouse", text="Size X")
props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.energy"
- props.header_text = "Lamp Energy: %.3f"
+ props.data_path_item = "data.size"
+ props.header_text = "Light Size X: %.3f"
- if lamp.type in {'SPOT', 'AREA', 'POINT'}:
- props = layout.operator("wm.context_modal_mouse", text="Falloff Distance")
+ if light.shape in {'RECTANGLE', 'ELLIPSE'}:
+ props = layout.operator("wm.context_modal_mouse", text="Size Y")
props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.distance"
- props.input_scale = 0.1
- props.header_text = "Lamp Falloff Distance: %.1f"
+ props.data_path_item = "data.size_y"
+ props.header_text = "Light Size Y: %.3f"
+
+ elif light.type in {'SPOT', 'POINT', 'SUN'}:
+ props = layout.operator("wm.context_modal_mouse", text="Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.shadow_soft_size"
+ props.header_text = "Light Size: %.3f"
- if lamp.type == 'SPOT':
+ if light.type == 'SPOT':
layout.separator()
props = layout.operator("wm.context_modal_mouse", text="Spot Size")
props.data_path_iter = "selected_editable_objects"
@@ -1610,23 +1782,15 @@ class VIEW3D_MT_object_specials(Menu):
props.input_scale = -0.01
props.header_text = "Spot Blend: %.2f"
- if not scene.render.use_shading_nodes:
- props = layout.operator("wm.context_modal_mouse", text="Clip Start")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.shadow_buffer_clip_start"
- props.input_scale = 0.05
- props.header_text = "Clip Start: %.2f"
-
- props = layout.operator("wm.context_modal_mouse", text="Clip End")
- props.data_path_iter = "selected_editable_objects"
- props.data_path_item = "data.shadow_buffer_clip_end"
- props.input_scale = 0.05
- props.header_text = "Clip End: %.2f"
- layout.separator()
+class VIEW3D_MT_object_shading(Menu):
+ # XXX, this menu is a place to store shading operator in object mode
+ bl_label = "Shading"
- props = layout.operator("object.isolate_type_render")
- props = layout.operator("object.hide_render_clear_all")
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("object.shade_smooth", text="Smooth")
+ layout.operator("object.shade_flat", text="Flat")
class VIEW3D_MT_object_apply(Menu):
@@ -1712,21 +1876,21 @@ class VIEW3D_MT_object_track(Menu):
layout.operator_enum("object.track_clear", "type")
-class VIEW3D_MT_object_group(Menu):
- bl_label = "Group"
+class VIEW3D_MT_object_collection(Menu):
+ bl_label = "Collection"
def draw(self, context):
layout = self.layout
- layout.operator("group.create")
- # layout.operator_menu_enum("group.objects_remove", "group") # BUGGY
- layout.operator("group.objects_remove")
- layout.operator("group.objects_remove_all")
+ layout.operator("collection.create")
+ # layout.operator_menu_enum("collection.objects_remove", "collection") # BUGGY
+ layout.operator("collection.objects_remove")
+ layout.operator("collection.objects_remove_all")
layout.separator()
- layout.operator("group.objects_add_active")
- layout.operator("group.objects_remove_active")
+ layout.operator("collection.objects_add_active")
+ layout.operator("collection.objects_remove_active")
class VIEW3D_MT_object_constraints(Menu):
@@ -1777,23 +1941,23 @@ class VIEW3D_MT_make_single_user(Menu):
props = layout.operator("object.make_single_user", text="Object")
props.object = True
- props.obdata = props.material = props.texture = props.animation = False
+ props.obdata = props.material = props.animation = False
props = layout.operator("object.make_single_user", text="Object & Data")
props.object = props.obdata = True
- props.material = props.texture = props.animation = False
+ props.material = props.animation = False
- props = layout.operator("object.make_single_user", text="Object & Data & Materials+Tex")
- props.object = props.obdata = props.material = props.texture = True
+ props = layout.operator("object.make_single_user", text="Object & Data & Materials")
+ props.object = props.obdata = props.material = True
props.animation = False
- props = layout.operator("object.make_single_user", text="Materials+Tex")
- props.material = props.texture = True
+ props = layout.operator("object.make_single_user", text="Materials")
+ props.material = True
props.object = props.obdata = props.animation = False
props = layout.operator("object.make_single_user", text="Object Animation")
props.animation = True
- props.object = props.obdata = props.material = props.texture = False
+ props.object = props.obdata = props.material = False
class VIEW3D_MT_make_links(Menu):
@@ -1819,36 +1983,17 @@ class VIEW3D_MT_make_links(Menu):
layout.operator("object.join_uvs") # stupid place to add this!
-class VIEW3D_MT_object_game(Menu):
- bl_label = "Game"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("object.logic_bricks_copy", text="Copy Logic Bricks")
- layout.operator("object.game_physics_copy", text="Copy Physics Properties")
-
- layout.separator()
-
- layout.operator("object.game_property_copy", text="Replace Properties").operation = 'REPLACE'
- layout.operator("object.game_property_copy", text="Merge Properties").operation = 'MERGE'
- layout.operator_menu_enum("object.game_property_copy", "property", text="Copy Properties...")
-
- layout.separator()
-
- layout.operator("object.game_property_clear")
-
-
class VIEW3D_MT_brush(Menu):
bl_label = "Brush"
def draw(self, context):
layout = self.layout
+ tool_settings = context.tool_settings
settings = UnifiedPaintPanel.paint_settings(context)
brush = getattr(settings, "brush", None)
- ups = context.tool_settings.unified_paint_settings
+ ups = tool_settings.unified_paint_settings
layout.prop(ups, "use_unified_size", text="Unified Size")
layout.prop(ups, "use_unified_strength", text="Unified Strength")
if context.image_paint_object or context.vertex_paint_object:
@@ -1915,10 +2060,6 @@ class VIEW3D_MT_paint_vertex(Menu):
def draw(self, context):
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
layout.operator("paint.vertex_color_set")
layout.operator("paint.vertex_color_smooth")
layout.operator("paint.vertex_color_dirt")
@@ -1987,17 +2128,15 @@ class VIEW3D_MT_vertex_group(Menu):
class VIEW3D_MT_paint_weight(Menu):
bl_label = "Weights"
- def draw(self, context):
- layout = self.layout
-
- layout.menu("VIEW3D_MT_undo_redo")
+ @staticmethod
+ def draw_generic(layout, is_editmode=False):
- layout.separator()
+ if not is_editmode:
- layout.operator("paint.weight_from_bones", text="Assign Automatic From Bones").type = 'AUTOMATIC'
- layout.operator("paint.weight_from_bones", text="Assign From Bone Envelopes").type = 'ENVELOPES'
+ layout.operator("paint.weight_from_bones", text="Assign Automatic From Bones").type = 'AUTOMATIC'
+ layout.operator("paint.weight_from_bones", text="Assign From Bone Envelopes").type = 'ENVELOPES'
- layout.separator()
+ layout.separator()
layout.operator("object.vertex_group_normalize_all", text="Normalize All")
layout.operator("object.vertex_group_normalize", text="Normalize")
@@ -2014,16 +2153,21 @@ class VIEW3D_MT_paint_weight(Menu):
layout.operator("object.vertex_group_levels", text="Levels")
layout.operator("object.vertex_group_smooth", text="Smooth")
- props = layout.operator("object.data_transfer", text="Transfer Weights")
- props.use_reverse_transfer = True
- props.data_type = 'VGROUP_WEIGHTS'
+ if not is_editmode:
+ props = layout.operator("object.data_transfer", text="Transfer Weights")
+ props.use_reverse_transfer = True
+ props.data_type = 'VGROUP_WEIGHTS'
layout.operator("object.vertex_group_limit_total", text="Limit Total")
layout.operator("object.vertex_group_fix", text="Fix Deforms")
- layout.separator()
+ if not is_editmode:
+ layout.separator()
- layout.operator("paint.weight_set")
+ layout.operator("paint.weight_set")
+
+ def draw(self, context):
+ self.draw_generic(self.layout, is_editmode=False)
class VIEW3D_MT_sculpt(Menu):
@@ -2032,12 +2176,8 @@ class VIEW3D_MT_sculpt(Menu):
def draw(self, context):
layout = self.layout
- toolsettings = context.tool_settings
- sculpt = toolsettings.sculpt
-
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
+ tool_settings = context.tool_settings
+ sculpt = tool_settings.sculpt
layout.prop(sculpt, "use_symmetry_x")
layout.prop(sculpt, "use_symmetry_y")
@@ -2103,16 +2243,9 @@ class VIEW3D_MT_particle(Menu):
def draw(self, context):
layout = self.layout
+ tool_settings = context.tool_settings
- particle_edit = context.tool_settings.particle_edit
-
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.operator("particle.delete")
-
- layout.separator()
+ particle_edit = tool_settings.particle_edit
layout.operator("particle.mirror")
@@ -2131,14 +2264,19 @@ class VIEW3D_MT_particle(Menu):
layout.menu("VIEW3D_MT_particle_showhide")
+ layout.separator()
+
+ layout.operator("particle.delete")
+
class VIEW3D_MT_particle_specials(Menu):
- bl_label = "Specials"
+ bl_label = "Particle Context Menu"
def draw(self, context):
layout = self.layout
+ tool_settings = context.tool_settings
- particle_edit = context.tool_settings.particle_edit
+ particle_edit = tool_settings.particle_edit
layout.operator("particle.rekey")
@@ -2162,6 +2300,13 @@ class VIEW3D_MT_particle_specials(Menu):
if particle_edit.select_mode == 'POINT':
layout.separator()
+
+ layout.operator("particle.select_all", text="All").action = 'SELECT'
+ layout.operator("particle.select_all", text="None").action = 'DESELECT'
+ layout.operator("particle.select_all", text="Invert").action = 'INVERT'
+
+ layout.separator()
+
layout.operator("particle.select_roots")
layout.operator("particle.select_tips")
@@ -2176,9 +2321,7 @@ class VIEW3D_MT_particle_specials(Menu):
layout.separator()
- layout.operator("particle.select_all").action = 'TOGGLE'
layout.operator("particle.select_linked")
- layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu):
@@ -2191,10 +2334,6 @@ class VIEW3D_MT_pose(Menu):
def draw(self, context):
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_transform_armature")
layout.menu("VIEW3D_MT_pose_transform")
@@ -2387,30 +2526,41 @@ class VIEW3D_MT_pose_apply(Menu):
class VIEW3D_MT_pose_specials(Menu):
- bl_label = "Specials"
+ bl_label = "Pose Context Menu"
def draw(self, context):
layout = self.layout
- layout.operator("paint.weight_from_bones", text="Assign Automatic from Bones").type = 'AUTOMATIC'
- layout.operator("paint.weight_from_bones", text="Assign from Bone Envelopes").type = 'ENVELOPES'
+ layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
+
+ layout.separator()
+
+ layout.operator("pose.copy")
+ layout.operator("pose.paste").flipped = False
+ layout.operator("pose.paste", text="Paste X-Flipped Pose").flipped = True
layout.separator()
layout.operator("pose.select_constraint_target")
- layout.operator("pose.flip_names")
+
+ layout.separator()
+
+ layout.operator("pose.paths_calculate", text="Calculate")
+ layout.operator("pose.paths_clear", text="Clear")
layout.separator()
layout.operator("pose.paths_calculate")
layout.operator("pose.paths_clear")
- layout.operator("pose.user_transforms_clear")
- layout.operator("pose.user_transforms_clear", text="Clear User Transforms (All)").only_selected = False
- layout.operator("pose.relax")
layout.separator()
- layout.operator_menu_enum("pose.autoside_names", "axis")
+ layout.operator("pose.hide").unselected = False
+ layout.operator("pose.reveal")
+
+ layout.separator()
+
+ layout.operator("pose.user_transforms_clear")
class BoneOptions:
@@ -2466,16 +2616,9 @@ class VIEW3D_MT_edit_mesh(Menu):
def draw(self, context):
layout = self.layout
+ tool_settings = context.tool_settings
- toolsettings = context.tool_settings
-
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_mesh_delete")
-
- layout.separator()
+ with_bullet = bpy.app.build_options.bullet
layout.menu("VIEW3D_MT_transform")
layout.menu("VIEW3D_MT_mirror")
@@ -2487,85 +2630,124 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.separator()
- layout.operator("mesh.duplicate_move")
+ layout.operator("mesh.duplicate_move", text="Duplicate")
layout.menu("VIEW3D_MT_edit_mesh_extrude")
+ layout.operator("mesh.split")
+ layout.operator("mesh.bisect")
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_mesh_vertices")
- layout.menu("VIEW3D_MT_edit_mesh_edges")
- layout.menu("VIEW3D_MT_edit_mesh_faces")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_mesh_normals")
- layout.menu("VIEW3D_MT_edit_mesh_clean")
+ if with_bullet:
+ layout.operator("mesh.convex_hull")
layout.separator()
layout.operator("mesh.symmetrize")
layout.operator("mesh.symmetry_snap")
- layout.operator("mesh.bisect")
- layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
layout.separator()
- layout.prop(toolsettings, "use_mesh_automerge")
- layout.menu("VIEW3D_MT_edit_proportional")
+ layout.menu("VIEW3D_MT_edit_mesh_normals")
+ layout.menu("VIEW3D_MT_edit_mesh_shading")
+ layout.menu("VIEW3D_MT_edit_mesh_weights")
+ layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
layout.separator()
layout.menu("VIEW3D_MT_edit_mesh_showhide")
+ layout.operator_menu_enum("mesh.separate", "type")
+ layout.menu("VIEW3D_MT_edit_mesh_clean")
+ layout.menu("VIEW3D_MT_edit_mesh_delete")
class VIEW3D_MT_edit_mesh_specials(Menu):
- bl_label = "Specials"
+ bl_label = "Mesh Context Menu"
def draw(self, context):
layout = self.layout
+ select_mode = context.tool_settings.mesh_select_mode
+
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("mesh.subdivide", text="Subdivide").smoothness = 0.0
- layout.operator("mesh.subdivide", text="Subdivide Smooth").smoothness = 1.0
+ layout.operator("mesh.subdivide", text="Subdivide")
layout.separator()
- layout.operator("mesh.merge", text="Merge...")
- layout.operator("mesh.remove_doubles")
+ layout.operator("mesh.duplicate_move", text="Duplicate")
- layout.separator()
+ # Vertex Select Commands
+ if select_mode[0]:
+ layout.separator()
- layout.operator("mesh.hide", text="Hide").unselected = False
- layout.operator("mesh.reveal", text="Reveal")
- layout.operator("mesh.select_all", text="Select Inverse").action = 'INVERT'
+ layout.operator("mesh.edge_face_add", text="New Edge/Face from Vertices")
+ layout.operator("mesh.vert_connect_path", text="Connect Vertex Path")
+ layout.operator("mesh.vert_connect", text="Connect Vertex Pairs")
- layout.separator()
+ layout.separator()
- layout.operator("mesh.flip_normals")
- layout.operator("mesh.vertices_smooth", text="Smooth")
- layout.operator("mesh.vertices_smooth_laplacian", text="Laplacian Smooth")
+ layout.operator("mesh.vertices_smooth", text="Smooth")
+ layout.operator("mesh.vertices_smooth_laplacian", text="Smooth Laplacian")
- layout.separator()
+ layout.separator()
+ layout.operator("mesh.merge", text="Merge Vertices...")
+ layout.operator("mesh.remove_doubles", text="Remove Double Vertices")
+ layout.operator("mesh.dissolve_verts")
+ layout.operator("mesh.delete", text="Delete Vertices").type = 'VERT'
- layout.operator("mesh.inset")
- layout.operator("mesh.bevel", text="Bevel")
- layout.operator("mesh.bridge_edge_loops")
+ # Edge Select Commands
+ if select_mode[1]:
+ layout.separator()
- layout.separator()
+ layout.operator("mesh.bridge_edge_loops", text="Bridge Edge Loops")
- layout.operator("mesh.faces_shade_smooth")
- layout.operator("mesh.faces_shade_flat")
+ layout.separator()
+
+ layout.operator("mesh.dissolve_edges")
+ layout.operator("mesh.delete", text="Delete Edges").type = 'EDGE'
+
+ # Face Select Commands
+ if select_mode[2]:
+ layout.separator()
+
+ layout.operator("mesh.faces_shade_smooth")
+ layout.operator("mesh.faces_shade_flat")
+
+ layout.separator()
+
+ layout.operator("mesh.bridge_edge_loops", text="Bridge Faces")
+
+ layout.separator()
+
+ layout.operator("mesh.poke")
+
+ layout.separator()
+
+ props = layout.operator("mesh.quads_convert_to_tris")
+ props.quad_method = props.ngon_method = 'BEAUTY'
+ layout.operator("mesh.tris_convert_to_quads")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_uv_map", text="UV Unwrap Faces...")
+
+ layout.separator()
+
+ layout.operator("mesh.dissolve_faces")
+ layout.operator("mesh.delete", text="Delete Faces").type = 'FACE'
+
+ # General Mesh Commands
layout.separator()
- layout.operator("mesh.blend_from_shape")
- layout.operator("mesh.shape_propagate_to_all")
- layout.operator("mesh.shortest_path_select")
- layout.operator("mesh.sort_elements")
+ layout.menu("VIEW3D_MT_snap", text="Snap...")
+ layout.operator("transform.mirror", text="Mirror")
layout.operator("mesh.symmetrize")
layout.operator("mesh.symmetry_snap")
+ layout.separator()
+
+ layout.operator("mesh.hide", text="Hide").unselected = False
+ layout.operator("mesh.reveal", text="Reveal")
+
class VIEW3D_MT_edit_mesh_select_mode(Menu):
bl_label = "Mesh Select Mode"
@@ -2584,21 +2766,22 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
_extrude_funcs = {
'VERT': lambda layout:
- layout.operator("mesh.extrude_vertices_move", text="Vertices Only"),
+ layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices"),
'EDGE': lambda layout:
- layout.operator("mesh.extrude_edges_move", text="Edges Only"),
- 'FACE': lambda layout:
- layout.operator("mesh.extrude_faces_move", text="Individual Faces"),
+ layout.operator("mesh.extrude_edges_move", text="Extrude Edges"),
'REGION': lambda layout:
- layout.operator("view3d.edit_mesh_extrude_move_normal", text="Region"),
+ layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces"),
'REGION_VERT_NORMAL': lambda layout:
- layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Region (Vertex Normals)"),
+ layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"),
+ 'FACE': lambda layout:
+ layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"),
}
@staticmethod
def extrude_options(context):
+ tool_settings = context.tool_settings
+ select_mode = tool_settings.mesh_select_mode
mesh = context.object.data
- select_mode = context.tool_settings.mesh_select_mode
menu = []
if mesh.total_face_sel:
@@ -2620,45 +2803,43 @@ class VIEW3D_MT_edit_mesh_extrude(Menu):
class VIEW3D_MT_edit_mesh_vertices(Menu):
- bl_label = "Vertices"
+ bl_label = "Vertex"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- with_bullet = bpy.app.build_options.bullet
+ layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices"),
+ layout.operator("mesh.bevel", text="Bevel Vertices").vertex_only = True
- layout.operator("mesh.merge")
- layout.operator("mesh.remove_doubles")
- props = layout.operator("mesh.rip_move")
- props.MESH_OT_rip.use_fill = False
- props = layout.operator("mesh.rip_move", text="Rip Fill")
- props.MESH_OT_rip.use_fill = True
- layout.operator("mesh.rip_edge_move")
- layout.operator("mesh.split")
- layout.operator_menu_enum("mesh.separate", "type")
+ layout.separator()
+
+ layout.operator("mesh.edge_face_add", text="New Edge/Face from Vertices")
layout.operator("mesh.vert_connect_path", text="Connect Vertex Path")
- layout.operator("mesh.vert_connect", text="Connect Vertices")
- layout.operator("transform.vert_slide", text="Slide")
+ layout.operator("mesh.vert_connect", text="Connect Vertex Pairs")
layout.separator()
- layout.operator("mesh.mark_sharp", text="Mark Sharp Edges").use_verts = True
- props = layout.operator("mesh.mark_sharp", text="Clear Sharp Edges")
- props.use_verts = True
- props.clear = True
+ props = layout.operator("mesh.rip_move", text="Rip Vertices")
+ props.MESH_OT_rip.use_fill = False
+ props = layout.operator("mesh.rip_move", text="Rip Vertices and Fill")
+ props.MESH_OT_rip.use_fill = True
+ layout.operator("mesh.rip_edge_move", text="Rip Vertices and Extend")
layout.separator()
- layout.operator("mesh.bevel").vertex_only = True
- if with_bullet:
- layout.operator("mesh.convex_hull")
- layout.operator("mesh.vertices_smooth")
+ layout.operator("transform.vert_slide", text="Slide Vertices")
+ layout.operator("mesh.vertices_smooth", text="Smooth Vertices")
+
+ layout.separator()
layout.operator("mesh.blend_from_shape")
+ layout.operator("mesh.shape_propagate_to_all", text="Propagate to Shapes")
+
+ layout.separator()
- layout.operator("object.vertex_group_smooth")
- layout.operator("mesh.shape_propagate_to_all")
+ layout.operator("mesh.merge", text="Merge Vertices")
+ layout.operator("mesh.remove_doubles", text="Remove Double Vertices")
layout.separator()
@@ -2693,6 +2874,13 @@ class VIEW3D_MT_edit_mesh_edges_data(Menu):
layout.operator("mesh.mark_sharp")
layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
+ layout.operator("mesh.mark_sharp", text="Mark Sharp from Vertices").use_verts = True
+ props = layout.operator("mesh.mark_sharp", text="Clear Sharp from Vertices")
+ props.use_verts = True
+ props.clear = True
+
+ layout.separator()
+
layout.separator()
if with_freestyle:
@@ -2702,21 +2890,22 @@ class VIEW3D_MT_edit_mesh_edges_data(Menu):
class VIEW3D_MT_edit_mesh_edges(Menu):
- bl_label = "Edges"
+ bl_label = "Edge"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("mesh.edge_face_add")
- layout.operator("mesh.subdivide")
- layout.operator("mesh.subdivide_edgering")
- layout.operator("mesh.unsubdivide")
+ layout.operator("mesh.extrude_edges_move", text="Extrude Edges"),
+ layout.operator("mesh.bevel", text="Bevel Edges").vertex_only = False
+ layout.operator("mesh.bridge_edge_loops")
layout.separator()
- layout.menu("VIEW3D_MT_edit_mesh_edges_data")
+ layout.operator("mesh.subdivide")
+ layout.operator("mesh.subdivide_edgering")
+ layout.operator("mesh.unsubdivide")
layout.separator()
@@ -2725,22 +2914,16 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
- layout.operator("mesh.bevel").vertex_only = False
+ layout.operator("transform.edge_slide")
layout.operator("mesh.edge_split")
- layout.operator("mesh.bridge_edge_loops")
layout.separator()
- layout.operator("transform.edge_slide")
- layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False
- layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True
- layout.operator("mesh.loop_to_region")
- layout.operator("mesh.region_to_loop")
+ layout.menu("VIEW3D_MT_edit_mesh_edges_data")
-class VIEW3D_MT_edit_mesh_faces(Menu):
- bl_label = "Faces"
- bl_idname = "VIEW3D_MT_edit_mesh_faces"
+class VIEW3D_MT_edit_mesh_faces_data(Menu):
+ bl_label = "Face Data"
def draw(self, context):
layout = self.layout
@@ -2749,48 +2932,69 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("mesh.flip_normals")
- layout.operator("mesh.edge_face_add")
- layout.operator("mesh.fill")
- layout.operator("mesh.fill_grid")
- layout.operator("mesh.beautify_fill")
- layout.operator("mesh.inset")
- layout.operator("mesh.bevel").vertex_only = False
- layout.operator("mesh.solidify")
- layout.operator("mesh.intersect")
- layout.operator("mesh.intersect_boolean")
- layout.operator("mesh.wireframe")
+ layout.operator("mesh.colors_rotate")
+ layout.operator("mesh.colors_reverse")
+
+ layout.separator()
+
+ layout.operator("mesh.uvs_rotate")
+ layout.operator("mesh.uvs_reverse")
layout.separator()
if with_freestyle:
layout.operator("mesh.mark_freestyle_face").clear = False
layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True
- layout.separator()
+
+class VIEW3D_MT_edit_mesh_faces(Menu):
+ bl_label = "Face"
+ bl_idname = "VIEW3D_MT_edit_mesh_faces"
+
+ def draw(self, context):
+ layout = self.layout
+
+ with_freestyle = bpy.app.build_options.freestyle
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces"),
+ layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"),
+ layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"),
+
+ layout.separator()
+
+ layout.operator("mesh.inset")
layout.operator("mesh.poke")
props = layout.operator("mesh.quads_convert_to_tris")
props.quad_method = props.ngon_method = 'BEAUTY'
layout.operator("mesh.tris_convert_to_quads")
- layout.operator("mesh.face_split_by_edges")
+ layout.operator("mesh.solidify", text="Solidify Faces")
+ layout.operator("mesh.wireframe")
layout.separator()
- layout.operator("mesh.faces_shade_smooth")
- layout.operator("mesh.faces_shade_flat")
+ layout.operator("mesh.fill")
+ layout.operator("mesh.fill_grid")
+ layout.operator("mesh.beautify_fill")
- layout.operator("mesh.normals_make_consistent", text="Recalculate Normals").inside = False
+ layout.separator()
+
+ layout.operator("mesh.intersect")
+ layout.operator("mesh.intersect_boolean")
layout.separator()
- layout.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
+ layout.operator("mesh.face_split_by_edges")
layout.separator()
- layout.operator("mesh.uvs_rotate")
- layout.operator("mesh.uvs_reverse")
- layout.operator("mesh.colors_rotate")
- layout.operator("mesh.colors_reverse")
+ layout.operator("mesh.faces_shade_smooth")
+ layout.operator("mesh.faces_shade_flat")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_edit_mesh_faces_data")
class VIEW3D_MT_edit_mesh_normals(Menu):
@@ -2805,6 +3009,37 @@ class VIEW3D_MT_edit_mesh_normals(Menu):
layout.separator()
layout.operator("mesh.flip_normals")
+ layout.operator("mesh.set_normals_from_faces", text="Set From Faces")
+
+
+class VIEW3D_MT_edit_mesh_shading(Menu):
+ bl_label = "Shading"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("mesh.faces_shade_smooth", text="Smooth Faces")
+ layout.operator("mesh.faces_shade_flat", text="Flat Faces")
+
+ layout.separator()
+
+ layout.operator("mesh.mark_sharp", text="Smooth Edges").clear = True
+ layout.operator("mesh.mark_sharp", text="Sharp Edges")
+
+ layout.separator()
+
+ props = layout.operator("mesh.mark_sharp", text="Smooth Vertices")
+ props.use_verts = True
+ props.clear = True
+
+ layout.operator("mesh.mark_sharp", text="Sharp Vertices").use_verts = True
+
+
+class VIEW3D_MT_edit_mesh_weights(Menu):
+ bl_label = "Weights"
+
+ def draw(self, context):
+ VIEW3D_MT_paint_weight.draw_generic(self.layout, is_editmode=True)
class VIEW3D_MT_edit_mesh_clean(Menu):
@@ -2882,14 +3117,6 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
def draw_curve(self, context):
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_curve_delete")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_transform")
layout.menu("VIEW3D_MT_mirror")
layout.menu("VIEW3D_MT_snap")
@@ -2914,15 +3141,9 @@ def draw_curve(self, context):
layout.separator()
- layout.menu("VIEW3D_MT_edit_curve_clean")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_proportional")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_edit_curve_showhide")
+ layout.menu("VIEW3D_MT_edit_curve_clean")
+ layout.menu("VIEW3D_MT_edit_curve_delete")
class VIEW3D_MT_edit_curve(Menu):
@@ -2977,7 +3198,7 @@ class VIEW3D_MT_edit_curve_clean(Menu):
class VIEW3D_MT_edit_curve_specials(Menu):
- bl_label = "Specials"
+ bl_label = "Curve Context Menu"
def draw(self, context):
layout = self.layout
@@ -3024,9 +3245,6 @@ class VIEW3D_MT_edit_font(Menu):
def draw(self, context):
layout = self.layout
- # Break convention of having undo menu here,
- # instead place in "Edit" menu, matching the text menu.
-
layout.menu("VIEW3D_MT_edit_text_chars")
layout.separator()
@@ -3086,14 +3304,6 @@ class VIEW3D_MT_edit_meta(Menu):
def draw(self, context):
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.operator("mball.delete_metaelems", text="Delete...")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_transform")
layout.menu("VIEW3D_MT_mirror")
layout.menu("VIEW3D_MT_snap")
@@ -3104,11 +3314,8 @@ class VIEW3D_MT_edit_meta(Menu):
layout.separator()
- layout.menu("VIEW3D_MT_edit_proportional")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_edit_meta_showhide")
+ layout.operator("mball.delete_metaelems", text="Delete...")
class VIEW3D_MT_edit_meta_showhide(Menu):
@@ -3128,8 +3335,6 @@ class VIEW3D_MT_edit_lattice(Menu):
def draw(self, context):
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
layout.separator()
layout.menu("VIEW3D_MT_transform")
@@ -3145,10 +3350,6 @@ class VIEW3D_MT_edit_lattice(Menu):
layout.operator("object.vertex_parent_set")
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_proportional")
-
class VIEW3D_MT_edit_armature(Menu):
bl_label = "Armature"
@@ -3159,14 +3360,6 @@ class VIEW3D_MT_edit_armature(Menu):
edit_object = context.edit_object
arm = edit_object.data
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.operator("armature.delete")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_transform_armature")
layout.menu("VIEW3D_MT_mirror")
layout.menu("VIEW3D_MT_snap")
@@ -3213,9 +3406,13 @@ class VIEW3D_MT_edit_armature(Menu):
layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings")
+ layout.separator()
+
+ layout.operator("armature.delete")
+
class VIEW3D_MT_armature_specials(Menu):
- bl_label = "Specials"
+ bl_label = "Armature Context Menu"
def draw(self, context):
layout = self.layout
@@ -3279,18 +3476,10 @@ class VIEW3D_MT_edit_gpencil(Menu):
bl_label = "GPencil"
def draw(self, context):
- toolsettings = context.tool_settings
+ tool_settings = context.tool_settings
layout = self.layout
- layout.menu("VIEW3D_MT_undo_redo")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_edit_gpencil_delete")
-
- layout.separator()
-
layout.menu("VIEW3D_MT_edit_gpencil_transform")
layout.operator("transform.mirror", text="Mirror")
layout.menu("GPENCIL_MT_snap")
@@ -3298,7 +3487,7 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.separator()
layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True
- layout.prop_menu_enum(toolsettings.gpencil_sculpt, "tool", text="Sculpt Brush")
+ layout.prop_menu_enum(tool_settings.gpencil_sculpt, "tool", text="Sculpt Brush")
layout.separator()
@@ -3322,10 +3511,6 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.separator()
- layout.menu("VIEW3D_MT_edit_proportional")
-
- layout.separator()
-
layout.operator("gpencil.reveal")
layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True
layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
@@ -3340,6 +3525,10 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_edit_gpencil_delete")
+
class VIEW3D_MT_edit_gpencil_transform(Menu):
bl_label = "Transform"
@@ -3373,6 +3562,29 @@ class VIEW3D_MT_edit_gpencil_interpolate(Menu):
layout.operator("gpencil.interpolate_sequence", text="Sequence")
+class VIEW3D_MT_object_mode_pie(Menu):
+ bl_label = "Mode"
+
+ def draw(self, context):
+ layout = self.layout
+
+ pie = layout.menu_pie()
+ pie.operator_enum("OBJECT_OT_mode_set", "mode")
+
+
+class VIEW3D_MT_view_pie(Menu):
+ bl_label = "View"
+ bl_idname = "VIEW3D_MT_view_pie"
+
+ def draw(self, context):
+ layout = self.layout
+
+ pie = layout.menu_pie()
+ pie.operator_enum("VIEW3D_OT_view_axis", "type")
+ pie.operator("view3d.view_camera", text="View Camera", icon='CAMERA_DATA')
+ pie.operator("view3d.view_selected", text="View Selected", icon='ZOOM_SELECTED')
+
+
# ********** Panel **********
@@ -3400,37 +3612,65 @@ class VIEW3D_PT_view3d_properties(Panel):
view = context.space_data
- col = layout.column()
- col.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews)
- col.prop(view, "lens")
- col.label(text="Lock to Object:")
- col.prop(view, "lock_object", text="")
- lock_object = view.lock_object
- if lock_object:
- if lock_object.type == 'ARMATURE':
- col.prop_search(view, "lock_bone", lock_object.data,
- "edit_bones" if lock_object.mode == 'EDIT'
- else "bones",
- text="")
- else:
- col.prop(view, "lock_cursor", text="Lock to Cursor")
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
- col = layout.column()
- col.prop(view, "lock_camera")
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True)
+ col = flow.column()
- col = layout.column(align=True)
- col.label(text="Clip:")
- col.prop(view, "clip_start", text="Start")
- col.prop(view, "clip_end", text="End")
+ subcol = col.column()
+ subcol.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews)
+ subcol.prop(view, "lens", text="Focal Length")
subcol = col.column(align=True)
+ subcol.prop(view, "clip_start", text="Clip Start")
+ subcol.prop(view, "clip_end", text="End")
+
+ subcol.separator()
+
+ col = flow.column()
+
+ subcol = col.column()
subcol.enabled = not view.lock_camera_and_layers
- subcol.label(text="Local Camera:")
- subcol.prop(view, "camera", text="")
+ subcol.prop(view, "camera", text="Local Camera")
+
+ subcol = col.column(align=True)
+ subcol.prop(view, "use_render_border")
+ subcol.active = view.region_3d.view_perspective != 'CAMERA'
+
+
+class VIEW3D_PT_view3d_camera_lock(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+ bl_label = "Camera Lock"
+ bl_parent_id = "VIEW3D_PT_view3d_properties"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ view = context.space_data
col = layout.column(align=True)
- col.prop(view, "use_render_border")
- col.active = view.region_3d.view_perspective != 'CAMERA'
+ subcol = col.column()
+ subcol.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews)
+
+ subcol.prop(view, "lock_object")
+ lock_object = view.lock_object
+ if lock_object:
+ if lock_object.type == 'ARMATURE':
+ subcol.prop_search(
+ view, "lock_bone", lock_object.data,
+ "edit_bones" if lock_object.mode == 'EDIT'
+ else "bones",
+ text=""
+ )
+ else:
+ subcol.prop(view, "lock_cursor", text="Lock to 3D Cursor")
+
+ col.prop(view, "lock_camera")
class VIEW3D_PT_view3d_cursor(Panel):
@@ -3440,527 +3680,957 @@ class VIEW3D_PT_view3d_cursor(Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
view = context.space_data
+
layout.column().prop(view, "cursor_location", text="Location")
-class VIEW3D_PT_view3d_name(Panel):
+class VIEW3D_PT_object_type_visibility(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Item"
+ bl_region_type = 'HEADER'
+ bl_label = "View Object Types"
+ bl_ui_units_x = 6
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ view = context.space_data
+
+ col = layout.column()
+
+ attr_object_types = (
+ # Geometry
+ "mesh",
+ "curve",
+ "surf",
+ "meta",
+ "font",
+ None,
+ # Other
+ "armature",
+ "lattice",
+ "empty",
+ "camera",
+ "lamp",
+ "light_probe",
+ "speaker",
+ )
+
+ for attr in attr_object_types:
+ if attr is None:
+ col.separator()
+ continue
+
+ attr_v = "show_object_viewport_" f"{attr:s}"
+ attr_s = "show_object_select_" f"{attr:s}"
+
+ icon_s = 'RESTRICT_SELECT_OFF' if getattr(view, attr_s) else 'RESTRICT_SELECT_ON'
+
+ row = col.row(align=True)
+ row.prop(view, attr_v)
+ row.active = getattr(view, attr_v)
+ row.prop(view, attr_s, text="", icon=icon_s, emboss=False)
+
+
+class VIEW3D_PT_shading(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Shading"
+ bl_ui_units_x = 11
+
+ def draw(self, context):
+ pass
+
+
+class VIEW3D_PT_shading_lighting(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Lighting"
+ bl_parent_id = 'VIEW3D_PT_shading'
+
+ def draw(self, context):
+ layout = self.layout
+
+ view = context.space_data
+ shading = view.shading
+
+ col = layout.column()
+ split = col.split(0.9)
+
+ if shading.type == 'SOLID':
+ split.row().prop(shading, "light", expand=True)
+ col = split.column()
+
+ split = layout.split(0.9)
+ col = split.column()
+ sub = col.row()
+ sub.scale_y = 0.6 # smaller matcap/hdri preview
+
+ if shading.light == 'STUDIO':
+ sub.template_icon_view(shading, "studio_light", show_labels=True, scale=3)
+
+ if shading.selected_studio_light.orientation == 'WORLD':
+ col.prop(shading, "studiolight_rotate_z", text="Rotation")
+
+ col = split.column()
+ col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES')
+
+ elif shading.light == 'MATCAP':
+ sub.template_icon_view(shading, "studio_light", show_labels=True, scale=3)
+
+ col = split.column()
+ col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES')
+ col.operator('VIEW3D_OT_toggle_matcap_flip', emboss=False, text="", icon='ARROW_LEFTRIGHT')
+
+ elif shading.type == 'MATERIAL':
+ col.prop(shading, "use_scene_lights")
+ col.prop(shading, "use_scene_world")
+
+ if not shading.use_scene_world:
+ col = layout.column()
+ split = col.split(0.9)
+
+ col = split.column()
+ sub = col.row()
+ sub.scale_y = 0.6
+ sub.template_icon_view(shading, "studio_light", show_labels=True, scale=3)
+
+ col = split.column()
+ col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES')
+
+ if shading.selected_studio_light.orientation == 'WORLD':
+ split = layout.split(0.9)
+ col = split.column()
+ col.prop(shading, "studiolight_rotate_z", text="Rotation")
+ col.prop(shading, "studiolight_background_alpha")
+ col = split.column() # to align properly with above
+
+
+class VIEW3D_PT_shading_color(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Color"
+ bl_parent_id = 'VIEW3D_PT_shading'
@classmethod
def poll(cls, context):
- return (context.active_object is not None)
+ view = context.space_data
+ shading = view.shading
+ return shading.type == 'SOLID'
def draw(self, context):
layout = self.layout
- ob = context.active_object
- row = layout.row()
- row.label(text="", icon='OBJECT_DATA')
- row.prop(ob, "name", text="")
+ view = context.space_data
+ shading = view.shading
- if ob.type == 'ARMATURE' and ob.mode in {'EDIT', 'POSE'}:
- bone = context.active_bone
- if bone:
- row = layout.row()
- row.label(text="", icon='BONE_DATA')
- row.prop(bone, "name", text="")
+ layout.row().prop(shading, "color_type", expand=True)
+ if shading.color_type == 'SINGLE':
+ layout.row().prop(shading, "single_color", text="")
-class VIEW3D_PT_view3d_display(Panel):
+
+class VIEW3D_PT_shading_options(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Display"
- bl_options = {'DEFAULT_CLOSED'}
+ bl_region_type = 'HEADER'
+ bl_label = "Options"
+ bl_parent_id = 'VIEW3D_PT_shading'
+
+ @classmethod
+ def poll(cls, context):
+ view = context.space_data
+ shading = view.shading
+ return shading.type == 'SOLID'
def draw(self, context):
layout = self.layout
view = context.space_data
- scene = context.scene
+ shading = view.shading
col = layout.column()
- col.prop(view, "show_only_render")
- col.prop(view, "show_world")
+
+ is_xray = shading.show_xray
+ is_shadows = shading.show_shadows
+
+ icon_x = 'CHECKBOX_HLT' if is_xray else 'CHECKBOX_DEHLT'
+ row = col.row()
+ row.prop(shading, "show_xray", text="")
+ sub = row.row()
+ sub.active = is_xray
+ sub.prop(shading, "xray_alpha", text="X-Ray")
+
+ icon_s = 'CHECKBOX_HLT' if is_shadows else 'CHECKBOX_DEHLT'
+ row = col.row()
+ row.prop(shading, "show_shadows", text="")
+ row.active = not is_xray
+ sub = row.row(align=True)
+ sub.active = is_shadows
+ sub.prop(shading, "shadow_intensity", text="Shadow")
+ sub.popover(
+ panel="VIEW3D_PT_shading_options_shadow",
+ icon='SCRIPTWIN',
+ text=""
+ )
col = layout.column()
- display_all = not view.show_only_render
- col.active = display_all
- col.prop(view, "show_outline_selected")
- col.prop(view, "show_all_objects_origin")
- col.prop(view, "show_relationship_lines")
+ row = col.row()
+ row.active = not is_xray
+ row.prop(shading, "show_cavity")
+
+ if shading.show_cavity:
+ sub = col.row(align=True)
+ sub.active = not shading.show_xray and shading.show_cavity
+ sub.prop(shading, "cavity_ridge_factor")
+ sub.prop(shading, "cavity_valley_factor")
+ sub.popover(
+ panel="VIEW3D_PT_shading_options_ssao",
+ icon='SCRIPTWIN',
+ text=""
+ )
+
+ row = layout.split()
+ row.prop(shading, "show_object_outline")
+ sub = row.row()
+ sub.active = shading.show_object_outline
+ sub.prop(shading, "object_outline_color", text="")
col = layout.column()
- col.active = display_all
- split = col.split(percentage=0.55)
- split.prop(view, "show_floor", text="Grid Floor")
+ if not shading.light == 'MATCAP':
+ col.prop(shading, "show_specular_highlight")
- row = split.row(align=True)
- row.prop(view, "show_axis_x", text="X", toggle=True)
- row.prop(view, "show_axis_y", text="Y", toggle=True)
- row.prop(view, "show_axis_z", text="Z", toggle=True)
+ col.prop(view, "show_world")
- sub = col.column(align=True)
- sub.active = bool(view.show_floor or view.region_quadviews or not view.region_3d.is_perspective)
- subsub = sub.column(align=True)
- subsub.active = view.show_floor
- subsub.prop(view, "grid_lines", text="Lines")
- sub.prop(view, "grid_scale", text="Scale")
- subsub = sub.column(align=True)
- subsub.active = scene.unit_settings.system == 'NONE'
- subsub.prop(view, "grid_subdivisions", text="Subdivisions")
- layout.separator()
+class VIEW3D_PT_shading_options_shadow(Panel):
+ bl_label = "Shadow Settings"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
- layout.operator("screen.region_quadview", text="Toggle Quad View")
+ @classmethod
+ def poll(cls, context):
+ return True
- if view.region_quadviews:
- region = view.region_quadviews[2]
- col = layout.column()
- col.prop(region, "lock_rotation")
- row = col.row()
- row.enabled = region.lock_rotation
- row.prop(region, "show_sync_view")
- row = col.row()
- row.enabled = region.lock_rotation and region.show_sync_view
- row.prop(region, "use_box_clip")
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+ col = layout.column()
+ col.prop(scene.display, "light_direction")
+ col.prop(scene.display, "shadow_shift")
-class VIEW3D_PT_view3d_stereo(Panel):
+
+class VIEW3D_PT_shading_options_ssao(Panel):
+ bl_label = "SSAO Settings"
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Stereoscopy"
- bl_options = {'DEFAULT_CLOSED'}
+ bl_region_type = 'HEADER'
@classmethod
def poll(cls, context):
+ return True
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
scene = context.scene
- return scene.render.use_multiview
+
+ col = layout.column(align=True)
+ col.prop(scene.display, "matcap_ssao_samples")
+ col.prop(scene.display, "matcap_ssao_distance")
+ col.prop(scene.display, "matcap_ssao_attenuation")
+
+
+class VIEW3D_PT_overlay(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Overlays"
+ bl_ui_units_x = 13
+
+ def draw(self, context):
+ pass
+
+
+class VIEW3D_PT_overlay_manipulators(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Manipulators"
+
+ def draw_header(self, context):
+ view = context.space_data
+ self.layout.prop(view, "show_manipulator", text="")
def draw(self, context):
layout = self.layout
+
view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
+
+ col = layout.column()
+ col.active = display_all
+
+ row = col.row(align=True)
+ row.active = view.show_manipulator
+ row.prop(view, "show_manipulator_navigate", text="Navigate", toggle=True)
+ row.prop(view, "show_manipulator_context", text="Active Object", toggle=True)
+ row.prop(view, "show_manipulator_tool", text="Active Tools", toggle=True)
- basic_stereo = context.scene.render.views_format == 'STEREO_3D'
+
+class VIEW3D_PT_overlay_guides(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Guides"
+
+ def draw(self, context):
+ layout = self.layout
+
+ view = context.space_data
+ overlay = view.overlay
+ shading = view.shading
+ display_all = overlay.show_overlays
col = layout.column()
- col.row().prop(view, "stereo_3d_camera", expand=True)
+ col.active = display_all
- col.label(text="Display:")
- row = col.row()
- row.active = basic_stereo
- row.prop(view, "show_stereo_3d_cameras")
- row = col.row()
- row.active = basic_stereo
- split = row.split()
- split.prop(view, "show_stereo_3d_convergence_plane")
- split = row.split()
- split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha")
- split.active = view.show_stereo_3d_convergence_plane
- row = col.row()
- split = row.split()
- split.prop(view, "show_stereo_3d_volume")
- split = row.split()
- split.prop(view, "stereo_3d_volume_alpha", text="Alpha")
+ split = col.split()
+ sub = split.column()
+ sub.prop(overlay, "show_floor", text="Grid")
+
+ if overlay.show_floor:
+ sub = col.column(align=True)
+ sub.active = bool(overlay.show_floor or view.region_quadviews or not view.region_3d.is_perspective)
+ subsub = sub.row(align=True)
+ subsub.active = overlay.show_floor
+ subsub.prop(overlay, "grid_scale", text="Scale")
+ subsub.prop(overlay, "grid_subdivisions", text="Subdivisions")
+
+ sub = split.column()
+ row = sub.row()
+ row.label(text="Axes")
+ subrow = row.row(align=True)
+ subrow.prop(overlay, "show_axis_x", text="X", toggle=True)
+ subrow.prop(overlay, "show_axis_y", text="Y", toggle=True)
+ subrow.prop(overlay, "show_axis_z", text="Z", toggle=True)
-class VIEW3D_PT_view3d_shading(Panel):
+ split = col.split()
+ sub = split.column()
+ sub.prop(overlay, "show_text", text="Text Info")
+ sub = split.column()
+ sub.prop(overlay, "show_cursor", text="3D Cursor")
+
+ if shading.type == 'MATERIAL':
+ col.prop(overlay, "show_look_dev")
+
+
+class VIEW3D_PT_overlay_object(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Shading"
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Objects"
def draw(self, context):
layout = self.layout
+ view = context.space_data
+ overlay = view.overlay
+ shading = view.shading
+ display_all = overlay.show_overlays
+
+ col = layout.column(align=True)
+ col.active = display_all
+
+ split = col.split()
+
+ sub = split.column(align=True)
+ sub.prop(overlay, "show_ornaments", text="Ornaments")
+ sub.prop(overlay, "show_relationship_lines")
+ sub.prop(overlay, "show_outline_selected")
+
+ sub = split.column(align=True)
+ sub.prop(overlay, "show_bones", text="Bones")
+ sub.prop(overlay, "show_motion_paths")
+ sub.prop(overlay, "show_object_origins", text="Origins")
+ subsub = sub.column()
+ subsub.active = overlay.show_object_origins
+ subsub.prop(overlay, "show_object_origins_all", text="Origins (All)")
+
+class VIEW3D_PT_overlay_geometry(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Geometry"
+
+ def draw(self, context):
+ layout = self.layout
view = context.space_data
- scene = context.scene
- gs = scene.game_settings
- obj = context.object
+ overlay = view.overlay
+ display_all = overlay.show_overlays
col = layout.column()
+ col.active = display_all
- if not scene.render.use_shading_nodes:
- col.prop(gs, "material_mode", text="")
-
- if view.viewport_shade == 'SOLID':
- col.prop(view, "show_textured_solid")
- col.prop(view, "use_matcap")
- if view.use_matcap:
- col.template_icon_view(view, "matcap_icon")
- if view.viewport_shade == 'TEXTURED' or context.mode == 'PAINT_TEXTURE':
- if scene.render.use_shading_nodes or gs.material_mode != 'GLSL':
- col.prop(view, "show_textured_shadeless")
-
- col.prop(view, "show_backface_culling")
-
- if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}:
- if obj and obj.mode == 'EDIT':
- col.prop(view, "show_occlude_wire")
-
- fx_settings = view.fx_settings
-
- if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}:
- sub = col.column()
- sub.active = view.region_3d.view_perspective == 'CAMERA'
- sub.prop(fx_settings, "use_dof")
- col.prop(fx_settings, "use_ssao", text="Ambient Occlusion")
- if fx_settings.use_ssao:
- ssao_settings = fx_settings.ssao
- subcol = col.column(align=True)
- subcol.prop(ssao_settings, "factor")
- subcol.prop(ssao_settings, "distance_max")
- subcol.prop(ssao_settings, "attenuation")
- subcol.prop(ssao_settings, "samples")
- subcol.prop(ssao_settings, "color")
-
-
-class VIEW3D_PT_view3d_motion_tracking(Panel):
+ row = col.row()
+ row.prop(overlay, "show_wireframes", text="")
+ sub = row.row()
+ sub.active = overlay.show_wireframes
+ sub.prop(overlay, "wireframe_threshold", text="Wireframe")
+
+ col = layout.column(align=True)
+ col.active = display_all
+
+ split = col.split()
+ sub = split.column(align=True)
+ sub.prop(overlay, "show_backface_culling")
+
+ sub = split.column(align=True)
+ #sub.prop(overlay, "show_onion_skins")
+ sub.prop(overlay, "show_face_orientation")
+
+
+class VIEW3D_PT_overlay_motion_tracking(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Motion Tracking"
- bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
view = context.space_data
-
self.layout.prop(view, "show_reconstruction", text="")
def draw(self, context):
layout = self.layout
-
view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
col = layout.column()
- col.active = view.show_reconstruction
- col.prop(view, "show_camera_path", text="Camera Path")
- col.prop(view, "show_bundle_names", text="3D Marker Names")
- col.label(text="Track Type and Size:")
- row = col.row(align=True)
- row.prop(view, "tracks_draw_type", text="")
- row.prop(view, "tracks_draw_size", text="")
+ col.active = display_all
+
+ if view.show_reconstruction:
+ split = col.split()
+
+ sub = split.column(align=True)
+ sub.active = view.show_reconstruction
+ sub.prop(view, "show_camera_path", text="Camera Path")
+ sub = split.column()
+ sub.prop(view, "show_bundle_names", text="Marker Names")
-class VIEW3D_PT_view3d_meshdisplay(Panel):
+ col = layout.column()
+ col.label(text="Tracks:")
+ row = col.row(align=True)
+ row.prop(view, "tracks_draw_type", text="")
+ row.prop(view, "tracks_draw_size", text="Size")
+
+
+class VIEW3D_PT_overlay_edit_mesh(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Mesh Display"
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Mesh Edit Mode"
@classmethod
def poll(cls, context):
- # The active object check is needed because of local-mode
- return (context.active_object and (context.mode == 'EDIT_MESH'))
+ return context.mode == 'EDIT_MESH'
def draw(self, context):
layout = self.layout
+
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
+ data = context.active_object.data
with_freestyle = bpy.app.build_options.freestyle
- mesh = context.active_object.data
- scene = context.scene
+ col = layout.column()
+ col.active = display_all
- split = layout.split()
+ split = col.split()
- col = split.column()
- col.label(text="Overlays:")
- col.prop(mesh, "show_faces", text="Faces")
- col.prop(mesh, "show_edges", text="Edges")
- col.prop(mesh, "show_edge_crease", text="Creases")
- if with_freestyle:
- col.prop(mesh, "show_edge_seams", text="Seams")
+ sub = split.column()
+ sub.prop(data, "show_edges", text="Edges")
+ sub = split.column()
+ sub.prop(data, "show_faces", text="Faces")
- layout.prop(mesh, "show_weight")
+ row = col.row(align=True)
+ row.prop(data, "show_edge_crease", text="Creases", toggle=True)
+ row.prop(data, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural, toggle=True)
+ row.prop(data, "show_edge_bevel_weight", text="Bevel", toggle=True)
- col = split.column()
- col.label()
if not with_freestyle:
- col.prop(mesh, "show_edge_seams", text="Seams")
- col.prop(mesh, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural)
- col.prop(mesh, "show_edge_bevel_weight", text="Bevel")
- if with_freestyle:
- col.prop(mesh, "show_freestyle_edge_marks", text="Edge Marks")
- col.prop(mesh, "show_freestyle_face_marks", text="Face Marks")
+ row.prop(data, "show_edge_seams", text="Seams", toggle=True)
- col = layout.column()
- col.separator()
- col.label(text="Normals:")
- row = col.row(align=True)
+class VIEW3D_PT_overlay_edit_mesh_shading(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh'
+ bl_label = "Shading"
- row.prop(mesh, "show_normal_vertex", text="", icon='VERTEXSEL')
- row.prop(mesh, "show_normal_loop", text="", icon='LOOPSEL')
- row.prop(mesh, "show_normal_face", text="", icon='FACESEL')
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'EDIT_MESH'
- sub = row.row(align=True)
- sub.active = mesh.show_normal_vertex or mesh.show_normal_face or mesh.show_normal_loop
- sub.prop(scene.tool_settings, "normal_size", text="Size")
+ def draw(self, context):
+ layout = self.layout
- col.separator()
- split = layout.split()
- col = split.column()
- col.label(text="Edge Info:")
- col.prop(mesh, "show_extra_edge_length", text="Length")
- col.prop(mesh, "show_extra_edge_angle", text="Angle")
- col = split.column()
- col.label(text="Face Info:")
- col.prop(mesh, "show_extra_face_area", text="Area")
- col.prop(mesh, "show_extra_face_angle", text="Angle")
- if context.user_preferences.view.show_developer_ui:
- layout.prop(mesh, "show_extra_indices")
-
-
-class VIEW3D_PT_view3d_meshstatvis(Panel):
+ view = context.space_data
+ overlay = view.overlay
+ tool_settings = context.tool_settings
+ display_all = overlay.show_overlays
+ data = context.active_object.data
+ statvis = tool_settings.statvis
+
+ col = layout.column()
+ col.active = display_all
+
+ col.prop(overlay, "show_occlude_wire")
+
+ col.prop(overlay, "show_weight", text="Vertex Group Weights")
+ if overlay.show_weight:
+ row = col.split()
+ row.label(text="Zero Weights")
+ row.prop(tool_settings, "vertex_group_user", text="")
+
+ col.prop(data, "show_statvis", text="Mesh Analysis")
+ if data.show_statvis:
+ col = col.column()
+
+ sub = col.split()
+ sub.active = data.show_statvis
+ sub.label(text="Type")
+ sub.prop(statvis, "type", text="")
+
+ statvis_type = statvis.type
+ if statvis_type == 'OVERHANG':
+ row = col.row(align=True)
+ row.prop(statvis, "overhang_min", text="Minimum")
+ row.prop(statvis, "overhang_max", text="Maximum")
+ col.row().prop(statvis, "overhang_axis", expand=True)
+ elif statvis_type == 'THICKNESS':
+ row = col.row(align=True)
+ row.prop(statvis, "thickness_min", text="Minimum")
+ row.prop(statvis, "thickness_max", text="Maximum")
+ col.prop(statvis, "thickness_samples")
+ elif statvis_type == 'INTERSECT':
+ pass
+ elif statvis_type == 'DISTORT':
+ row = col.row(align=True)
+ row.prop(statvis, "distort_min", text="Minimum")
+ row.prop(statvis, "distort_max", text="Maximum")
+ elif statvis_type == 'SHARP':
+ row = col.row(align=True)
+ row.prop(statvis, "sharp_min", text="Minimum")
+ row.prop(statvis, "sharp_max", text="Maximum")
+
+
+class VIEW3D_PT_overlay_edit_mesh_measurement(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Mesh Analysis"
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh'
+ bl_label = "Measurement"
@classmethod
def poll(cls, context):
- # The active object check is needed because of local-mode
- return (context.active_object and (context.mode == 'EDIT_MESH'))
+ return context.mode == 'EDIT_MESH'
- def draw_header(self, context):
- mesh = context.active_object.data
+ def draw(self, context):
+ layout = self.layout
- self.layout.prop(mesh, "show_statvis", text="")
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
+ data = context.active_object.data
+
+ col = layout.column()
+ col.active = display_all
+
+ split = col.split()
+
+ sub = split.column()
+ sub.prop(data, "show_extra_edge_length", text="Edge Length")
+ sub.prop(data, "show_extra_edge_angle", text="Edge Angle")
+
+ sub = split.column()
+ sub.prop(data, "show_extra_face_area", text="Face Area")
+ sub.prop(data, "show_extra_face_angle", text="Face Angle")
+
+
+class VIEW3D_PT_overlay_edit_mesh_normals(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh'
+ bl_label = "Normals"
+
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'EDIT_MESH'
def draw(self, context):
layout = self.layout
- mesh = context.active_object.data
- statvis = context.tool_settings.statvis
- layout.active = mesh.show_statvis
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
- layout.prop(statvis, "type")
- statvis_type = statvis.type
- if statvis_type == 'OVERHANG':
- row = layout.row(align=True)
- row.prop(statvis, "overhang_min", text="")
- row.prop(statvis, "overhang_max", text="")
- layout.row().prop(statvis, "overhang_axis", expand=True)
- elif statvis_type == 'THICKNESS':
- row = layout.row(align=True)
- row.prop(statvis, "thickness_min", text="")
- row.prop(statvis, "thickness_max", text="")
- layout.prop(statvis, "thickness_samples")
- elif statvis_type == 'INTERSECT':
- pass
- elif statvis_type == 'DISTORT':
- row = layout.row(align=True)
- row.prop(statvis, "distort_min", text="")
- row.prop(statvis, "distort_max", text="")
- elif statvis_type == 'SHARP':
- row = layout.row(align=True)
- row.prop(statvis, "sharp_min", text="")
- row.prop(statvis, "sharp_max", text="")
+ col = layout.column()
+ col.active = display_all
+
+ row = col.row(align=True)
+ row.prop(overlay, "show_vertex_normals", text="", icon='VERTEXSEL')
+ row.prop(overlay, "show_split_normals", text="", icon='LOOPSEL')
+ row.prop(overlay, "show_face_normals", text="", icon='FACESEL')
+
+ sub = row.row(align=True)
+ sub.active = overlay.show_vertex_normals or overlay.show_face_normals or overlay.show_split_normals
+ sub.prop(overlay, "normals_length", text="Size")
-class VIEW3D_PT_view3d_curvedisplay(Panel):
+class VIEW3D_PT_overlay_edit_mesh_freestyle(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Curve Display"
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Freestyle"
@classmethod
def poll(cls, context):
- return (context.mode == 'EDIT_CURVE')
+ return context.mode == 'EDIT_MESH' and bpy.app.build_options.freestyle
def draw(self, context):
layout = self.layout
- curve = context.active_object.data
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
+ data = context.active_object.data
col = layout.column()
+ col.active = display_all
+
row = col.row()
- row.prop(curve, "show_handles", text="Handles")
- row.prop(curve, "show_normal_face", text="Normals")
- col.prop(context.scene.tool_settings, "normal_size", text="Normal Size")
+ row.prop(data, "show_freestyle_edge_marks", text="Edge Marks")
+ row.prop(data, "show_freestyle_face_marks", text="Face Marks")
+ row.prop(data, "show_edge_seams", text="Seams")
-class VIEW3D_PT_background_image(Panel):
+class VIEW3D_PT_overlay_edit_mesh_developer(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Background Images"
- bl_options = {'DEFAULT_CLOSED'}
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh'
+ bl_label = "Developer"
- def draw_header(self, context):
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'EDIT_MESH' and context.user_preferences.view.show_developer_ui
+
+ def draw(self, context):
+ layout = self.layout
+
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
+ data = context.active_object.data
+
+ col = layout.column()
+ col.active = display_all
+
+ col.prop(data, "show_extra_indices", text="Indices")
+
+
+class VIEW3D_PT_overlay_edit_curve(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Edit Curve"
+
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'EDIT_CURVE'
+
+ def draw(self, context):
+ layout = self.layout
view = context.space_data
+ data = context.active_object.data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
+
+ col = layout.column()
+ col.active = display_all
+
+ row = col.row()
+ row.prop(data, "show_handles", text="Handles")
+ row.prop(data, "show_normal_face", text="Normals")
+
+
+class VIEW3D_PT_overlay_sculpt(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_context = ".sculpt_mode"
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Sculpt"
- self.layout.prop(view, "show_background_images", text="")
+ @classmethod
+ def poll(cls, context):
+ return (
+ context.mode == 'SCULPT' and
+ (context.sculpt_object and context.tool_settings.sculpt)
+ )
def draw(self, context):
layout = self.layout
+ tool_settings = context.tool_settings
+ sculpt = tool_settings.sculpt
+ layout.prop(sculpt, "show_diffuse_color")
+ layout.prop(sculpt, "show_mask")
+
+
+class VIEW3D_PT_overlay_pose(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Pose Mode"
+
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'POSE'
+
+ def draw(self, context):
+ layout = self.layout
view = context.space_data
- use_multiview = context.scene.render.use_multiview
+ overlay = view.overlay
+ display_all = overlay.show_overlays
col = layout.column()
- col.operator("view3d.background_image_add", text="Add Image")
-
- for i, bg in enumerate(view.background_images):
- layout.active = view.show_background_images
- box = layout.box()
- row = box.row(align=True)
- row.prop(bg, "show_expanded", text="", emboss=False)
- if bg.source == 'IMAGE' and bg.image:
- row.prop(bg.image, "name", text="", emboss=False)
- elif bg.source == 'MOVIE_CLIP' and bg.clip:
- row.prop(bg.clip, "name", text="", emboss=False)
- else:
- row.label(text="Not Set")
+ col.active = display_all
+ col.prop(overlay, "show_transparent_bones")
- if bg.show_background_image:
- row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_OFF')
- else:
- row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_ON')
+ row = col.row()
+ row.prop(overlay, "show_bone_select", text="")
+ sub = row.row()
+ sub.active = display_all and overlay.show_bone_select
+ sub.prop(overlay, "bone_select_alpha", text="Fade Geometry")
- row.operator("view3d.background_image_remove", text="", emboss=False, icon='X').index = i
- box.prop(bg, "view_axis", text="Axis")
+class VIEW3D_PT_overlay_edit_armature(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Edit Armature"
- if bg.show_expanded:
- row = box.row()
- row.prop(bg, "source", expand=True)
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'EDIT_ARMATURE'
- has_bg = False
- if bg.source == 'IMAGE':
- row = box.row()
- row.template_ID(bg, "image", open="image.open")
- if bg.image is not None:
- box.template_image(bg, "image", bg.image_user, compact=True)
- has_bg = True
+ def draw(self, context):
+ layout = self.layout
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
- if use_multiview and bg.view_axis in {'CAMERA', 'ALL'}:
- box.prop(bg.image, "use_multiview")
+ col = layout.column()
+ col.active = display_all
+ col.prop(overlay, "show_transparent_bones")
- column = box.column()
- column.active = bg.image.use_multiview
- column.label(text="Views Format:")
- column.row().prop(bg.image, "views_format", expand=True)
+class VIEW3D_PT_overlay_paint(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = ""
- sub = column.box()
- sub.active = bg.image.views_format == 'STEREO_3D'
- sub.template_image_stereo_3d(bg.image.stereo_3d_format)
+ @classmethod
+ def poll(cls, context):
+ return context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}
- elif bg.source == 'MOVIE_CLIP':
- box.prop(bg, "use_camera_clip")
+ def draw_header(self, context):
+ layout = self.layout
+ layout.label(text={
+ 'PAINT_TEXTURE': "Texture Paint",
+ 'PAINT_VERTEX': "Vertex Paint",
+ 'PAINT_WEIGHT': "Weight Paint",
+ }[context.mode])
- column = box.column()
- column.active = not bg.use_camera_clip
- column.template_ID(bg, "clip", open="clip.open")
+ def draw(self, context):
+ layout = self.layout
+ view = context.space_data
+ overlay = view.overlay
+ display_all = overlay.show_overlays
- if bg.clip:
- column.template_movieclip(bg, "clip", compact=True)
+ col = layout.column()
+ col.active = display_all
- if bg.use_camera_clip or bg.clip:
- has_bg = True
+ col.prop(overlay, {
+ 'PAINT_TEXTURE': "texture_paint_mode_opacity",
+ 'PAINT_VERTEX': "vertex_paint_mode_opacity",
+ 'PAINT_WEIGHT': "weight_paint_mode_opacity",
+ }[context.mode], text="Opacity")
- column = box.column()
- column.active = has_bg
- column.prop(bg.clip_user, "proxy_render_size", text="")
- column.prop(bg.clip_user, "use_render_undistorted")
+ if context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
+ col.prop(overlay, "show_paint_wire")
- if has_bg:
- col = box.column()
- col.prop(bg, "opacity", slider=True)
- col.row().prop(bg, "draw_depth", expand=True)
- if bg.view_axis in {'CAMERA', 'ALL'}:
- col.row().prop(bg, "frame_method", expand=True)
+class VIEW3D_PT_pivot_point(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Pivot Point"
+ bl_ui_units_x = 8
- box = col.box()
- row = box.row()
- row.prop(bg, "offset_x", text="X")
- row.prop(bg, "offset_y", text="Y")
+ def draw(self, context):
+ toolsettings = context.tool_settings
+ obj = context.active_object
+ mode = context.mode
- row = box.row()
- row.prop(bg, "use_flip_x")
- row.prop(bg, "use_flip_y")
+ layout = self.layout
+ col = layout.column()
+ col.label("Pivot Point")
+ col.prop(toolsettings, "transform_pivot_point", expand=True)
- row = box.row()
- if bg.view_axis != 'CAMERA':
- row.prop(bg, "rotation")
- row.prop(bg, "size")
+ col.separator()
+
+ if (obj is None) or (mode in {'OBJECT', 'POSE', 'WEIGHT_PAINT'}):
+ col.prop(
+ toolsettings,
+ "use_transform_pivot_point_align",
+ text="Center Points Only",
+ )
+
+
+class VIEW3D_PT_snapping(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'HEADER'
+ bl_label = "Snapping"
+
+ def draw(self, context):
+ toolsettings = context.tool_settings
+ snap_elements = toolsettings.snap_elements
+ obj = context.active_object
+ mode = context.mode
+ object_mode = 'OBJECT' if obj is None else obj.mode
+
+ layout = self.layout
+ col = layout.column()
+ col.label("Snapping")
+ col.prop(toolsettings, "snap_elements", expand=True)
+
+ col.separator()
+ if 'INCREMENT' in snap_elements:
+ col.prop(toolsettings, "use_snap_grid_absolute")
+
+ if snap_elements != {'INCREMENT'}:
+ col.label("Target")
+ row = col.row(align=True)
+ row.prop(toolsettings, "snap_target", expand=True)
+
+ if obj:
+ if object_mode == 'EDIT':
+ col.prop(toolsettings, "use_snap_self")
+ if object_mode in {'OBJECT', 'POSE', 'EDIT'}:
+ col.prop(toolsettings, "use_snap_align_rotation", text="Align Rotation")
+
+ if 'FACE' in snap_elements:
+ col.prop(toolsettings, "use_snap_project", text="Project Elements")
+
+ if 'VOLUME' in snap_elements:
+ col.prop(toolsettings, "use_snap_peel_object")
class VIEW3D_PT_transform_orientations(Panel):
bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
+ bl_region_type = 'HEADER'
bl_label = "Transform Orientations"
- bl_options = {'DEFAULT_CLOSED'}
+ bl_ui_units_x = 8
def draw(self, context):
layout = self.layout
+ layout.label("Transform Orientations")
- view = context.space_data
- orientation = view.current_orientation
+ scene = context.scene
+ orientation = scene.current_orientation
- row = layout.row(align=True)
- row.prop(view, "transform_orientation", text="")
- row.operator("transform.create_orientation", text="", icon='ZOOMIN')
+ row = layout.row()
+ col = row.column()
+ col.prop(scene, "transform_orientation", expand=True)
+ row.operator("transform.create_orientation", text="", icon='ZOOMIN', emboss=False).use = True
if orientation:
- row = layout.row(align=True)
+ row = layout.row(align=False)
row.prop(orientation, "name", text="")
- row.operator("transform.delete_orientation", text="", icon='X')
+ row.operator("transform.delete_orientation", text="", icon='X', emboss=False)
-class VIEW3D_PT_etch_a_ton(Panel):
+class VIEW3D_PT_quad_view(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
- bl_label = "Skeleton Sketching"
+ bl_label = "Quad View"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
- scene = context.space_data
- ob = context.active_object
- return scene and ob and ob.type == 'ARMATURE' and ob.mode == 'EDIT'
-
- def draw_header(self, context):
- layout = self.layout
- toolsettings = context.scene.tool_settings
-
- layout.prop(toolsettings, "use_bone_sketching", text="")
+ view = context.space_data
+ return view.region_quadviews
def draw(self, context):
layout = self.layout
- toolsettings = context.scene.tool_settings
+ view = context.space_data
+ region = view.region_quadviews[2]
col = layout.column()
+ col.prop(region, "lock_rotation")
+ row = col.row()
+ row.enabled = region.lock_rotation
+ row.prop(region, "show_sync_view")
+ row = col.row()
+ row.enabled = region.lock_rotation and region.show_sync_view
+ row.prop(region, "use_box_clip")
- col.prop(toolsettings, "use_etch_quick")
- col.prop(toolsettings, "use_etch_overdraw")
- col.separator()
+class VIEW3D_PT_view3d_stereo(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+ bl_label = "Stereoscopy"
+ bl_options = {'DEFAULT_CLOSED'}
- col.prop(toolsettings, "etch_convert_mode")
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
- if toolsettings.etch_convert_mode == 'LENGTH':
- col.prop(toolsettings, "etch_length_limit")
- elif toolsettings.etch_convert_mode == 'ADAPTIVE':
- col.prop(toolsettings, "etch_adaptive_limit")
- elif toolsettings.etch_convert_mode == 'FIXED':
- col.prop(toolsettings, "etch_subdivision_number")
- elif toolsettings.etch_convert_mode == 'RETARGET':
- col.prop(toolsettings, "etch_template")
- col.prop(toolsettings, "etch_roll_mode")
+ multiview = scene.render.use_multiview
+ return multiview
- col.separator()
+ def draw(self, context):
+ layout = self.layout
+ view = context.space_data
- colsub = col.column(align=True)
- colsub.prop(toolsettings, "use_etch_autoname")
- sub = colsub.column(align=True)
- sub.enabled = not toolsettings.use_etch_autoname
- sub.prop(toolsettings, "etch_number")
- sub.prop(toolsettings, "etch_side")
+ basic_stereo = context.scene.render.views_format == 'STEREO_3D'
- col.separator()
+ col = layout.column()
+ col.row().prop(view, "stereo_3d_camera", expand=True)
- col.operator("sketch.convert", text="Convert to Bones")
- col.operator("sketch.delete", text="Delete Strokes")
+ col.label(text="Display:")
+ row = col.row()
+ row.active = basic_stereo
+ row.prop(view, "show_stereo_3d_cameras")
+ row = col.row()
+ row.active = basic_stereo
+ split = row.split()
+ split.prop(view, "show_stereo_3d_convergence_plane")
+ split = row.split()
+ split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha")
+ split.active = view.show_stereo_3d_convergence_plane
+ row = col.row()
+ split = row.split()
+ split.prop(view, "show_stereo_3d_volume")
+ split = row.split()
+ split.prop(view, "stereo_3d_volume_alpha", text="Alpha")
class VIEW3D_PT_context_properties(Panel):
@@ -3972,10 +4642,10 @@ class VIEW3D_PT_context_properties(Panel):
def _active_context_member(context):
obj = context.object
if obj:
- mode = obj.mode
- if mode == 'POSE':
+ object_mode = obj.mode
+ if object_mode == 'POSE':
return "active_pose_bone"
- elif mode == 'EDIT' and obj.type == 'ARMATURE':
+ elif object_mode == 'EDIT' and obj.type == 'ARMATURE':
return "active_bone"
else:
return "object"
@@ -4047,25 +4717,26 @@ classes = (
INFO_MT_edit_curve_add,
INFO_MT_edit_armature_add,
INFO_MT_armature_add,
- INFO_MT_lamp_add,
+ INFO_MT_light_add,
+ INFO_MT_lightprobe_add,
INFO_MT_camera_add,
INFO_MT_add,
- VIEW3D_MT_undo_redo,
- VIEW3D_MT_object_relations,
VIEW3D_MT_object,
VIEW3D_MT_object_animation,
+ VIEW3D_MT_object_rigid_body,
VIEW3D_MT_object_clear,
VIEW3D_MT_object_specials,
+ VIEW3D_MT_object_shading,
VIEW3D_MT_object_apply,
+ VIEW3D_MT_object_relations,
VIEW3D_MT_object_parent,
VIEW3D_MT_object_track,
- VIEW3D_MT_object_group,
+ VIEW3D_MT_object_collection,
VIEW3D_MT_object_constraints,
VIEW3D_MT_object_quick_effects,
VIEW3D_MT_object_showhide,
VIEW3D_MT_make_single_user,
VIEW3D_MT_make_links,
- VIEW3D_MT_object_game,
VIEW3D_MT_brush,
VIEW3D_MT_brush_paint_modes,
VIEW3D_MT_paint_vertex,
@@ -4101,7 +4772,10 @@ classes = (
VIEW3D_MT_edit_mesh_edges,
VIEW3D_MT_edit_mesh_edges_data,
VIEW3D_MT_edit_mesh_faces,
+ VIEW3D_MT_edit_mesh_faces_data,
VIEW3D_MT_edit_mesh_normals,
+ VIEW3D_MT_edit_mesh_shading,
+ VIEW3D_MT_edit_mesh_weights,
VIEW3D_MT_edit_mesh_clean,
VIEW3D_MT_edit_mesh_delete,
VIEW3D_MT_edit_mesh_showhide,
@@ -4127,21 +4801,42 @@ classes = (
VIEW3D_MT_edit_armature_delete,
VIEW3D_MT_edit_gpencil_transform,
VIEW3D_MT_edit_gpencil_interpolate,
+ VIEW3D_MT_object_mode_pie,
+ VIEW3D_MT_view_pie,
VIEW3D_PT_grease_pencil,
VIEW3D_PT_grease_pencil_palettecolor,
VIEW3D_PT_view3d_properties,
+ VIEW3D_PT_view3d_camera_lock,
VIEW3D_PT_view3d_cursor,
- VIEW3D_PT_view3d_name,
- VIEW3D_PT_view3d_display,
+ VIEW3D_PT_object_type_visibility,
+ VIEW3D_PT_quad_view,
VIEW3D_PT_view3d_stereo,
- VIEW3D_PT_view3d_shading,
- VIEW3D_PT_view3d_motion_tracking,
- VIEW3D_PT_view3d_meshdisplay,
- VIEW3D_PT_view3d_meshstatvis,
- VIEW3D_PT_view3d_curvedisplay,
- VIEW3D_PT_background_image,
+ VIEW3D_PT_shading,
+ VIEW3D_PT_shading_lighting,
+ VIEW3D_PT_shading_color,
+ VIEW3D_PT_shading_options,
+ VIEW3D_PT_shading_options_shadow,
+ VIEW3D_PT_shading_options_ssao,
+ VIEW3D_PT_overlay,
+ VIEW3D_PT_overlay_manipulators,
+ VIEW3D_PT_overlay_guides,
+ VIEW3D_PT_overlay_object,
+ VIEW3D_PT_overlay_geometry,
+ VIEW3D_PT_overlay_motion_tracking,
+ VIEW3D_PT_overlay_edit_mesh,
+ VIEW3D_PT_overlay_edit_mesh_shading,
+ VIEW3D_PT_overlay_edit_mesh_measurement,
+ VIEW3D_PT_overlay_edit_mesh_normals,
+ VIEW3D_PT_overlay_edit_mesh_freestyle,
+ VIEW3D_PT_overlay_edit_mesh_developer,
+ VIEW3D_PT_overlay_edit_curve,
+ VIEW3D_PT_overlay_edit_armature,
+ VIEW3D_PT_overlay_pose,
+ VIEW3D_PT_overlay_paint,
+ VIEW3D_PT_overlay_sculpt,
+ VIEW3D_PT_pivot_point,
+ VIEW3D_PT_snapping,
VIEW3D_PT_transform_orientations,
- VIEW3D_PT_etch_a_ton,
VIEW3D_PT_context_properties,
)
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 41f1a64ca51..87c6a3840ae 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -36,8 +36,8 @@ from .properties_paint_common import (
class View3DPanel:
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
# **************** standard tool clusters ******************
@@ -53,419 +53,30 @@ def draw_keyframing_tools(context, layout):
# Used by vertex & weight paint
def draw_vpaint_symmetry(layout, vpaint):
- col = layout.column(align=True)
- col.label(text="Mirror:")
- row = col.row(align=True)
+ split = layout.split()
+
+ col = split.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Mirror")
+
+ col = split.column()
+ row = col.row(align=True)
row.prop(vpaint, "use_symmetry_x", text="X", toggle=True)
row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True)
row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True)
col = layout.column()
+ col.use_property_split = True
col.prop(vpaint, "radial_symmetry", text="Radial")
-# ********** default tools for object-mode ****************
-
-
-class VIEW3D_PT_tools_transform(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "objectmode"
- bl_label = "Transform"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
- col = layout.column(align=True)
- col.operator("transform.mirror", text="Mirror")
-
-
-class VIEW3D_PT_tools_object(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "objectmode"
- bl_label = "Edit"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.operator("object.duplicate_move", text="Duplicate")
- col.operator("object.duplicate_move_linked", text="Duplicate Linked")
-
- col.operator("object.delete")
-
- obj = context.active_object
- if obj:
- obj_type = obj.type
-
- if obj_type in {'MESH', 'CURVE', 'SURFACE', 'ARMATURE'}:
- col = layout.column(align=True)
- col.operator("object.join")
-
- if obj_type in {'MESH', 'CURVE', 'SURFACE', 'ARMATURE', 'FONT', 'LATTICE'}:
- col = layout.column(align=True)
- col.operator_menu_enum("object.origin_set", "type", text="Set Origin")
-
- if obj_type in {'MESH', 'CURVE', 'SURFACE'}:
- col = layout.column(align=True)
- col.label(text="Shading:")
- row = col.row(align=True)
- row.operator("object.shade_smooth", text="Smooth")
- row.operator("object.shade_flat", text="Flat")
-
- if obj_type == 'MESH':
- col = layout.column(align=True)
- col.label(text="Data Transfer:")
- row = col.row(align=True)
- row.operator("object.data_transfer", text="Data")
- row.operator("object.datalayout_transfer", text="Data Layout")
-
-
-class VIEW3D_PT_tools_add_object(View3DPanel, Panel):
- bl_category = "Create"
- bl_context = "objectmode"
- bl_label = "Add Primitive"
-
- @staticmethod
- def draw_add_mesh(layout, label=False):
- if label:
- layout.label(text="Primitives:")
- layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE')
- layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE')
- layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE')
- layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE')
- layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE')
- layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER')
- layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE')
- layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS')
-
- if label:
- layout.label(text="Special:")
- else:
- layout.separator()
- layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID')
- layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY')
-
- @staticmethod
- def draw_add_curve(layout, label=False):
-
- if label:
- layout.label(text="Bezier:")
- layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE')
- layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE')
-
- if label:
- layout.label(text="Nurbs:")
- else:
- layout.separator()
- layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE')
- layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
- layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
-
- layout.separator()
-
- layout.operator("curve.draw", icon='LINE_DATA')
-
- @staticmethod
- def draw_add_surface(layout):
- layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE')
- layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE')
- layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE')
- layout.operator("surface.primitive_nurbs_surface_cylinder_add", text="Nurbs Cylinder", icon='SURFACE_NCYLINDER')
- layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE')
- layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS')
-
- @staticmethod
- def draw_add_mball(layout):
- layout.operator_enum("object.metaball_add", "type")
-
- @staticmethod
- def draw_add_lamp(layout):
- layout.operator_enum("object.lamp_add", "type")
-
- @staticmethod
- def draw_add_other(layout):
- layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
- layout.operator("object.armature_add", text="Armature", icon='OUTLINER_OB_ARMATURE')
- layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
- layout.operator("object.empty_add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'PLAIN_AXES'
- layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
- layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Mesh:")
- self.draw_add_mesh(col)
-
- col = layout.column(align=True)
- col.label(text="Curve:")
- self.draw_add_curve(col)
-
- # not used here:
- # draw_add_surface
- # draw_add_mball
-
- col = layout.column(align=True)
- col.label(text="Lamp:")
- self.draw_add_lamp(col)
-
- col = layout.column(align=True)
- col.label(text="Other:")
- self.draw_add_other(col)
-
-
-class VIEW3D_PT_tools_relations(View3DPanel, Panel):
- bl_category = "Relations"
- bl_context = "objectmode"
- bl_label = "Relations"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
-
- col.label(text="Group:")
- col.operator("group.create", text="New Group")
- col.operator("group.objects_add_active", text="Add to Active")
- col.operator("group.objects_remove", text="Remove from Group")
-
- col.separator()
-
- col.label(text="Parent:")
- row = col.row(align=True)
- row.operator("object.parent_set", text="Set")
- row.operator("object.parent_clear", text="Clear")
-
- col.separator()
-
- col.label(text="Object Data:")
- col.operator("object.make_links_data")
- col.operator("object.make_single_user")
-
- col.separator()
-
- col.label(text="Linked Objects:")
- col.operator("object.make_local")
- col.operator("object.proxy_make")
-
-
-class VIEW3D_PT_tools_animation(View3DPanel, Panel):
- bl_category = "Animation"
- bl_context = "objectmode"
- bl_label = "Animation"
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.active_object
- mpath = ob.motion_path if ob else None
-
- draw_keyframing_tools(context, layout)
-
- col = layout.column(align=True)
- col.label(text="Motion Paths:")
- if mpath:
- row = col.row(align=True)
- row.operator("object.paths_update", text="Update")
- row.operator("object.paths_clear", text="", icon='X')
- else:
- col.operator("object.paths_calculate", text="Calculate")
-
- col.separator()
-
- col.label(text="Action:")
- col.operator("nla.bake", text="Bake Action")
-
-
-class VIEW3D_PT_tools_rigid_body(View3DPanel, Panel):
- bl_category = "Physics"
- bl_context = "objectmode"
- bl_label = "Rigid Body Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Add/Remove:")
- row = col.row(align=True)
- row.operator("rigidbody.objects_add", text="Add Active").type = 'ACTIVE'
- row.operator("rigidbody.objects_add", text="Add Passive").type = 'PASSIVE'
- row = col.row(align=True)
- row.operator("rigidbody.objects_remove", text="Remove")
-
- col = layout.column(align=True)
- col.label(text="Object Tools:")
- col.operator("rigidbody.shape_change", text="Change Shape")
- col.operator("rigidbody.mass_calculate", text="Calculate Mass")
- col.operator("rigidbody.object_settings_copy", text="Copy from Active")
- col.operator("object.visual_transform_apply", text="Apply Transformation")
- col.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
- col.label(text="Constraints:")
- col.operator("rigidbody.connect", text="Connect")
-
# ********** default tools for editmode_mesh ****************
-class VIEW3D_PT_tools_transform_mesh(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "mesh_edit"
- bl_label = "Transform"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
- col.operator("transform.shrink_fatten", text="Shrink/Fatten")
- col.operator("transform.push_pull", text="Push/Pull")
-
-
-class VIEW3D_PT_tools_meshedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "mesh_edit"
- bl_label = "Mesh Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Deform:")
- row = col.row(align=True)
- row.operator("transform.edge_slide", text="Slide Edge")
- row.operator("transform.vert_slide", text="Vertex")
- col.operator("mesh.noise")
- col.operator("mesh.vertices_smooth")
- col.operator("transform.vertex_random")
-
- col = layout.column(align=True)
- col.label(text="Add:")
-
- col.menu("VIEW3D_MT_edit_mesh_extrude")
- col.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Region")
- col.operator("view3d.edit_mesh_extrude_individual_move", text="Extrude Individual")
- col.operator("mesh.inset", text="Inset Faces")
- col.operator("mesh.edge_face_add")
- col.operator("mesh.subdivide")
- col.operator("mesh.loopcut_slide")
- col.operator("mesh.offset_edge_loops_slide")
- col.operator("mesh.duplicate_move", text="Duplicate")
- row = col.row(align=True)
- row.operator("mesh.spin")
- row.operator("mesh.screw")
-
- row = col.row(align=True)
- props = row.operator("mesh.knife_tool", text="Knife")
- props.use_occlude_geometry = True
- props.only_selected = False
- props = row.operator("mesh.knife_tool", text="Select")
- props.use_occlude_geometry = False
- props.only_selected = True
- col.operator("mesh.knife_project")
- col.operator("mesh.bisect")
-
- col = layout.column(align=True)
- col.label(text="Remove:")
- col.menu("VIEW3D_MT_edit_mesh_delete")
- col.operator_menu_enum("mesh.merge", "type")
- col.operator("mesh.remove_doubles")
-
-
-class VIEW3D_PT_tools_meshweight(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "mesh_edit"
- bl_label = "Weight Tools"
- bl_options = {'DEFAULT_CLOSED'}
-
- # Used for Weight-Paint mode and Edit-Mode
- @staticmethod
- def draw_generic(layout):
- col = layout.column()
- col.operator("object.vertex_group_normalize_all", text="Normalize All")
- col.operator("object.vertex_group_normalize", text="Normalize")
- col.operator("object.vertex_group_mirror", text="Mirror")
- col.operator("object.vertex_group_invert", text="Invert")
- col.operator("object.vertex_group_clean", text="Clean")
- col.operator("object.vertex_group_quantize", text="Quantize")
- col.operator("object.vertex_group_levels", text="Levels")
- col.operator("object.vertex_group_smooth", text="Smooth")
- col.operator("object.vertex_group_limit_total", text="Limit Total")
- col.operator("object.vertex_group_fix", text="Fix Deforms")
-
- def draw(self, context):
- layout = self.layout
- self.draw_generic(layout)
-
-
-class VIEW3D_PT_tools_add_mesh_edit(View3DPanel, Panel):
- bl_category = "Create"
- bl_context = "mesh_edit"
- bl_label = "Add Meshes"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
-
- VIEW3D_PT_tools_add_object.draw_add_mesh(col, label=True)
-
-
-class VIEW3D_PT_tools_shading(View3DPanel, Panel):
- bl_category = "Shading / UVs"
- bl_context = "mesh_edit"
- bl_label = "Shading"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Faces:")
- row = col.row(align=True)
- row.operator("mesh.faces_shade_smooth", text="Smooth")
- row.operator("mesh.faces_shade_flat", text="Flat")
- col.label(text="Edges:")
- row = col.row(align=True)
- row.operator("mesh.mark_sharp", text="Smooth").clear = True
- row.operator("mesh.mark_sharp", text="Sharp")
- col.label(text="Vertices:")
- row = col.row(align=True)
- props = row.operator("mesh.mark_sharp", text="Smooth")
- props.use_verts = True
- props.clear = True
- row.operator("mesh.mark_sharp", text="Sharp").use_verts = True
-
- col = layout.column(align=True)
- col.label(text="Normals:")
- col.operator("mesh.normals_make_consistent", text="Recalculate")
- col.operator("mesh.flip_normals", text="Flip Direction")
- col.operator("mesh.set_normals_from_faces", text="Set From Faces")
-
-
-class VIEW3D_PT_tools_uvs(View3DPanel, Panel):
- bl_category = "Shading / UVs"
- bl_context = "mesh_edit"
- bl_label = "UVs"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="UV Mapping:")
- col.menu("VIEW3D_MT_uv_map", text="Unwrap")
- col.operator("mesh.mark_seam").clear = False
- col.operator("mesh.mark_seam", text="Clear Seam").clear = True
-
class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
bl_category = "Options"
- bl_context = "mesh_edit"
+ bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Mesh Options"
@classmethod
@@ -493,85 +104,15 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
col.prop(tool_settings, "edge_path_live_unwrap")
col.label("Double Threshold:")
col.prop(tool_settings, "double_threshold", text="")
+ col.prop(tool_settings, "use_mesh_automerge") # , icon='AUTOMERGE_ON'
- if mesh.show_weight:
- col.label("Show Zero Weights:")
- col.row().prop(tool_settings, "vertex_group_user", expand=True)
# ********** default tools for editmode_curve ****************
-class VIEW3D_PT_tools_transform_curve(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "curve_edit"
- bl_label = "Transform"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
- col = layout.column(align=True)
- col.operator("transform.tilt", text="Tilt")
- col.operator("transform.transform", text="Shrink/Fatten").mode = 'CURVE_SHRINKFATTEN'
-
-
-class VIEW3D_PT_tools_curveedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "curve_edit"
- bl_label = "Curve Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Curve:")
- col.operator("curve.duplicate_move", text="Duplicate")
- col.operator("curve.delete")
- col.operator("curve.cyclic_toggle")
- col.operator("curve.switch_direction")
- col.operator("curve.spline_type_set")
- col.operator("curve.radius_set")
-
- col = layout.column(align=True)
- col.label(text="Handles:")
- row = col.row(align=True)
- row.operator("curve.handle_type_set", text="Auto").type = 'AUTOMATIC'
- row.operator("curve.handle_type_set", text="Vector").type = 'VECTOR'
- row = col.row(align=True)
- row.operator("curve.handle_type_set", text="Align").type = 'ALIGNED'
- row.operator("curve.handle_type_set", text="Free").type = 'FREE_ALIGN'
-
- col = layout.column(align=True)
- col.operator("curve.normals_make_consistent")
-
- col = layout.column(align=True)
- col.label(text="Modeling:")
- col.operator("curve.extrude_move", text="Extrude")
- col.operator("curve.subdivide")
- col.operator("curve.smooth")
- col.operator("transform.vertex_random")
-
-
-class VIEW3D_PT_tools_add_curve_edit(View3DPanel, Panel):
- bl_category = "Create"
- bl_context = "curve_edit"
- bl_label = "Add Curves"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
-
- VIEW3D_PT_tools_add_object.draw_add_curve(col, label=True)
-
-
class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
bl_category = "Options"
- bl_context = "curve_edit"
+ bl_context = ".curve_edit" # dot on purpose (access from topbar)
bl_label = "Curve Stroke"
def draw(self, context):
@@ -623,128 +164,12 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
colsub.prop(cps, "surface_plane", expand=True)
-# ********** default tools for editmode_surface ****************
-
-class VIEW3D_PT_tools_transform_surface(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "surface_edit"
- bl_label = "Transform"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
-
-class VIEW3D_PT_tools_surfaceedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "surface_edit"
- bl_label = "Surface Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Curve:")
- col.operator("curve.duplicate_move", text="Duplicate")
- col.operator("curve.delete")
- col.operator("curve.cyclic_toggle")
- col.operator("curve.switch_direction")
-
- col = layout.column(align=True)
- col.label(text="Modeling:")
- col.operator("curve.extrude", text="Extrude")
- col.operator("curve.spin")
- col.operator("curve.subdivide")
-
- col = layout.column(align=True)
- col.label(text="Deform:")
- col.operator("transform.vertex_random")
-
-
-class VIEW3D_PT_tools_add_surface_edit(View3DPanel, Panel):
- bl_category = "Create"
- bl_context = "surface_edit"
- bl_label = "Add Surfaces"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
-
- VIEW3D_PT_tools_add_object.draw_add_surface(col)
-
-
-# ********** default tools for editmode_text ****************
-
-
-class VIEW3D_PT_tools_textedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "text_edit"
- bl_label = "Text Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Set Case:")
- col.operator("font.case_set", text="To Upper").case = 'UPPER'
- col.operator("font.case_set", text="To Lower").case = 'LOWER'
-
- col = layout.column(align=True)
- col.label(text="Style:")
- col.operator("font.style_toggle", text="Bold").style = 'BOLD'
- col.operator("font.style_toggle", text="Italic").style = 'ITALIC'
- col.operator("font.style_toggle", text="Underline").style = 'UNDERLINE'
-
-
# ********** default tools for editmode_armature ****************
-class VIEW3D_PT_tools_armatureedit_transform(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "armature_edit"
- bl_label = "Transform"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
-
-class VIEW3D_PT_tools_armatureedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "armature_edit"
- bl_label = "Armature Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Bones:")
- col.operator("armature.bone_primitive_add", text="Add")
- col.operator("armature.duplicate_move", text="Duplicate")
- col.operator("armature.delete", text="Delete")
-
- col = layout.column(align=True)
- col.label(text="Modeling:")
- col.operator("armature.extrude_move")
- col.operator("armature.subdivide", text="Subdivide")
-
- col = layout.column(align=True)
- col.label(text="Deform:")
- col.operator("transform.vertex_random")
-
-
class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
bl_category = "Options"
- bl_context = "armature_edit"
+ bl_context = ".armature_edit" # dot on purpose (access from topbar)
bl_label = "Armature Options"
def draw(self, context):
@@ -753,138 +178,30 @@ class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
self.layout.prop(arm, "use_mirror_x")
-# ********** default tools for editmode_mball ****************
-
-
-class VIEW3D_PT_tools_mballedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "mball_edit"
- bl_label = "Meta Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Transform:")
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
- col = layout.column(align=True)
- col.label(text="Deform:")
- col.operator("transform.vertex_random")
-
-
-class VIEW3D_PT_tools_add_mball_edit(View3DPanel, Panel):
- bl_category = "Create"
- bl_context = "mball_edit"
- bl_label = "Add Metaball"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
-
- VIEW3D_PT_tools_add_object.draw_add_mball(col)
-
-
-# ********** default tools for editmode_lattice ****************
-
-
-class VIEW3D_PT_tools_latticeedit(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "lattice_edit"
- bl_label = "Lattice Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Transform:")
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
- col = layout.column(align=True)
- col.operator("lattice.make_regular")
-
- col = layout.column(align=True)
- col.label(text="Deform:")
- col.operator("transform.vertex_random")
-
-
# ********** default tools for pose-mode ****************
-
-class VIEW3D_PT_tools_posemode(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "posemode"
- bl_label = "Pose Tools"
-
- def draw(self, context):
- layout = self.layout
-
- col = layout.column(align=True)
- col.label(text="Transform:")
- col.operator("transform.translate")
- col.operator("transform.rotate")
- col.operator("transform.resize", text="Scale")
-
- col = layout.column(align=True)
- col.label(text="In-Between:")
- row = col.row(align=True)
- row.operator("pose.push", text="Push")
- row.operator("pose.relax", text="Relax")
- col.operator("pose.breakdown", text="Breakdowner")
-
- col = layout.column(align=True)
- col.label(text="Pose:")
- row = col.row(align=True)
- row.operator("pose.copy", text="Copy")
- row.operator("pose.paste", text="Paste")
-
- row = layout.row(align=True)
- row.operator("pose.propagate", text="Propagate")
- row.menu("VIEW3D_MT_pose_propagate", icon='TRIA_RIGHT', text="")
-
- col = layout.column(align=True)
- col.operator("poselib.pose_add", text="Add To Library")
-
- draw_keyframing_tools(context, layout)
-
- ob = context.object
- avs = ob.pose.animation_visualization
-
- col = layout.column(align=True)
- col.label(text="Motion Paths:")
- if avs.motion_path.has_motion_paths:
- row = col.row(align=True)
- row.operator("pose.paths_update", text="Update")
- row.operator("pose.paths_clear", text="", icon='X')
- else:
- col.operator("pose.paths_calculate", text="Calculate")
-
-
class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
bl_category = "Options"
- bl_context = "posemode"
+ bl_context = ".posemode" # dot on purpose (access from topbar)
bl_label = "Pose Options"
def draw(self, context):
arm = context.active_object.data
self.layout.prop(arm, "use_auto_ik")
+ self.layout.prop(arm, "use_mirror_x")
# ********** default tools for paint modes ****************
class View3DPaintPanel(UnifiedPaintPanel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel):
bl_category = "Tools"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Missing Data"
@classmethod
@@ -930,22 +247,19 @@ class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel):
col.label("Missing Canvas", icon='INFO')
col.label("Add or assign a canvas image below")
col.label("Canvas Image:")
- # todo this should be combinded into a single row
- col.template_ID(toolsettings, "canvas", open="image.open")
- col.operator("image.new", text="New").gen_context = 'PAINT_CANVAS'
+ col.template_ID(toolsettings, "canvas", new="image.new", open="image.open")
if toolsettings.missing_stencil:
col.separator()
col.label("Missing Stencil", icon='INFO')
col.label("Add or assign a stencil image below")
col.label("Stencil Image:")
- # todo this should be combinded into a single row
- col.template_ID(toolsettings, "stencil_image", open="image.open")
- col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL'
+ col.template_ID(toolsettings, "stencil_image", new="image.new", open="image.open")
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
- bl_category = "Tools"
+ bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Brush"
@classmethod
@@ -1199,9 +513,6 @@ class TEXTURE_UL_texpaintslots(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(item, "name", text="", emboss=False, icon_value=icon)
- if (not mat.use_nodes) and context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}:
- mtex_index = mat.texture_paint_slots[index].index
- layout.prop(mat, "use_textures", text="", index=mtex_index)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="")
@@ -1213,16 +524,16 @@ class VIEW3D_MT_tools_projectpaint_uvlayer(Menu):
def draw(self, context):
layout = self.layout
- for i, tex in enumerate(context.active_object.data.uv_textures):
- props = layout.operator("wm.context_set_int", text=tex.name, translate=False)
- props.data_path = "active_object.data.uv_textures.active_index"
+ for i, uv_layer in enumerate(context.active_object.data.uv_layers):
+ props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
+ props.data_path = "active_object.data.uv_layers.active_index"
props.value = i
+# TODO, move to space_view3d.py
class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
- bl_context = "imagepaint"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Slots"
- bl_category = "Slots"
@classmethod
def poll(cls, context):
@@ -1262,26 +573,15 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
else:
slot = None
- if (not mat.use_nodes) and context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}:
- row = col.row(align=True)
- row.operator_menu_enum("paint.add_texture_paint_slot", "type")
- row.operator("paint.delete_texture_paint_slot", text="", icon='X')
-
- if slot:
- col.prop(mat.texture_slots[slot.index], "blend_type")
- col.separator()
-
- if slot and slot.index != -1:
+ if slot and slot.is_valid:
col.label("UV Map:")
- col.prop_search(slot, "uv_layer", ob.data, "uv_textures", text="")
+ col.prop_search(slot, "uv_layer", ob.data, "uv_layers", text="")
elif settings.mode == 'IMAGE':
mesh = ob.data
- uv_text = mesh.uv_textures.active.name if mesh.uv_textures.active else ""
+ uv_text = mesh.uv_layers.active.name if mesh.uv_layers.active else ""
col.label("Canvas Image:")
- # todo this should be combinded into a single row
- col.template_ID(settings, "canvas", open="image.open")
- col.operator("image.new", text="New").gen_context = 'PAINT_CANVAS'
+ col.template_ID(settings, "canvas", new="image.new", open="image.open")
col.label("UV Map:")
col.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False)
@@ -1289,10 +589,10 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
col.operator("image.save_dirty", text="Save All Images")
+# TODO, move to space_view3d.py
class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
- bl_context = "imagepaint"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Mask"
- bl_category = "Slots"
@classmethod
def poll(cls, context):
@@ -1306,6 +606,7 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
toolsettings = context.tool_settings
ipaint = toolsettings.image_paint
@@ -1315,23 +616,29 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
col = layout.column()
col.active = ipaint.use_stencil_layer
- stencil_text = mesh.uv_texture_stencil.name if mesh.uv_texture_stencil else ""
- col.label("UV Map:")
- col.menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False)
+ stencil_text = mesh.uv_layer_stencil.name if mesh.uv_layer_stencil else ""
+ split = col.split(0.5)
+ colsub = split.column()
+ colsub.alignment = 'RIGHT'
+ colsub.label("UV Layer")
+ split.column().menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False)
- col.label("Stencil Image:")
# todo this should be combinded into a single row
- col.template_ID(ipaint, "stencil_image", open="image.open")
- col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL'
+ split = col.split(0.5)
+ colsub = split.column()
+ colsub.alignment = 'RIGHT'
+ colsub.label("Stencil Image")
+ colsub = split.column()
+ colsub.template_ID(ipaint, "stencil_image", new="image.new", open="image.open")
- col.label("Visualization:")
row = col.row(align=True)
- row.prop(ipaint, "stencil_color", text="")
+ row.prop(ipaint, "stencil_color", text="Display Color")
row.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA')
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_overlay(Panel, View3DPaintPanel):
- bl_category = "Options"
+ bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Overlay"
@classmethod
@@ -1396,8 +703,9 @@ class VIEW3D_PT_tools_brush_overlay(Panel, View3DPaintPanel):
sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
- bl_category = "Tools"
+ bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Texture"
bl_options = {'DEFAULT_CLOSED'}
@@ -1420,9 +728,9 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
brush_texture_settings(col, brush, context.sculpt_object)
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
- bl_category = "Tools"
- bl_context = "imagepaint"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Texture Mask"
bl_options = {'DEFAULT_CLOSED'}
@@ -1443,8 +751,9 @@ class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
brush_mask_texture_settings(col, brush)
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
- bl_category = "Tools"
+ bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Stroke"
bl_options = {'DEFAULT_CLOSED'}
@@ -1463,12 +772,11 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
settings = self.paint_settings(context)
brush = settings.brush
+ layout.use_property_split = True
col = layout.column()
- col.label(text="Stroke Method:")
-
- col.prop(brush, "stroke_method", text="")
+ col.prop(brush, "stroke_method")
if brush.use_anchor:
col.separator()
@@ -1498,12 +806,16 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
if brush.sculpt_capabilities.has_jitter:
col.separator()
- row = col.row(align=True)
+ colsub = col.split(0.5)
+ row = colsub.row(align=True)
+ row.alignment = 'RIGHT'
+ row.label("Jitter")
+ row = colsub.row(align=True)
row.prop(brush, "use_relative_jitter", icon_only=True)
if brush.use_relative_jitter:
- row.prop(brush, "jitter", slider=True)
+ row.prop(brush, "jitter", slider=True, text="")
else:
- row.prop(brush, "jitter_absolute")
+ row.prop(brush, "jitter_absolute", text="")
row.prop(brush, "use_pressure_jitter", toggle=True, text="")
if brush.sculpt_capabilities.has_smooth_stroke:
@@ -1541,8 +853,9 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
layout.prop(settings, "input_samples")
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
- bl_category = "Tools"
+ bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Curve"
bl_options = {'DEFAULT_CLOSED'}
@@ -1570,26 +883,31 @@ class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
+# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
- bl_category = "Tools"
+ bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Dyntopo"
bl_options = {'DEFAULT_CLOSED'}
+ bl_ui_units_x = 12
@classmethod
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
def draw_header(self, context):
+ is_popover = self.is_popover
layout = self.layout
layout.operator(
"sculpt.dynamic_topology_toggle",
icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
text="",
- emboss=False,
+ emboss=is_popover,
)
def draw(self, context):
layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
toolsettings = context.tool_settings
sculpt = toolsettings.sculpt
@@ -1598,9 +916,10 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
col = layout.column()
col.active = context.sculpt_object.use_dynamic_topology_sculpting
- sub = col.column(align=True)
+
+ sub = col.column()
sub.active = (brush and brush.sculpt_tool != 'MASK')
- if (sculpt.detail_type_method == 'CONSTANT'):
+ if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
row = sub.row(align=True)
row.prop(sculpt, "constant_detail_resolution")
row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
@@ -1608,20 +927,23 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
sub.prop(sculpt, "detail_percent")
else:
sub.prop(sculpt, "detail_size")
- sub.prop(sculpt, "detail_refine_method", text="")
- sub.prop(sculpt, "detail_type_method", text="")
- col.separator()
+ sub.prop(sculpt, "detail_refine_method", text="Refine Method")
+ sub.prop(sculpt, "detail_type_method", text="Detailing")
+
col.prop(sculpt, "use_smooth_shading")
- col.operator("sculpt.optimize")
- if (sculpt.detail_type_method == 'CONSTANT'):
- col.operator("sculpt.detail_flood_fill")
+
col.separator()
+
col.prop(sculpt, "symmetrize_direction")
col.operator("sculpt.symmetrize")
+ col.operator("sculpt.optimize")
+ if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
+ col.operator("sculpt.detail_flood_fill")
+# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
- bl_category = "Options"
+ bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
@@ -1653,8 +975,9 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
self.unified_paint_settings(layout, context)
+# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
- bl_category = "Tools"
+ bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Symmetry/Lock"
bl_options = {'DEFAULT_CLOSED'}
@@ -1667,35 +990,55 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
sculpt = context.tool_settings.sculpt
- col = layout.column(align=True)
- col.label(text="Mirror:")
+ split = layout.split()
+
+ col = split.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Mirror")
+
+ col = split.column()
+
row = col.row(align=True)
row.prop(sculpt, "use_symmetry_x", text="X", toggle=True)
row.prop(sculpt, "use_symmetry_y", text="Y", toggle=True)
row.prop(sculpt, "use_symmetry_z", text="Z", toggle=True)
- layout.column().prop(sculpt, "radial_symmetry", text="Radial")
- layout.prop(sculpt, "use_symmetry_feather", text="Feather")
+ split = layout.split()
- layout.label(text="Lock:")
+ col = split.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Lock")
- row = layout.row(align=True)
+ col = split.column()
+
+ row = col.row(align=True)
row.prop(sculpt, "lock_x", text="X", toggle=True)
row.prop(sculpt, "lock_y", text="Y", toggle=True)
row.prop(sculpt, "lock_z", text="Z", toggle=True)
- layout.label(text="Tiling:")
+ split = layout.split()
- row = layout.row(align=True)
+ col = split.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Tiling")
+
+ col = split.column()
+
+ row = col.row(align=True)
row.prop(sculpt, "tile_x", text="X", toggle=True)
row.prop(sculpt, "tile_y", text="Y", toggle=True)
row.prop(sculpt, "tile_z", text="Z", toggle=True)
+ layout.use_property_split = True
+
+ layout.prop(sculpt, "use_symmetry_feather", text="Feather")
+ layout.column().prop(sculpt, "radial_symmetry", text="Radial")
layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
- bl_category = "Options"
+ bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Appearance"
@classmethod
@@ -1739,25 +1082,9 @@ class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
# ********** default tools for weight-paint ****************
-class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel):
- bl_category = "Tools"
- bl_context = "weightpaint"
- bl_label = "Weight Tools"
-
- def draw(self, context):
- layout = self.layout
- VIEW3D_PT_tools_meshweight.draw_generic(layout)
-
- col = layout.column()
- col.operator("paint.weight_gradient")
- props = col.operator("object.data_transfer", text="Transfer Weights")
- props.use_reverse_transfer = True
- props.data_type = 'VGROUP_WEIGHTS'
-
-
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
- bl_category = "Tools"
- bl_context = "weightpaint"
+ bl_context = ".weightpaint"
bl_options = {'DEFAULT_CLOSED'}
bl_label = "Symmetry"
@@ -1768,9 +1095,9 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
draw_vpaint_symmetry(layout, wpaint)
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
- bl_category = "Options"
- bl_context = "weightpaint"
+ bl_context = ".weightpaint"
bl_label = "Options"
def draw(self, context):
@@ -1799,9 +1126,9 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
# ********** default tools for vertex-paint ****************
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel):
- bl_category = "Options"
- bl_context = "vertexpaint"
+ bl_context = ".vertexpaint" # dot on purpose (access from topbar)
bl_label = "Options"
def draw(self, context):
@@ -1815,9 +1142,9 @@ class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel):
self.unified_paint_settings(col, context)
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
- bl_category = "Tools"
- bl_context = "vertexpaint"
+ bl_context = ".vertexpaint" # dot on purpose (access from topbar)
bl_options = {'DEFAULT_CLOSED'}
bl_label = "Symmetry"
@@ -1831,9 +1158,9 @@ class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
# ********** default tools for texture-paint ****************
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
- bl_category = "Tools"
- bl_context = "imagepaint"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "External"
bl_options = {'DEFAULT_CLOSED'}
@@ -1853,9 +1180,9 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
col.operator("paint.project_image", text="Apply Camera Image")
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
- bl_category = "Tools"
- bl_context = "imagepaint"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Symmetry"
bl_options = {'DEFAULT_CLOSED'}
@@ -1865,16 +1192,23 @@ class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
toolsettings = context.tool_settings
ipaint = toolsettings.image_paint
- col = layout.column(align=True)
+ split = layout.split()
+
+ col = split.column()
+ col.alignment = 'RIGHT'
+ col.label(text="Mirror")
+
+ col = split.column()
+
row = col.row(align=True)
row.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
- bl_category = "Options"
- bl_context = "imagepaint"
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Project Paint"
@classmethod
@@ -1909,8 +1243,8 @@ class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
self.unified_paint_settings(layout, context)
+# TODO, move to space_view3d.py
class VIEW3D_PT_imagepaint_options(View3DPaintPanel):
- bl_category = "Options"
bl_label = "Options"
@classmethod
@@ -1929,17 +1263,17 @@ class VIEW3D_MT_tools_projectpaint_stencil(Menu):
def draw(self, context):
layout = self.layout
- for i, tex in enumerate(context.active_object.data.uv_textures):
- props = layout.operator("wm.context_set_int", text=tex.name, translate=False)
- props.data_path = "active_object.data.uv_texture_stencil_index"
+ for i, uv_layer in enumerate(context.active_object.data.uv_layers):
+ props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
+ props.data_path = "active_object.data.uv_layer_stencil_index"
props.value = i
+# TODO, move to space_view3d.py
class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
"""Default tools for particle mode"""
- bl_context = "particlemode"
+ bl_context = ".particlemode"
bl_label = "Options"
- bl_category = "Tools"
def draw(self, context):
layout = self.layout
@@ -2038,60 +1372,10 @@ class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Pa
bl_space_type = 'VIEW_3D'
-# Note: moved here so that it's always in last position in 'Tools' panels!
-class VIEW3D_PT_tools_history(View3DPanel, Panel):
- bl_category = "Tools"
- # No bl_context, we are always available!
- bl_label = "History"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- layout = self.layout
- obj = context.object
-
- col = layout.column(align=True)
- row = col.row(align=True)
- row.operator("ed.undo")
- row.operator("ed.redo")
- if obj is None or obj.mode != 'SCULPT':
- # Sculpt mode does not generate an undo menu it seems...
- col.operator("ed.undo_history")
-
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
-
-
classes = (
- VIEW3D_PT_tools_transform,
- VIEW3D_PT_tools_object,
- VIEW3D_PT_tools_add_object,
- VIEW3D_PT_tools_relations,
- VIEW3D_PT_tools_animation,
- VIEW3D_PT_tools_rigid_body,
- VIEW3D_PT_tools_transform_mesh,
- VIEW3D_PT_tools_meshedit,
- VIEW3D_PT_tools_meshweight,
- VIEW3D_PT_tools_add_mesh_edit,
- VIEW3D_PT_tools_shading,
- VIEW3D_PT_tools_uvs,
VIEW3D_PT_tools_meshedit_options,
- VIEW3D_PT_tools_transform_curve,
- VIEW3D_PT_tools_curveedit,
- VIEW3D_PT_tools_add_curve_edit,
VIEW3D_PT_tools_curveedit_options_stroke,
- VIEW3D_PT_tools_transform_surface,
- VIEW3D_PT_tools_surfaceedit,
- VIEW3D_PT_tools_add_surface_edit,
- VIEW3D_PT_tools_textedit,
- VIEW3D_PT_tools_armatureedit,
- VIEW3D_PT_tools_armatureedit_transform,
VIEW3D_PT_tools_armatureedit_options,
- VIEW3D_PT_tools_mballedit,
- VIEW3D_PT_tools_add_mball_edit,
- VIEW3D_PT_tools_latticeedit,
- VIEW3D_PT_tools_posemode,
VIEW3D_PT_tools_posemode_options,
VIEW3D_PT_imapaint_tools_missing,
VIEW3D_PT_tools_brush,
@@ -2108,7 +1392,6 @@ classes = (
VIEW3D_PT_sculpt_options,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_tools_brush_appearance,
- VIEW3D_PT_tools_weightpaint,
VIEW3D_PT_tools_weightpaint_symmetry,
VIEW3D_PT_tools_weightpaint_options,
VIEW3D_PT_tools_vertexpaint,
@@ -2124,7 +1407,6 @@ classes = (
VIEW3D_PT_tools_grease_pencil_sculpt,
VIEW3D_PT_tools_grease_pencil_brush,
VIEW3D_PT_tools_grease_pencil_brushcurves,
- VIEW3D_PT_tools_history,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 92411aeb0ef..e6500b7c2c0 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -43,18 +43,10 @@ class CompositorNodeCategory(SortedNodeCategory):
return (context.space_data.tree_type == 'CompositorNodeTree')
-class ShaderNewNodeCategory(SortedNodeCategory):
+class ShaderNodeCategory(SortedNodeCategory):
@classmethod
def poll(cls, context):
- return (context.space_data.tree_type == 'ShaderNodeTree' and
- context.scene.render.use_shading_nodes)
-
-
-class ShaderOldNodeCategory(SortedNodeCategory):
- @classmethod
- def poll(cls, context):
- return (context.space_data.tree_type == 'ShaderNodeTree' and
- not context.scene.render.use_shading_nodes)
+ return (context.space_data.tree_type == 'ShaderNodeTree')
class TextureNodeCategory(SortedNodeCategory):
@@ -142,62 +134,39 @@ def object_shader_nodes_poll(context):
snode.shader_type == 'OBJECT')
+def cycles_shader_nodes_poll(context):
+ return context.engine == 'CYCLES'
+
+
+def eevee_shader_nodes_poll(context):
+ return context.engine == 'BLENDER_EEVEE'
+
+
+def eevee_cycles_shader_nodes_poll(context):
+ return (cycles_shader_nodes_poll(context) or
+ eevee_shader_nodes_poll(context))
+
+
+def object_cycles_shader_nodes_poll(context):
+ return (object_shader_nodes_poll(context) and
+ cycles_shader_nodes_poll(context))
+
+
+def object_eevee_shader_nodes_poll(context):
+ return (object_shader_nodes_poll(context) and
+ eevee_shader_nodes_poll(context))
+
+
+def object_eevee_cycles_shader_nodes_poll(context):
+ return (object_shader_nodes_poll(context) and
+ eevee_cycles_shader_nodes_poll(context))
+
+
# All standard node categories currently used in nodes.
shader_node_categories = [
- # Shader Nodes
- ShaderOldNodeCategory("SH_INPUT", "Input", items=[
- NodeItem("ShaderNodeMaterial"),
- NodeItem("ShaderNodeCameraData"),
- NodeItem("ShaderNodeFresnel"),
- NodeItem("ShaderNodeLayerWeight"),
- NodeItem("ShaderNodeLampData"),
- NodeItem("ShaderNodeValue"),
- NodeItem("ShaderNodeRGB"),
- NodeItem("ShaderNodeTexture"),
- NodeItem("ShaderNodeGeometry"),
- NodeItem("ShaderNodeExtendedMaterial"),
- NodeItem("ShaderNodeParticleInfo"),
- NodeItem("ShaderNodeObjectInfo"),
- NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
- ]),
- ShaderOldNodeCategory("SH_OUTPUT", "Output", items=[
- NodeItem("ShaderNodeOutput"),
- NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
- ]),
- ShaderOldNodeCategory("SH_OP_COLOR", "Color", items=[
- NodeItem("ShaderNodeMixRGB"),
- NodeItem("ShaderNodeRGBCurve"),
- NodeItem("ShaderNodeInvert"),
- NodeItem("ShaderNodeHueSaturation"),
- NodeItem("ShaderNodeGamma"),
- ]),
- ShaderOldNodeCategory("SH_OP_VECTOR", "Vector", items=[
- NodeItem("ShaderNodeNormal"),
- NodeItem("ShaderNodeMapping"),
- NodeItem("ShaderNodeVectorCurve"),
- NodeItem("ShaderNodeVectorTransform"),
- NodeItem("ShaderNodeNormalMap"),
- ]),
- ShaderOldNodeCategory("SH_CONVERTOR", "Converter", items=[
- NodeItem("ShaderNodeValToRGB"),
- NodeItem("ShaderNodeRGBToBW"),
- NodeItem("ShaderNodeMath"),
- NodeItem("ShaderNodeVectorMath"),
- NodeItem("ShaderNodeSqueeze"),
- NodeItem("ShaderNodeSeparateRGB"),
- NodeItem("ShaderNodeCombineRGB"),
- NodeItem("ShaderNodeSeparateHSV"),
- NodeItem("ShaderNodeCombineHSV"),
- ]),
- ShaderOldNodeCategory("SH_GROUP", "Group", items=node_group_items),
- ShaderOldNodeCategory("SH_LAYOUT", "Layout", items=[
- NodeItem("NodeFrame"),
- NodeItem("NodeReroute"),
- ]),
-
- # New Shader Nodes (Cycles)
- ShaderNewNodeCategory("SH_NEW_INPUT", "Input", items=[
+ # Shader Nodes (Cycles and Eevee)
+ ShaderNodeCategory("SH_NEW_INPUT", "Input", items=[
NodeItem("ShaderNodeTexCoord"),
NodeItem("ShaderNodeAttribute"),
NodeItem("ShaderNodeLightPath"),
@@ -218,36 +187,37 @@ shader_node_categories = [
NodeItem("ShaderNodeUVAlongStroke", poll=line_style_shader_nodes_poll),
NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
- ShaderNewNodeCategory("SH_NEW_OUTPUT", "Output", items=[
- NodeItem("ShaderNodeOutputMaterial", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeOutputLamp", poll=object_shader_nodes_poll),
+ ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
+ NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll),
NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll),
NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll),
NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
]),
- ShaderNewNodeCategory("SH_NEW_SHADER", "Shader", items=[
- NodeItem("ShaderNodeMixShader"),
- NodeItem("ShaderNodeAddShader"),
- NodeItem("ShaderNodeBsdfDiffuse", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfPrincipled", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfGlossy", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfTransparent", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfRefraction", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfGlass", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfTranslucent", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfAnisotropic", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfVelvet", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfToon", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeSubsurfaceScattering", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeEmission", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeBsdfHair", poll=object_shader_nodes_poll),
+ ShaderNodeCategory("SH_NEW_SHADER", "Shader", items=[
+ NodeItem("ShaderNodeMixShader", poll=eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeAddShader", poll=eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfDiffuse", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfPrincipled", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfGlossy", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfTransparent", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfRefraction", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfGlass", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfTranslucent", poll=object_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfAnisotropic", poll=object_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfVelvet", poll=object_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfToon", poll=object_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeSubsurfaceScattering", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeEmission", poll=object_eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeBsdfHair", poll=object_cycles_shader_nodes_poll),
NodeItem("ShaderNodeBackground", poll=world_shader_nodes_poll),
- NodeItem("ShaderNodeHoldout", poll=object_shader_nodes_poll),
- NodeItem("ShaderNodeVolumeAbsorption"),
- NodeItem("ShaderNodeVolumeScatter"),
+ NodeItem("ShaderNodeHoldout", poll=object_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeVolumeAbsorption", poll=eevee_cycles_shader_nodes_poll),
+ NodeItem("ShaderNodeVolumeScatter", poll=eevee_cycles_shader_nodes_poll),
NodeItem("ShaderNodeVolumePrincipled"),
+ NodeItem("ShaderNodeEeveeSpecular", poll=object_eevee_shader_nodes_poll),
]),
- ShaderNewNodeCategory("SH_NEW_TEXTURE", "Texture", items=[
+ ShaderNodeCategory("SH_NEW_TEXTURE", "Texture", items=[
NodeItem("ShaderNodeTexImage"),
NodeItem("ShaderNodeTexEnvironment"),
NodeItem("ShaderNodeTexSky"),
@@ -262,7 +232,7 @@ shader_node_categories = [
NodeItem("ShaderNodeTexPointDensity"),
NodeItem("ShaderNodeTexIES"),
]),
- ShaderNewNodeCategory("SH_NEW_OP_COLOR", "Color", items=[
+ ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[
NodeItem("ShaderNodeMixRGB"),
NodeItem("ShaderNodeRGBCurve"),
NodeItem("ShaderNodeInvert"),
@@ -271,7 +241,7 @@ shader_node_categories = [
NodeItem("ShaderNodeGamma"),
NodeItem("ShaderNodeBrightContrast"),
]),
- ShaderNewNodeCategory("SH_NEW_OP_VECTOR", "Vector", items=[
+ ShaderNodeCategory("SH_NEW_OP_VECTOR", "Vector", items=[
NodeItem("ShaderNodeMapping"),
NodeItem("ShaderNodeBump"),
NodeItem("ShaderNodeDisplacement"),
@@ -281,10 +251,11 @@ shader_node_categories = [
NodeItem("ShaderNodeVectorCurve"),
NodeItem("ShaderNodeVectorTransform"),
]),
- ShaderNewNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[
+ ShaderNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[
NodeItem("ShaderNodeMath"),
NodeItem("ShaderNodeValToRGB"),
NodeItem("ShaderNodeRGBToBW"),
+ NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll),
NodeItem("ShaderNodeVectorMath"),
NodeItem("ShaderNodeSeparateRGB"),
NodeItem("ShaderNodeCombineRGB"),
@@ -295,11 +266,11 @@ shader_node_categories = [
NodeItem("ShaderNodeWavelength"),
NodeItem("ShaderNodeBlackbody"),
]),
- ShaderNewNodeCategory("SH_NEW_SCRIPT", "Script", items=[
+ ShaderNodeCategory("SH_NEW_SCRIPT", "Script", items=[
NodeItem("ShaderNodeScript"),
]),
- ShaderNewNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items),
- ShaderNewNodeCategory("SH_NEW_LAYOUT", "Layout", items=[
+ ShaderNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items),
+ ShaderNodeCategory("SH_NEW_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),
NodeItem("NodeReroute"),
]),