diff options
Diffstat (limited to 'release/scripts/startup')
72 files changed, 8982 insertions, 8142 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..cc7f69ca7ca 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 diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py index dda6b2fa5ab..5f3075b403f 100644 --- a/release/scripts/startup/bl_operators/clip.py +++ b/release/scripts/startup/bl_operators/clip.py @@ -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 @@ -942,8 +942,8 @@ 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) @@ -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/file.py b/release/scripts/startup/bl_operators/file.py index 5bb97ff298a..cf03b4fccdb 100644 --- a/release/scripts/startup/bl_operators/file.py +++ b/release/scripts/startup/bl_operators/file.py @@ -65,10 +65,10 @@ class WM_OT_previews_batch_generate(Operator): 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( default=True, @@ -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: @@ -175,10 +175,11 @@ class WM_OT_previews_batch_clear(Operator): name="Scenes", description="Clear scenes' previews", ) - use_groups = BoolProperty(default=True, - name="Groups", - description="Clear groups' previews", - ) + use_collections = BoolProperty( + default=True, + name="Collections", + description="Clear collections' previews", + ) use_objects = BoolProperty( default=True, name="Objects", @@ -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..88368792b8b 100644 --- a/release/scripts/startup/bl_operators/freestyle.py +++ b/release/scripts/startup/bl_operators/freestyle.py @@ -47,15 +47,15 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator): @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 @@ -207,8 +207,8 @@ class SCENE_OT_freestyle_module_open(bpy.types.Operator): @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/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 7fb1877d191..f07c1ccb549 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -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/object.py b/release/scripts/startup/bl_operators/object.py index 91e5859d2c0..fb321463d33 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -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'} @@ -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'} @@ -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'} @@ -513,7 +517,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 +555,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 +648,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 +668,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: @@ -850,7 +854,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 +865,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 +877,6 @@ classes = ( DupliOffsetFromCursor, IsolateTypeRender, JoinUVs, - LodByName, - LodClearAll, - LodGenerate, MakeDupliFace, SelectCamera, SelectHierarchy, diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index c2592f13d66..f087022b6fd 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -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") @@ -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'} @@ -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/presets.py b/release/scripts/startup/bl_operators/presets.py index 8852bca971d..780183fb713 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 @@ -40,6 +47,10 @@ class AddPresetBase: maxlen=64, options={'SKIP_SAVE'}, ) + remove_name = BoolProperty( + default=False, + options={'HIDDEN', 'SKIP_SAVE'}, + ) remove_active = BoolProperty( default=False, options={'HIDDEN', 'SKIP_SAVE'}, @@ -48,6 +59,7 @@ class AddPresetBase: # needed for mix-ins order = [ "name", + "remove_name", "remove_active", ] @@ -85,11 +97,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 +173,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 +213,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: @@ -241,18 +260,55 @@ 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( + cls.bl_space_type, + cls.bl_region_type, + cls.__name__, + icon='PRESET', + text="", + ) + + @classmethod + def draw_menu(cls, layout, text=None): + if text is None: + text = cls.bl_label + + layout.popover( + cls.bl_space_type, + cls.bl_region_type, + 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 +316,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 +325,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" @@ -302,7 +356,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 +372,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 +398,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 +416,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 +442,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 +472,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" @@ -509,7 +506,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 +524,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 +554,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" @@ -670,7 +667,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 +692,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..9fa8188e946 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 @@ -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 @@ -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/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 72445be6950..7620b354a08 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) diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 0b0dd58e80f..0d5bc3136a5 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() diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index f0b1f934e38..aebc0ae0313 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) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 5b12f6196a4..8055ff25090 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: @@ -815,17 +828,17 @@ class WM_OT_context_modal_mouse(Operator): header_text = header_text % eval("item.%s" % self.data_path_item) else: header_text = (self.header_text % delta) + " (delta)" - context.area.header_text_set(header_text) + context.workspace.status_text_set(header_text) elif 'LEFTMOUSE' == event_type: item = next(iter(self._values.keys())) self._values_clear() - context.area.header_text_set() + context.workspace.status_text_set() return operator_value_undo_return(item) elif event_type in {'RIGHTMOUSE', 'ESC'}: self._values_restore() - context.area.header_text_set() + context.workspace.status_text_set() return {'CANCELLED'} return {'RUNNING_MODAL'} @@ -1089,6 +1102,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" @@ -1102,6 +1120,7 @@ class WM_OT_properties_edit(Operator): 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( @@ -1154,6 +1173,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 +1303,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 @@ -1492,54 +1516,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" @@ -1887,6 +1863,37 @@ 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" @@ -2332,6 +2339,174 @@ 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 + cls.draw_cls(layout, context, detect_layout=False, scale_y=1.0) + + wm.popover(draw_menu, 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 +2519,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 +2558,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..da9054fb681 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -39,8 +39,9 @@ _modules = [ "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..10709676b85 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, num_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..1da3d9621aa 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.col(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 index f9394139b42..d613967584c 100644 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ b/release/scripts/startup/bl_ui/properties_data_lamp.py @@ -22,14 +22,6 @@ 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' @@ -37,14 +29,14 @@ class DataButtonsPanel: @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.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'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout @@ -55,20 +47,15 @@ class DATA_PT_context_lamp(DataButtonsPanel, Panel): 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'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): self.layout.template_preview(context.lamp) @@ -76,7 +63,7 @@ class DATA_PT_preview(DataButtonsPanel, Panel): class DATA_PT_lamp(DataButtonsPanel, Panel): bl_label = "Lamp" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -85,239 +72,175 @@ class DATA_PT_lamp(DataButtonsPanel, Panel): layout.row().prop(lamp, "type", expand=True) - split = layout.split() + layout.use_property_split = True - col = split.column() - sub = col.column() - sub.prop(lamp, "color", text="") - sub.prop(lamp, "energy") + col = col.column() + col.prop(lamp, "color") + col.prop(lamp, "energy") if lamp.type in {'POINT', 'SPOT'}: - sub.label(text="Falloff:") - sub.prop(lamp, "falloff_type", text="") - sub.prop(lamp, "distance") + + col = col.column() + col.label(text="Falloff") + col.prop(lamp, "falloff_type") + col.prop(lamp, "distance") + col.prop(lamp, "shadow_soft_size") 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:") + 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") + col.label() -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) +class DATA_PT_EEVEE_lamp(DataButtonsPanel, Panel): + bl_label = "Lamp" + COMPAT_ENGINES = {'BLENDER_EEVEE'} def draw(self, context): layout = self.layout + lamp = context.lamp - 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") + layout.row().prop(lamp, "type", expand=True) - 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.use_property_split = True - layout.separator() + col = layout.column() + col.prop(lamp, "color") + col.prop(lamp, "energy") + col.prop(lamp, "specular_factor", text="Specular") - layout.prop(lamp, "use_atmosphere") + col.separator() - split = layout.split() + if lamp.type in {'POINT', 'SPOT', 'SUN'}: + col.prop(lamp, "shadow_soft_size", text="Radius") + elif lamp.type == 'AREA': + col.prop(lamp, "shape") - 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") + sub = col.column(align=True) - 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") + if lamp.shape in {'SQUARE', 'DISK'}: + sub.prop(lamp, "size") + elif lamp.shape in {'RECTANGLE', 'ELLIPSE'}: + sub.prop(lamp, "size", text="Size X") + sub.prop(lamp, "size_y", text="Y") -class DATA_PT_shadow(DataButtonsPanel, Panel): +class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel): bl_label = "Shadow" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} @classmethod def poll(cls, context): lamp = context.lamp - engine = context.scene.render.engine + engine = context.engine return (lamp and lamp.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) 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 + layout.use_property_split = True 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") + layout.active = lamp.use_shadow - if lamp.shadow_method != 'NOSHADOW': - split = layout.split() + col = layout.column() + sub = col.column(align=True) + sub.prop(lamp, "shadow_buffer_clip_start", text="Clip Start") + sub.prop(lamp, "shadow_buffer_clip_end", text="End") - col = split.column() - col.prop(lamp, "shadow_color", text="") + col.prop(lamp, "shadow_buffer_soft", text="Softness") - col = split.column() - col.prop(lamp, "use_shadow_layer", text="This Layer Only") - col.prop(lamp, "use_only_shadow") + col.separator() - if lamp.shadow_method == 'RAY_SHADOW': - split = layout.split() + col.prop(lamp, "shadow_buffer_bias", text="Bias") + col.prop(lamp, "shadow_buffer_exp", text="Exponent") + col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") - col = split.column() - col.label(text="Sampling:") - if lamp.type in {'POINT', 'SUN', 'SPOT'}: - sub = col.row() +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'} - sub.prop(lamp, "shadow_ray_samples", text="Samples") - sub.prop(lamp, "shadow_soft_size", text="Soft Size") + @classmethod + def poll(cls, context): + lamp = context.lamp + engine = context.engine - elif lamp.type == 'AREA': - sub = col.row(align=True) + return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES) - 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") + def draw(self, context): + layout = self.layout + lamp = context.lamp + layout.use_property_split = True - col.row().prop(lamp, "shadow_ray_sample_method", expand=True) + col = layout.column() - if lamp.shadow_ray_sample_method == 'ADAPTIVE_QMC': - layout.prop(lamp, "shadow_adaptive_threshold", text="Threshold") + col.prop(lamp, "shadow_cascade_count", text="Count") + col.prop(lamp, "shadow_cascade_fade", text="Fade") - 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") + col.prop(lamp, "shadow_cascade_max_distance", text="Max Distance") + col.prop(lamp, "shadow_cascade_exponent", text="Distribution") - 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() +class DATA_PT_EEVEE_shadow_contact(DataButtonsPanel, Panel): + bl_label = "Contact Shadows" + bl_parent_id = "DATA_PT_EEVEE_shadow" + COMPAT_ENGINES = {'BLENDER_EEVEE'} - 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") + @classmethod + def poll(cls, context): + lamp = context.lamp + engine = context.engine + return (lamp and lamp.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES) - 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") + def draw_header(self, context): + lamp = context.lamp - elif lamp.shadow_buffer_type == 'IRREGULAR': - layout.prop(lamp, "shadow_buffer_bias", text="Bias") + layout = self.layout + layout.active = lamp.use_shadow + layout.prop(lamp, "use_contact_shadow", text="") - split = layout.split() + def draw(self, context): + layout = self.layout + lamp = context.lamp + layout.use_property_split = True - 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 = layout.column() + col.active = lamp.use_shadow and lamp.use_contact_shadow - 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") + col.prop(lamp, "contact_shadow_distance", text="Distance") + col.prop(lamp, "contact_shadow_soft_size", text="Softness") + col.prop(lamp, "contact_shadow_bias", text="Bias") + col.prop(lamp, "contact_shadow_thickness", text="Thickness") class DATA_PT_area(DataButtonsPanel, Panel): bl_label = "Area Shape" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): lamp = context.lamp - engine = context.scene.render.engine + engine = context.engine return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES) def draw(self, context): @@ -329,21 +252,21 @@ class DATA_PT_area(DataButtonsPanel, Panel): col.row().prop(lamp, "shape", expand=True) sub = col.row(align=True) - if lamp.shape == 'SQUARE': + if lamp.shape in {'SQUARE', 'DISK'}: sub.prop(lamp, "size") - elif lamp.shape == 'RECTANGLE': + elif lamp.shape in {'RECTANGLE', 'ELLIPSE'}: 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'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): lamp = context.lamp - engine = context.scene.render.engine + engine = context.engine return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES) def draw(self, context): @@ -371,15 +294,40 @@ class DATA_PT_spot(DataButtonsPanel, Panel): sub.prop(lamp, "halo_step", text="Step") +class DATA_PT_spot(DataButtonsPanel, Panel): + bl_label = "Spot Shape" + bl_parent_id = "DATA_PT_EEVEE_lamp" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + lamp = context.lamp + engine = context.engine + return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + lamp = context.lamp + + col = layout.column() + + col.prop(lamp, "spot_size", text="Size") + col.prop(lamp, "spot_blend", text="Blend", slider=True) + + col.prop(lamp, "show_cone") + + class DATA_PT_falloff_curve(DataButtonsPanel, Panel): bl_label = "Falloff Curve" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} @classmethod def poll(cls, context): lamp = context.lamp - engine = context.scene.render.engine + engine = context.engine return (lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE') and (engine in cls.COMPAT_ENGINES) @@ -390,18 +338,19 @@ class DATA_PT_falloff_curve(DataButtonsPanel, Panel): class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} _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_EEVEE_lamp, + 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, 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_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 290b08342be..f5f1339ed97 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_material.py b/release/scripts/startup/bl_ui/properties_material.py index 73740df37e8..fdbf0b240c4 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, find_output_node 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 = find_output_node(ntree, output_type) + 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_EEVEE_MATERIAL', '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..17034689528 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, num_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, num_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, num_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, num_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, num_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..fbc053a565f 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,451 @@ 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") - row = col.row() - row.label(text="Animate:") - row.prop(part, "billboard_animation", text="") - row.label(text="Offset:") - row.prop(part, "billboard_offset_split", text="") + 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") + + +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() - if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD': + 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="") + + 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 +1486,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 +1584,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 - col = split.column() + psys = context.particle_system + part = particle_get_settings(context) + + layout.use_property_split = True + + col = layout.column() col.prop(part, "use_roughness_curve") if part.use_roughness_curve: @@ -1246,8 +1619,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 +1632,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 +1688,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 +1709,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 - split = layout.split(percentage=0.2) - split.label(text="Type 1:") - split.prop(part.force_field_1, "type", text="") + part = particle_get_settings(context) + + 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 +1797,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 +1857,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..72b5d9f1574 100644 --- a/release/scripts/startup/bl_ui/properties_physics_field.py +++ b/release/scripts/startup/bl_ui/properties_physics_field.py @@ -33,60 +33,48 @@ 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') + 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 +84,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 +181,7 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, Panel): md = context.collision split = layout.split() + layout.use_property_split = True coll = md.settings @@ -199,39 +190,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, num_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, num_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..de8bca229e4 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_label = "Dynamics" + bl_parent_id = 'PHYSICS_PT_rigid_body' bl_default_closed = True - 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 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 a5ce345a93c..5458b038d98 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:") + 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") - self.draw_framerate(sub, rd) + col = layout.split(percentage=0.5) + col.alignment = 'RIGHT' + col.label(text="Frame Rate") + self.draw_framerate(col, 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" +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'} - - @classmethod - def poll(cls, context): - rd = context.scene.render - return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - rd = context.scene.render - - 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" - 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() - 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'} + 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(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() - - col = split.column() - col.active = not rd.is_movie_format - col.prop(rd, "use_overwrite") - col.prop(rd, "use_placeholder") + layout.use_property_split = True - 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,418 @@ 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") - else: - split = layout.split() +class RENDER_PT_eevee_ambient_occlusion(RenderButtonsPanel, Panel): + bl_label = "Ambient Occlusion" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} - col = split.column() - col.prop(rd, "use_bake_clear") - col.prop(rd, "bake_margin") + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) - if rd.bake_type == 'DISPLACEMENT': - col = split.column() - col.prop(rd, "use_bake_lores_mesh") + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_gtao", text="") - if rd.bake_type == 'AO': - col = split.column() - col.prop(rd, "bake_bias") - col.prop(rd, "bake_samples") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + props = scene.eevee - if rd.bake_type == 'DERIVATIVE': - row = layout.row() - row.prop(rd, "use_bake_user_scale", text="") + 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") - sub = row.column() - sub.active = rd.use_bake_user_scale - sub.prop(rd, "bake_user_scale", text="User Scale") + +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") + col.prop(props, "shadow_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 + + scene = context.scene + props = scene.eevee + + col = layout.column() + col.prop(props, "gi_diffuse_bounces") + col.prop(props, "gi_cubemap_resolution") + col.prop(props, "gi_visibility_resolution") + + +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) + + 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..43706c360da 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 Color Space") + + +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") + + 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") - 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 = 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 @@ -418,41 +443,75 @@ class SCENE_PT_simplify(SceneButtonsPanel, Panel): 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 Viewport Subdivision") + col.prop(rd, "simplify_child_particles", text="Max Child Particles") + + col.separator() + + col = layout.column() + col.prop(rd, "simplify_subdivision_render", text="Max Render Subdivision") + col.prop(rd, "simplify_child_particles_render", text="Max Child Particles") + - col = split.column() - col.label(text="Viewport:") - col.prop(rd, "simplify_subdivision", text="Subdivision") - col.prop(rd, "simplify_child_particles", text="Child Particles") +class SCENE_PT_viewport_display(SceneButtonsPanel, Panel): + bl_label = "Viewport Display" + bl_options = {'DEFAULT_CLOSED'} - 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") + @classmethod + def poll(cls, context): + return True + + 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 SCENE_PT_viewport_display_ssao(SceneButtonsPanel, Panel): + bl_label = "Screen Space Ambient Occlusion" + bl_parent_id = "SCENE_PT_viewport_display" + + @classmethod + def poll(cls, context): + return True + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + col = layout.column() + col.prop(scene.display, "matcap_ssao_samples") + col.prop(scene.display, "matcap_ssao_distance") + col.prop(scene.display, "matcap_ssao_attenuation") 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_viewport_display, + SCENE_PT_viewport_display_ssao, SCENE_PT_audio, SCENE_PT_physics, SCENE_PT_rigid_body_world, diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index 7da34782364..16e29d1ecc8 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,195 +75,161 @@ 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" + +class TEXTURE_PT_preview(TextureButtonsPanel, Panel): + bl_label = "Preview" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + @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) + return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + tex = context.texture + slot = getattr(context, "texture_slot", None) + idblock = context_tex_datablock(context) -class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel): + if idblock: + layout.template_preview(tex, parent=idblock, slot=slot) + else: + layout.template_preview(tex, slot=slot) + + # Show Alpha Button for Brush Textures, see #29502 + idblock = context_tex_datablock(context) + if isinstance(idblock, Brush): + layout.prop(tex, "use_preview_alpha") + + +class TEXTURE_PT_context(TextureButtonsPanel, Panel): bl_label = "" + bl_context = "texture" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @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)) + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} 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) + space = context.space_data pin_id = space.pin_id + use_pin_id = space.use_pin_id + user = context.texture_user - space.use_limited_texture_context = True - - if space.use_pin_id and not isinstance(pin_id, Texture): - idblock = id_tex_datablock(pin_id) + if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)): 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() + if not pin_id: + layout.template_texture_user() - row = layout.row() + if user or pin_id: + layout.separator() - 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() + split = layout.split(percentage=0.65) + col = split.column() - 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="") + if pin_id: + col.template_ID(space, "pin_id") else: + propname = context.texture_user_property.identifier + col.template_ID(user, propname, new="texture.new") + + if tex: + split = layout.split(percentage=0.2) split.label(text="Type:") split.prop(tex, "type", text="") -class TEXTURE_PT_preview(TextureButtonsPanel, Panel): - bl_label = "Preview" - 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): + node = context.texture_node + return node and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout - tex = context.texture - slot = getattr(context, "texture_slot", None) - idblock = context_tex_datablock(context) + node = context.texture_node + ntree = node.id_data + layout.template_node_view(ntree, node, None) - if idblock: - layout.template_preview(tex, parent=idblock, slot=slot) - else: - layout.template_preview(tex, slot=slot) - # Show Alpha Button for Brush Textures, see #29502 - if context.space_data.texture_context == 'BRUSH': - layout.prop(tex, "use_preview_alpha") +class TEXTURE_PT_node_mapping(TextureButtonsPanel, Panel): + bl_label = "Mapping" + bl_context = "texture" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @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 + + 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 TEXTURE_PT_colors(TextureButtonsPanel, Panel): bl_label = "Colors" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @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) def draw(self, context): layout = self.layout + layout.use_property_split = True tex = context.texture - layout.prop(tex, "use_color_ramp", text="Ramp") - if tex.use_color_ramp: - layout.template_color_ramp(tex, "color_ramp", expand=True) - - split = layout.split() - - col = split.column() - col.label(text="RGB Multiply:") + col = layout.column() sub = col.column(align=True) - sub.prop(tex, "factor_red", text="R") + sub.prop(tex, "factor_red", text="Multiply R") sub.prop(tex, "factor_green", text="G") sub.prop(tex, "factor_blue", text="B") - col = split.column() - col.label(text="Adjust:") col.prop(tex, "intensity") col.prop(tex, "contrast") col.prop(tex, "saturation") - col = layout.column() col.prop(tex, "use_clamp", text="Clamp") - -# Texture Slot Panels # - - -class TextureSlotPanel(TextureButtonsPanel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - if not hasattr(context, "texture_slot"): - return False - - engine = context.scene.render.engine - return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES) - - -# Texture Type Panels # + 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 TextureTypePanel(TextureButtonsPanel): @@ -304,14 +237,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 +268,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 +297,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 +324,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 +339,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 +357,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,7 +377,7 @@ 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 @@ -459,7 +392,7 @@ def texture_filter_common(tex, layout): layout.prop(tex, "filter_type", text="") 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") @@ -471,15 +404,9 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): bl_label = "Image Sampling" bl_options = {'DEFAULT_CLOSED'} 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 idblock = context_tex_datablock(context) @@ -500,17 +427,6 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): 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") - col.prop(tex, "use_mipmap") row = col.row() row.active = tex.use_mipmap @@ -519,39 +435,12 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): texture_filter_common(tex, col) - def draw_bge(self, context): - layout = self.layout - - 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.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_options = {'DEFAULT_CLOSED'} tex_type = 'IMAGE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout @@ -603,62 +492,10 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, Panel): 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() - - 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) - - 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 +531,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 +567,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 +586,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 +610,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 +640,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 +670,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 +677,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 +688,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 +707,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,47 +761,26 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel): col.prop(tex, "invert", text="Negative") col.prop(tex, "use_stencil") - if isinstance(idblock, Material) or isinstance(idblock, World): - col.prop(tex, "default_value", text="DVar", slider=True) - - if isinstance(idblock, Material): - layout.label(text="Bump Mapping:") - - # only show bump settings if activated but not for normal-map images - row = layout.row() - - 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") - 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_context, + TEXTURE_PT_node, + TEXTURE_PT_node_mapping, + TEXTURE_PT_mapping, + TEXTURE_PT_influence, TEXTURE_PT_colors, TEXTURE_PT_clouds, TEXTURE_PT_wood, @@ -1254,17 +791,9 @@ classes = ( TEXTURE_PT_image, 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_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..bba7f9e132a 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, find_output_node 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 = find_output_node(ntree, ('OUTPUT_WORLD',)) - 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..d4ae3121a88 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,18 @@ 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) - row = layout.row() row.template_ID(sc, "clip", open="clip.open") + CLIP_MT_tracking_editor_menus.draw_collapsible(context, layout) + if clip: tracking = clip.tracking active_object = tracking.objects.active + layout.separator_spacer() + 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 +78,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 +99,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 +108,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 +116,36 @@ 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) row = layout.row() row.template_ID(sc, "clip", open="clip.open") if clip: - layout.prop(sc, "mode", text="") - 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 +278,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 +290,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 +621,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 +712,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 +1226,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 +1419,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 +1524,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..9ae20ba2194 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,157 @@ 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="") + row.prop(dopesheet, "use_multi_word_filter", 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="") + row.prop(dopesheet, "use_multi_word_filter", 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="") + row.prop(dopesheet, "use_multi_word_filter", 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, num_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.lamps: + flow.prop(dopesheet, "show_lamps", text="Lamps") + 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,16 +204,42 @@ 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.popover( + space_type='DOPESHEET_EDITOR', + region_type='HEADER', + panel_type="DOPESHEET_PT_filters", + text="", + icon='FILTER', + ) + 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 - layout.prop(st, "mode", text="") + @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') @@ -134,7 +250,7 @@ class DOPESHEET_HT_header(Header): 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() if st.mode == 'DOPESHEET': dopesheet_filter(layout, context) @@ -152,17 +268,16 @@ 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.prop(st.dopesheet, "use_multi_word_filter", text="") + + layout.separator_spacer() 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) + 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) # Grease Pencil mode doesn't need snapping, as it's frame-aligned only if st.mode != 'GPENCIL': @@ -233,9 +348,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): @@ -449,8 +562,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 +635,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_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 5ed58a57e47..e3ebb99d859 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,9 +38,18 @@ class GRAPH_HT_header(Header): row = layout.row(align=True) row.template_header() - GRAPH_MT_editor_menus.draw_collapsible(context, layout) + # Now a exposed as a sub-space type + # layout.prop(st, "mode", text="") - layout.prop(st, "mode", text="") + layout.popover( + space_type='GRAPH_EDITOR', + region_type='HEADER', + panel_type="GRAPH_PT_filters", + text="", + icon='FILTER', + ) + + GRAPH_MT_editor_menus.draw_collapsible(context, layout) dopesheet_filter(layout, context) @@ -48,13 +59,13 @@ class GRAPH_HT_header(Header): sub.active = st.use_normalization sub.prop(st, "use_auto_normalization", icon='FILE_REFRESH', text="", toggle=True) - row = layout.row(align=True) + layout.separator_spacer() - 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) + 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, "auto_snap", text="") layout.prop(st, "pivot_point", icon_only=True) @@ -71,6 +82,21 @@ class GRAPH_HT_header(Header): 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): bl_idname = "GRAPH_MT_editor_menus" bl_label = "" @@ -129,9 +155,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): @@ -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 9cbb27bcedb..1acc8cf601d 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, @@ -126,9 +126,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): @@ -194,7 +192,7 @@ class IMAGE_MT_image(Menu): show_render = sima.show_render - layout.operator("image.read_renderlayers") + layout.operator("image.read_viewlayers") layout.operator("image.save_dirty", text="Save All Images") @@ -424,6 +422,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' @@ -443,20 +478,16 @@ class IMAGE_HT_header(Header): row = layout.row(align=True) row.template_header() - MASK_MT_editor_menus.draw_collapsible(context, layout) + layout.prop(sima, "mode", text="") 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 @@ -469,10 +500,25 @@ class IMAGE_HT_header(Header): layout.prop(toolsettings, "uv_select_mode", text="", expand=True) layout.prop(uvedit, "sticky_select_mode", icon_only=True) + MASK_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator_spacer() + + if show_uvedit or show_maskedit or mode == 'PAINT': + layout.prop(sima, "use_realtime_update", icon_only=True, icon='LOCKED') + + if show_uvedit: + uvedit = sima.uv_editor + + mesh = context.edit_object.data + layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="") + 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) + # 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) row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") @@ -480,8 +526,7 @@ class IMAGE_HT_header(Header): 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="") + layout.prop(sima, "pivot_point", icon_only=True) if ima: if ima.is_stereo_3d: @@ -501,9 +546,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" @@ -615,50 +657,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' @@ -690,11 +688,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() @@ -726,10 +724,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): @@ -1353,6 +1382,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, @@ -1362,7 +1392,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 c7bebf68eea..e5ef5f9a0da 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -26,347 +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") - layout.operator("screen.screencast") - - 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..9a5f835d505 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 @@ -35,13 +37,37 @@ class NLA_HT_header(Header): row = layout.row(align=True) row.template_header() + layout.popover( + space_type='NLA_EDITOR', + region_type='HEADER', + panel_type="NLA_PT_filters", + text="", + icon='FILTER', + ) + NLA_MT_editor_menus.draw_collapsible(context, layout) dopesheet_filter(layout, context) + layout.separator_spacer() 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 +116,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): @@ -219,6 +243,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..521c510ad2d 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,16 +49,14 @@ 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="", expand=True) ob = context.object - if (not scene.render.use_shading_nodes or snode.shader_type == 'OBJECT') and ob: + if snode.shader_type == 'OBJECT' and ob: row = layout.row() # disable material slot buttons when pinned, cannot find correct slot within id_from (#36589) row.enabled = not snode.pin @@ -68,24 +67,32 @@ class NODE_HT_header(Header): if id_from and ob.type != 'LAMP': 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") + # No shader nodes for Eevee lamps + if snode_id and not (context.engine == 'BLENDER_EEVEE' and ob.type == 'LAMP'): + row.prop(snode_id, "use_nodes") + + NODE_MT_editor_menus.draw_collapsible(context, layout) - if scene.render.use_shading_nodes and snode.shader_type == 'WORLD': + if 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 + NODE_MT_editor_menus.draw_collapsible(context, layout) + + if snode.shader_type == 'LINESTYLE': + view_layer = context.view_layer + lineset = view_layer.freestyle_settings.linesets.active if lineset is not None: row = layout.row() row.enabled = not snode.pin row.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new") + + NODE_MT_editor_menus.draw_collapsible(context, layout) + if snode_id: row.prop(snode_id, "use_nodes") @@ -97,21 +104,31 @@ class NODE_HT_header(Header): 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") + NODE_MT_editor_menus.draw_collapsible(context, layout) + elif snode.tree_type == 'CompositorNodeTree': + if snode_id: layout.prop(snode_id, "use_nodes") + + NODE_MT_editor_menus.draw_collapsible(context, layout) + + 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 layout.template_ID(snode, "node_tree", new="node.new_node_tree") + NODE_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator_spacer() layout.prop(snode, "pin", text="") layout.operator("node.tree_path_parent", text="", icon='FILE_PARENT') @@ -194,9 +211,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 +286,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 +307,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 +374,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 +384,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 +443,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 +584,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..44813b699a2 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,41 @@ 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 in {'VIEW_LAYER'}: + layout.operator("outliner.collection_new", text="", icon='GROUP').nested = True - 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(space_type='OUTLINER', + region_type='HEADER', + panel_type="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 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 +77,8 @@ 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") + + OUTLINER_MT_editor_menus.draw_collapsible(context, layout) class OUTLINER_MT_editor_menus(Menu): @@ -73,11 +93,13 @@ class OUTLINER_MT_editor_menus(Menu): 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") + elif space.display_mode == 'ORPHAN_DATA': + layout.menu("OUTLINER_MT_edit_orphan_data") + class OUTLINER_MT_view(Menu): bl_label = "View" @@ -87,56 +109,202 @@ class OUTLINER_MT_view(Menu): space = context.space_data - if space.display_mode not in {'DATABLOCKS', 'USER_PREFERENCES'}: + layout.prop(space, "use_filter_complete", text="Exact Match Search") + layout.prop(space, "use_filter_case_sensitive", text="Case Sensitive Search") + + layout.separator() + + if space.display_mode != 'DATA_API': layout.prop(space, "use_sort_alpha") layout.prop(space, "show_restrict_columns") layout.separator() layout.operator("outliner.show_active") + layout.separator() + 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("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 OUTLINER_MT_search(Menu): - bl_label = "Search" +class OUTLINER_MT_edit_datablocks(Menu): + bl_label = "Edit" def draw(self, context): layout = self.layout - space = context.space_data + layout.operator("outliner.keyingset_add_selected") + layout.operator("outliner.keyingset_remove_selected") - layout.prop(space, "use_filter_case_sensitive") - layout.prop(space, "use_filter_complete") + layout.separator() + layout.operator("outliner.drivers_add_selected") + layout.operator("outliner.drivers_delete_selected") -class OUTLINER_MT_edit_datablocks(Menu): + +class OUTLINER_MT_edit_orphan_data(Menu): bl_label = "Edit" def draw(self, context): layout = self.layout + layout.operator("outliner.orphans_purge") + + +class OUTLINER_MT_collection_view_layer(Menu): + bl_label = "View Layer" + + def draw(self, context): + layout = self.layout + + space = context.space_data + + layout.operator("outliner.collection_exclude_set", text="Exclude") + layout.operator("outliner.collection_include_set", text="Include") - layout.operator("outliner.keyingset_add_selected") - layout.operator("outliner.keyingset_remove_selected") + +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.drivers_add_selected") - layout.operator("outliner.drivers_delete_selected") + 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.menu("OUTLINER_MT_collection_view_layer") + + layout.separator() + layout.operator_menu_enum("outliner.id_operation", "type", text="ID Data") + + +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 + + +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.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() + + 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") + + +class OUTLINER_PT_filter(Panel): + bl_space_type = 'OUTLINER' + bl_region_type = 'HEADER' + bl_label = "Filter" + + def draw(self, context): + layout = self.layout + + space = context.space_data + display_mode = space.display_mode + + layout.prop(space, "use_filter_collection", text="Collections") + + layout.separator() + + col = layout.column() + col.prop(space, "use_filter_object", text="Objects") + active = space.use_filter_object + + sub = col.column(align=True) + sub.active = active + sub.prop(space, "filter_state", text="") + sub.prop(space, "use_filter_object_content", text="Object Contents") + sub.prop(space, "use_filter_children", text="Object Children") + + layout.separator() + + col = layout.column_flow(align=True) + col.active = active + + if bpy.data.meshes: + col.prop(space, "use_filter_object_mesh", text="Meshes") + if bpy.data.armatures: + col.prop(space, "use_filter_object_armature", text="Armatures") + if bpy.data.lamps: + col.prop(space, "use_filter_object_lamp", text="Lamps") + if bpy.data.cameras: + col.prop(space, "use_filter_object_camera", text="Cameras") + + col.prop(space, "use_filter_object_empty", text="Empties") + + if bpy.data.curves or \ + bpy.data.metaballs or \ + bpy.data.lightprobes or \ + bpy.data.lattices or \ + bpy.data.fonts or bpy.data.speakers: + col.prop(space, "use_filter_object_others", text="Others") classes = ( OUTLINER_HT_header, OUTLINER_MT_editor_menus, OUTLINER_MT_view, - OUTLINER_MT_search, OUTLINER_MT_edit_datablocks, + OUTLINER_MT_edit_orphan_data, + OUTLINER_MT_collection, + OUTLINER_MT_collection_new, + OUTLINER_MT_collection_view_layer, + OUTLINER_MT_object, + 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 0697cf8e56b..ce1d1da038c 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -79,14 +79,14 @@ 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) - layout.prop(st, "view_type", expand=True, text="") - if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}: layout.prop(st, "display_mode", expand=True, text="") @@ -237,9 +237,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): @@ -431,10 +429,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 +1282,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..b0cfe424d3e --- /dev/null +++ b/release/scripts/startup/bl_ui/space_statusbar.py @@ -0,0 +1,79 @@ +# ##### 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): + area = context.area + region = context.region + + if region.alignment == 'RIGHT': + if region == area.regions[0]: + self.draw_right(context) + else: + self.draw_center(context) + else: + self.draw_left(context) + + def draw_left(self, context): + layout = self.layout + + layout.template_input_status() + + def draw_center(self, context): + layout = self.layout + + scene = context.scene + view_layer = context.view_layer + + layout.label(text=scene.statistics(view_layer), translate=False) + + def draw_right(self, context): + layout = self.layout + + 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 + + +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 98a7da855ca..b1af82c95fe 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -180,9 +180,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..4616aeb45a4 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -18,45 +18,29 @@ # <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) + layout.separator_spacer() 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() + row.prop(toolsettings, "use_keyframe_insert_auto", text="", toggle=True) - row = layout.row(align=True) row.operator("screen.frame_jump", text="", icon='REW').end = False row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False if not screen.is_animation_playing: @@ -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) + layout.separator_spacer() - 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.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.popover( + space_type='DOPESHEET_EDITOR', + region_type='HEADER', + panel_type="TIME_PT_playback", + text="Playback", + ) + layout.popover( + space_type='DOPESHEET_EDITOR', + region_type='HEADER', + panel_type="TIME_PT_keyframing_settings", + text="Keying", + ) layout.menu("TIME_MT_view") layout.menu("TIME_MT_marker") - layout.menu("TIME_MT_frame") - layout.menu("TIME_MT_playback") 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.operator("marker.delete", text="Delete Marker") - layout.menu("TIME_MT_autokey") + layout.separator() + layout.operator("marker.rename", text="Rename Marker") + layout.operator("marker.move", text="Grab/Move Marker") + + layout.separator() + + layout.operator("marker.camera_bind") + + layout.separator() -class TIME_MT_playback(Menu): + 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_PT_keyframing_settings(TimelinePanelButtons, Panel): + bl_label = "Keyframing Settings" + bl_options = {'HIDE_HEADER'} + bl_region_type = 'HEADER' -class TIME_MT_autokey(Menu): - bl_label = "Auto-Keyframing Mode" + @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..20db56af416 --- /dev/null +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -0,0 +1,683 @@ +# ##### 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 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, + "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 "", + 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. + """ + 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) + + 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 + + if not item.keymap: + continue + + # Only check the first item in the tools key-map (a little arbitrary). + 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] + 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', + any=kmi_found.any, + shift=kmi_found.shift, + ctrl=kmi_found.ctrl, + alt=kmi_found.alt, + oskey=kmi_found.oskey, + key_modifier=kmi_found.key_modifier, + ) + kmi.properties.name = item.text + + 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..c5c17d2c3cb --- /dev/null +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -0,0 +1,1083 @@ +# ##### 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="Move", + cursor='SCROLL_XY', + icon="ops.transform.translate", + widget="TRANSFORM_WGT_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", + 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", + 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", + ) + + @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", + 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.translate, + _defs_transform.transform, + ), + _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..5ea5923c1e0 --- /dev/null +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -0,0 +1,601 @@ +# ##### 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_ARMATURE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".armature_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="") + + +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 TOPBAR_PT_pivot_point(Panel): + bl_space_type = 'TOPBAR' + bl_region_type = 'HEADER' + bl_label = "Pivot Point" + + def draw(self, context): + toolsettings = context.tool_settings + obj = context.active_object + mode = context.mode + + layout = self.layout + col = layout.column() + col.label("Pivot Point") + col.prop(toolsettings, "transform_pivot_point", expand=True) + + 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 TOPBAR_PT_snapping(Panel): + bl_space_type = 'TOPBAR' + 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 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", 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_context = 'INVOKE_AREA' + layout.operator("wm.save_homefile", icon='SAVE_PREFS') + layout.operator("wm.read_factory_settings", icon='LOAD_FACTORY') + + 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.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", icon='IMAGE_COL') + 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", icon='SETTINGS') + + 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() + + # 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_fullscreen_toggle", icon='FULLSCREEN_ENTER') + + layout.separator() + + layout.operator("screen.screenshot") + layout.operator("screen.screencast") + + 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') + + +classes = ( + TOPBAR_HT_upper_bar, + TOPBAR_HT_lower_bar, + TOPBAR_PT_pivot_point, + TOPBAR_PT_snapping, + 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 b7d425bbc6f..90917d52724 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -22,6 +22,7 @@ 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 @@ -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,46 @@ 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() + col.prop(view, "show_manipulator_navigate") + + sub = col.column(align=True) + + sub.prop(view, "show_mini_axis", text="Display Mini Axis") + sub.active = not view.show_manipulator_navigate + + sub = col.column(align=True) sub.active = view.show_mini_axis 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="Transform Manipulator") + # Currently not working + # col.prop(view, "show_manipulator_shaded") + 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 +281,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 +305,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 +325,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:") @@ -477,7 +489,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() @@ -517,7 +528,6 @@ 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") @@ -533,8 +543,6 @@ class USERPREF_PT_system(Panel): 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!") @@ -542,6 +550,10 @@ class USERPREF_PT_system(Panel): col.prop(system, "use_region_overlap") col.separator() + col.label(text="Max Viewport Anti-aliasing Method") + col.prop(system, "max_anti_alias_method", text="") + + col.separator() col.label(text="Text Draw Options:") col.prop(system, "use_text_antialiasing") @@ -724,6 +736,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) @@ -803,6 +816,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) @@ -851,6 +867,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:") @@ -865,6 +884,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) @@ -873,7 +893,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() @@ -888,34 +909,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() @@ -933,9 +942,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() @@ -1432,12 +1445,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(): @@ -1571,6 +1585,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, @@ -1591,6 +1661,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 c8f113f558d..6645a1b12ef 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -34,117 +34,174 @@ 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="") + # 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 & Pivot + if object_mode in {'OBJECT', 'EDIT', 'POSE'}: + layout.prop(scene, "transform_orientation", text="") + + 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.popover( + space_type='TOPBAR', + region_type='HEADER', + panel_type="TOPBAR_PT_pivot_point", + icon=act_pivot_point.icon, + text="", + ) + + if obj: # 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.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) + + elif object_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.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) + + elif object_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) + 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: # 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) + 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) # 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 - if obj: - if (mode == 'EDIT' and obj.type == 'MESH'): - layout.prop(toolsettings, "use_mesh_automerge", text="", icon='AUTOMERGE_ON') - - # 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 + icon = 'NONE' - # 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 + row.prop(tool_settings, "use_snap", text="") + + sub = row.row(align=True) + sub.popover( + space_type='TOPBAR', + region_type='HEADER', + panel_type="TOPBAR_PT_snapping", + icon=icon, + text="" + ) - # 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') + layout.separator_spacer() - # XXX: icon - layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH') + # Viewport Settings + row = layout.row(align=True) + row.prop(shading, "type", text="", expand=True) - 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) + sub = row.row(align=True) + sub.enabled = shading.type != 'RENDERED' + sub.popover(space_type='VIEW_3D', region_type='HEADER', panel_type="VIEW3D_PT_shading") + + 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(space_type='VIEW_3D', region_type='HEADER', panel_type="VIEW3D_PT_overlay") class VIEW3D_MT_editor_menus(Menu): @@ -161,48 +218,56 @@ class VIEW3D_MT_editor_menus(Menu): edit_object = context.edit_object gp_edit = context.gpencil_data and context.gpencil_data.use_stroke_edit_mode - layout.menu("VIEW3D_MT_view") + # Use aligned row to squeeze out a bit more space. + row = layout.row(align=True) + row.menu("VIEW3D_MT_view") # Select Menu if gp_edit: - layout.menu("VIEW3D_MT_select_gpencil") + row.menu("VIEW3D_MT_select_gpencil") elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}: mesh = obj.data if mesh.use_paint_mask: - layout.menu("VIEW3D_MT_select_paint_mask") + row.menu("VIEW3D_MT_select_paint_mask") elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}: - layout.menu("VIEW3D_MT_select_paint_mask_vertex") + row.menu("VIEW3D_MT_select_paint_mask_vertex") elif mode_string != 'SCULPT': - layout.menu("VIEW3D_MT_select_%s" % mode_string.lower()) + row.menu("VIEW3D_MT_select_%s" % mode_string.lower()) if gp_edit: pass elif mode_string == 'OBJECT': - layout.menu("INFO_MT_add", text="Add") + row.menu("INFO_MT_add", text="Add") elif mode_string == 'EDIT_MESH': - layout.menu("INFO_MT_mesh_add", text="Add") + row.menu("INFO_MT_mesh_add", text="Add") elif mode_string == 'EDIT_CURVE': - layout.menu("INFO_MT_curve_add", text="Add") + row.menu("INFO_MT_curve_add", text="Add") elif mode_string == 'EDIT_SURFACE': - layout.menu("INFO_MT_surface_add", text="Add") + row.menu("INFO_MT_surface_add", text="Add") elif mode_string == 'EDIT_METABALL': - layout.menu("INFO_MT_metaball_add", text="Add") + row.menu("INFO_MT_metaball_add", text="Add") elif mode_string == 'EDIT_ARMATURE': - layout.menu("INFO_MT_edit_armature_add", text="Add") + row.menu("INFO_MT_edit_armature_add", text="Add") if gp_edit: - layout.menu("VIEW3D_MT_edit_gpencil") + row.menu("VIEW3D_MT_edit_gpencil") elif edit_object: - layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower()) + row.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower()) + + if mode_string == 'EDIT_MESH': + row.menu("VIEW3D_MT_edit_mesh_vertices") + row.menu("VIEW3D_MT_edit_mesh_edges") + row.menu("VIEW3D_MT_edit_mesh_faces") + elif obj: if mode_string != 'PAINT_TEXTURE': - layout.menu("VIEW3D_MT_%s" % mode_string.lower()) + row.menu("VIEW3D_MT_%s" % mode_string.lower()) if mode_string in {'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'PAINT_TEXTURE'}: - layout.menu("VIEW3D_MT_brush") + row.menu("VIEW3D_MT_brush") if mode_string == 'SCULPT': - layout.menu("VIEW3D_MT_hide_mask") + row.menu("VIEW3D_MT_hide_mask") else: - layout.menu("VIEW3D_MT_object") + row.menu("VIEW3D_MT_object") # ********** Menu ********** @@ -232,15 +297,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 +357,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 +478,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 +490,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 +508,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 +536,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): @@ -662,16 +726,12 @@ class VIEW3D_MT_select_object(Menu): layout.separator() - layout.operator("object.select_all").action = 'TOGGLE' - layout.operator("object.select_all", text="Inverse").action = 'INVERT' - - 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("object.select_all", text="Select/Deselect All").action = 'TOGGLE' 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_all", text="Inverse Selection").action = 'INVERT' + layout.operator("object.select_mirror", text="Mirror Selection") + layout.operator("object.select_random", text="Select Random") layout.separator() @@ -679,8 +739,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...") @@ -789,7 +849,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") @@ -853,19 +914,19 @@ class VIEW3D_MT_select_edit_mesh(Menu): layout.separator() # primitive - layout.operator("mesh.select_all").action = 'TOGGLE' - layout.operator("mesh.select_all", text="Inverse").action = 'INVERT' + layout.operator("mesh.select_all", text="Select/Deselect All").action = 'TOGGLE' + layout.operator("mesh.select_all", text="Inverse Selection").action = 'INVERT' 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 +952,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): @@ -967,10 +1028,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") @@ -1183,13 +1240,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 +1264,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 +1287,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): @@ -1278,6 +1360,17 @@ class INFO_MT_lamp_add(Menu): layout.operator_enum("object.lamp_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): bl_idname = "INFO_MT_camera_add" bl_label = "Camera" @@ -1326,37 +1419,32 @@ class INFO_MT_add(Menu): layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP') 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 +1472,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 +1484,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 +1515,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 +1542,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 +1584,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 +1597,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' @@ -1549,52 +1694,39 @@ class VIEW3D_MT_object_specials(Menu): 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 lamp.node_tree: + for node in lamp.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 = "Lamp 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 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.energy" - props.header_text = "Lamp Energy: %.3f" + props.data_path_item = "data.size" + props.header_text = "Lamp Size X: %.3f" - if lamp.type in {'SPOT', 'AREA', 'POINT'}: - props = layout.operator("wm.context_modal_mouse", text="Falloff Distance") + if lamp.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 = "Lamp Size Y: %.3f" + + 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" if lamp.type == 'SPOT': layout.separator() @@ -1610,23 +1742,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 +1836,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 +1901,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 +1943,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 +2020,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 +2088,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 +2113,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 +2136,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 +2203,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 +2224,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") @@ -2191,10 +2289,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 +2481,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 +2571,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 +2585,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 +2721,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 +2758,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 +2829,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 +2845,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 +2869,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 +2887,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.separator() - layout.operator("mesh.normals_make_consistent", text="Recalculate Normals").inside = False + 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 +2964,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 +3072,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 +3096,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 +3153,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 +3200,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 +3259,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 +3269,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 +3290,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 +3305,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 +3315,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 +3361,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 +3431,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 +3442,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 +3466,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 +3480,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 +3517,28 @@ 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_viewnumpad", "type") + pie.operator("view3d.view_selected", text="View Selected", icon='ZOOM_SELECTED') + + # ********** Panel ********** @@ -3455,540 +3621,535 @@ class VIEW3D_PT_view3d_cursor(Panel): layout.column().prop(view, "cursor_location", text="Location") -class VIEW3D_PT_view3d_name(Panel): +class VIEW3D_PT_shading(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Item" + bl_region_type = 'HEADER' + bl_label = "Shading" @classmethod def poll(cls, context): - return (context.space_data and context.active_object) + return True 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="") - - 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="") + pass -class VIEW3D_PT_view3d_display(Panel): +class VIEW3D_PT_shading_lighting(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Display" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' + bl_label = "Lighting" + bl_parent_id = 'VIEW3D_PT_shading' @classmethod def poll(cls, context): - view = context.space_data - return (view) + return True def draw(self, context): layout = self.layout view = context.space_data - scene = context.scene - - col = layout.column() - col.prop(view, "show_only_render") - col.prop(view, "show_world") + shading = view.shading - 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") + if shading.type == 'SOLID': + layout.row().prop(shading, "light", expand=True) + if shading.light == 'STUDIO': + row = layout.row() + row.template_icon_view(shading, "studio_light", show_labels=True) + sub = row.column() + sub.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') + if shading.selected_studio_light.orientation == 'WORLD': + layout.row().prop(shading, "studiolight_rot_z") - col = layout.column() - col.active = display_all - split = col.split(percentage=0.55) - split.prop(view, "show_floor", text="Grid Floor") + elif shading.light == 'MATCAP': + row = layout.row() + row.template_icon_view(shading, "studio_light", show_labels=True) + sub = row.column() + sub.operator('VIEW3D_OT_toggle_matcap_flip', emboss=False, text="", icon='ARROW_LEFTRIGHT') + sub.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') + + elif shading.type == 'MATERIAL': + row = layout.row() + row.template_icon_view(shading, "studio_light", show_labels=True) + sub = row.column() + sub.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') + if shading.selected_studio_light.orientation == 'WORLD': + layout.row().prop(shading, "studiolight_rot_z") + layout.row().prop(shading, "studiolight_background_alpha") + layout.prop(shading, "use_scene_light") + + +class VIEW3D_PT_shading_color(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Color" + bl_parent_id = 'VIEW3D_PT_shading' - 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) + @classmethod + def poll(cls, context): + view = context.space_data + shading = view.shading + return shading.type in ['SOLID'] - 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") + def draw(self, context): + layout = self.layout - layout.separator() + view = context.space_data + shading = view.shading - layout.operator("screen.region_quadview", text="Toggle Quad View") + layout.row().prop(shading, "color_type", expand=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") + if shading.color_type == 'SINGLE': + layout.row().prop(shading, "single_color", text="") -class VIEW3D_PT_view3d_stereo(Panel): +class VIEW3D_PT_shading_options(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Stereoscopy" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' + bl_label = "Options" + bl_parent_id = 'VIEW3D_PT_shading' @classmethod def poll(cls, context): - scene = context.scene - - multiview = scene.render.use_multiview - return context.space_data and multiview + view = context.space_data + shading = view.shading + return shading.type == 'SOLID' def draw(self, context): layout = self.layout - view = context.space_data - - basic_stereo = context.scene.render.views_format == 'STEREO_3D' - - col = layout.column() - col.row().prop(view, "stereo_3d_camera", expand=True) - - col.label(text="Display:") - row = col.row() - row.active = basic_stereo - row.prop(view, "show_stereo_3d_cameras") - row = col.row() - row.active = basic_stereo - split = row.split() - split.prop(view, "show_stereo_3d_convergence_plane") - split = row.split() - split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha") - split.active = view.show_stereo_3d_convergence_plane - row = col.row() - split = row.split() - split.prop(view, "show_stereo_3d_volume") - split = row.split() - split.prop(view, "stereo_3d_volume_alpha", text="Alpha") - -class VIEW3D_PT_view3d_shading(Panel): + view = context.space_data + shading = view.shading + + if not shading.light == 'MATCAP': + row = layout.row() + row.prop(shading, "show_specular_highlight") + + row = layout.split(0.4) + row.prop(shading, "show_xray") + sub = row.row() + sub.active = shading.show_xray + sub.prop(shading, "xray_alpha", text="") + + row = layout.split(0.4) + row.active = not shading.show_xray + row.prop(shading, "show_shadows") + sub = row.row() + sub.active = shading.show_shadows and not shading.show_xray + sub.prop(shading, "shadow_intensity", text="") + + row = layout.split(0.4) + row.active = not shading.show_xray + row.prop(shading, "show_cavity") + sub = row.column(align=True) + sub.active = not shading.show_xray and shading.show_cavity + sub.prop(shading, "cavity_ridge_factor") + sub.prop(shading, "cavity_valley_factor") + + row = layout.split(0.4) + row.prop(shading, "show_object_outline") + sub = row.row() + sub.active = shading.show_object_outline + sub.prop(shading, "object_outline_color", text="") + + layout.prop(view, "show_world") + + +class VIEW3D_PT_overlay(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Shading" + bl_region_type = 'HEADER' + bl_label = "Overlays" + + @classmethod + def poll(cls, context): + return True def draw(self, context): layout = self.layout view = context.space_data - scene = context.scene - gs = scene.game_settings - obj = context.object + shading = view.shading + 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="") + split = col.split() - 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") + sub = split.column() + sub.prop(view, "show_manipulator", text="Manipulators") + sub.prop(overlay, "show_text", text="Text") + sub.prop(overlay, "show_cursor", text="3D Cursor") + sub.prop(overlay, "show_outline_selected") + sub.prop(overlay, "show_all_objects_origin") - col.prop(view, "show_backface_culling") + sub = split.column() + sub.prop(overlay, "show_relationship_lines") + sub.prop(overlay, "show_motion_paths") + #sub.prop(overlay, "show_onion_skins") + sub.prop(overlay, "show_face_orientation") + sub.prop(overlay, "show_backface_culling") + if shading.type == 'MATERIAL': + sub.prop(overlay, "show_look_dev") - if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: - if obj and obj.mode == 'EDIT': - col.prop(view, "show_occlude_wire") + row = col.row() + row.prop(overlay, "show_wireframes") + sub = row.row() + sub.active = overlay.show_wireframes + sub.prop(overlay, "wireframe_threshold", text="") - fx_settings = view.fx_settings + col = layout.column() + col.active = display_all + split = col.split(percentage=0.55) + split.prop(overlay, "show_floor", text="Grid Floor") - 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 = split.row(align=True) + row.prop(overlay, "show_axis_x", text="X", toggle=True) + row.prop(overlay, "show_axis_y", text="Y", toggle=True) + row.prop(overlay, "show_axis_z", text="Z", toggle=True) + + 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.column(align=True) + subsub.active = overlay.show_floor + subsub.prop(overlay, "grid_scale", text="Scale") + subsub.prop(overlay, "grid_subdivisions", text="Subdivisions") + + col.prop(view, "show_reconstruction", text="Motion Tracking") + if view.show_reconstruction: + sub = col.column(align=True) + sub.active = view.show_reconstruction + sub.prop(view, "show_camera_path", text="Camera Path") + sub.prop(view, "show_bundle_names", text="3D Marker Names") + sub.label(text="Track Type and Size:") + row = sub.row(align=True) + row.prop(view, "tracks_draw_type", text="") + row.prop(view, "tracks_draw_size", text="") + + +class VIEW3D_PT_overlay_edit_mesh(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Motion Tracking" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Edit Mesh" @classmethod def poll(cls, context): - view = context.space_data - return (view) - - def draw_header(self, context): - view = context.space_data - - self.layout.prop(view, "show_reconstruction", text="") + return context.mode == 'EDIT_MESH' def draw(self, context): layout = self.layout view = context.space_data + shading = view.shading + overlay = view.overlay + tool_settings = context.tool_settings + display_all = overlay.show_overlays + data = context.active_object.data + statvis = tool_settings.statvis + with_freestyle = bpy.app.build_options.freestyle + show_developer_ui = context.user_preferences.view.show_developer_ui 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="") - - -class VIEW3D_PT_view3d_meshdisplay(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Mesh Display" - - @classmethod - def poll(cls, context): - # The active object check is needed because of local-mode - return (context.active_object and (context.mode == 'EDIT_MESH')) - - def draw(self, context): - layout = self.layout - with_freestyle = bpy.app.build_options.freestyle + col.active = display_all - mesh = context.active_object.data - scene = context.scene + split = col.split() - split = layout.split() + sub = split.column() + sub.prop(data, "show_faces", text="Faces") + sub.prop(data, "show_edges", text="Edges") + sub.prop(data, "show_edge_crease", text="Creases") + sub.prop(data, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural) + sub.prop(data, "show_edge_bevel_weight", text="Bevel") + if not with_freestyle: + sub.prop(data, "show_edge_seams", text="Seams") - 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(overlay, "show_occlude_wire") + sub.prop(data, "show_extra_edge_length", text="Edge Length") + sub.prop(data, "show_extra_edge_angle", text="Edge Angle") + sub.prop(data, "show_extra_face_area", text="Face Area") + sub.prop(data, "show_extra_face_angle", text="Face Angle") - layout.prop(mesh, "show_weight") + if show_developer_ui: + sub.prop(data, "show_extra_indices", text="Indices") - 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") - - col = layout.column() + col.label(text="Freestyle:") + row = col.row() + 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") - col.separator() col.label(text="Normals:") row = col.row(align=True) - 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') + 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 = mesh.show_normal_vertex or mesh.show_normal_face or mesh.show_normal_loop - sub.prop(scene.tool_settings, "normal_size", text="Size") - - 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): + sub.active = overlay.show_vertex_normals or overlay.show_face_normals or overlay.show_split_normals + sub.prop(overlay, "normals_length", text="Size") + + col.prop(overlay, "show_weight") + if overlay.show_weight: + col.label("Show Zero Weights:") + col.row().prop(tool_settings, "vertex_group_user", expand=True) + + col.prop(data, "show_statvis", text="Mesh Analysis") + if data.show_statvis: + sub = col.column() + sub.active = data.show_statvis + sub.prop(statvis, "type") + statvis_type = statvis.type + if statvis_type == 'OVERHANG': + row = sub.row(align=True) + row.prop(statvis, "overhang_min", text="") + row.prop(statvis, "overhang_max", text="") + sub.row().prop(statvis, "overhang_axis", expand=True) + elif statvis_type == 'THICKNESS': + row = sub.row(align=True) + row.prop(statvis, "thickness_min", text="") + row.prop(statvis, "thickness_max", text="") + sub.prop(statvis, "thickness_samples") + elif statvis_type == 'INTERSECT': + pass + elif statvis_type == 'DISTORT': + row = sub.row(align=True) + row.prop(statvis, "distort_min", text="") + row.prop(statvis, "distort_max", text="") + elif statvis_type == 'SHARP': + row = sub.row(align=True) + row.prop(statvis, "sharp_min", text="") + row.prop(statvis, "sharp_max", text="") + + +class VIEW3D_PT_overlay_edit_curve(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Mesh Analysis" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Edit Curve" @classmethod def poll(cls, context): - # The active object check is needed because of local-mode - return (context.active_object and (context.mode == 'EDIT_MESH')) - - def draw_header(self, context): - mesh = context.active_object.data - - self.layout.prop(mesh, "show_statvis", text="") + 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 - mesh = context.active_object.data - statvis = context.tool_settings.statvis - layout.active = mesh.show_statvis + col = layout.column() + col.active = display_all - 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="") + row = col.row() + row.prop(data, "show_handles", text="Handles") + row.prop(data, "show_normal_face", text="Normals") -class VIEW3D_PT_view3d_curvedisplay(Panel): +class VIEW3D_PT_overlay_sculpt(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Curve Display" + bl_context = ".sculpt_mode" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Sculpt" @classmethod def poll(cls, context): - editmesh = context.mode == 'EDIT_CURVE' - return (editmesh) + 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 - curve = context.active_object.data - - col = layout.column() - 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") + layout.prop(sculpt, "show_diffuse_color") + layout.prop(sculpt, "show_mask") -class VIEW3D_PT_background_image(Panel): +class VIEW3D_PT_overlay_pose(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' + bl_label = "Pose Mode" - def draw_header(self, context): - view = context.space_data - - self.layout.prop(view, "show_background_images", text="") + @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") - - 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 - - box.prop(bg, "view_axis", text="Axis") - - 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") + col.active = display_all + col.prop(overlay, "show_transparent_bones") + row = col.split(0.65) + row.prop(overlay, "show_bone_selection") + sub = row.column() + sub.active = display_all and overlay.show_bone_selection + sub.prop(overlay, "bone_selection_alpha", text="") - 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_edit_armature(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Edit Armature" - 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 == 'EDIT_ARMATURE' - elif bg.source == 'MOVIE_CLIP': - box.prop(bg, "use_camera_clip") + def draw(self, context): + layout = self.layout + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays - column = box.column() - column.active = not bg.use_camera_clip - column.template_ID(bg, "clip", open="clip.open") + col = layout.column() + col.active = display_all + col.prop(overlay, "show_transparent_bones") - if bg.clip: - column.template_movieclip(bg, "clip", compact=True) - if bg.use_camera_clip or bg.clip: - has_bg = True +class VIEW3D_PT_overlay_paint(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "" - column = box.column() - column.active = has_bg - column.prop(bg.clip_user, "proxy_render_size", text="") - column.prop(bg.clip_user, "use_render_undistorted") + @classmethod + def poll(cls, context): + return context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'} - if has_bg: - col = box.column() - col.prop(bg, "opacity", slider=True) - col.row().prop(bg, "draw_depth", expand=True) + 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]) - if bg.view_axis in {'CAMERA', 'ALL'}: - col.row().prop(bg, "frame_method", expand=True) + def draw(self, context): + layout = self.layout + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays - box = col.box() - row = box.row() - row.prop(bg, "offset_x", text="X") - row.prop(bg, "offset_y", text="Y") + col = layout.column() + col.active = display_all - row = box.row() - row.prop(bg, "use_flip_x") - row.prop(bg, "use_flip_y") + 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") - row = box.row() - if bg.view_axis != 'CAMERA': - row.prop(bg, "rotation") - row.prop(bg, "size") + if context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX'}: + col.prop(overlay, "show_paint_wire") -class VIEW3D_PT_transform_orientations(Panel): +class VIEW3D_PT_quad_view(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_label = "Transform Orientations" + bl_label = "Quad View" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): view = context.space_data - return (view) + return view.region_quadviews def draw(self, context): layout = self.layout view = context.space_data - orientation = view.current_orientation - row = layout.row(align=True) - row.prop(view, "transform_orientation", text="") - row.operator("transform.create_orientation", text="", icon='ZOOMIN') - - if orientation: - row = layout.row(align=True) - row.prop(orientation, "name", text="") - row.operator("transform.delete_orientation", text="", icon='X') + 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") -class VIEW3D_PT_etch_a_ton(Panel): +class VIEW3D_PT_view3d_stereo(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_label = "Skeleton Sketching" + bl_label = "Stereoscopy" 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 + scene = context.scene - layout.prop(toolsettings, "use_bone_sketching", text="") + multiview = scene.render.use_multiview + return context.space_data and multiview def draw(self, context): layout = self.layout + view = context.space_data - toolsettings = context.scene.tool_settings + basic_stereo = context.scene.render.views_format == 'STEREO_3D' col = layout.column() + col.row().prop(view, "stereo_3d_camera", expand=True) - col.prop(toolsettings, "use_etch_quick") - col.prop(toolsettings, "use_etch_overdraw") + 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") - col.separator() - col.prop(toolsettings, "etch_convert_mode") +class VIEW3D_PT_transform_orientations(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_label = "Transform Orientations" + bl_options = {'DEFAULT_CLOSED'} - 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") + @classmethod + def poll(cls, context): + view = context.space_data + return (view) - col.separator() + def draw(self, context): + layout = self.layout - 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") + scene = context.scene + orientation = scene.current_orientation - col.separator() + row = layout.row(align=True) + row.prop(scene, "transform_orientation", text="") + row.operator("transform.create_orientation", text="", icon='ZOOMIN') - col.operator("sketch.convert", text="Convert to Bones") - col.operator("sketch.delete", text="Delete Strokes") + if orientation: + row = layout.row(align=True) + row.prop(orientation, "name", text="") + row.operator("transform.delete_orientation", text="", icon='X') class VIEW3D_PT_context_properties(Panel): @@ -4000,10 +4161,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" @@ -4076,24 +4237,25 @@ classes = ( INFO_MT_edit_armature_add, INFO_MT_armature_add, INFO_MT_lamp_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, @@ -4129,7 +4291,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, @@ -4155,21 +4320,26 @@ 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_cursor, - VIEW3D_PT_view3d_name, - VIEW3D_PT_view3d_display, + 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_overlay, + VIEW3D_PT_overlay_edit_mesh, + VIEW3D_PT_overlay_edit_curve, + VIEW3D_PT_overlay_edit_armature, + VIEW3D_PT_overlay_pose, + VIEW3D_PT_overlay_paint, + VIEW3D_PT_overlay_sculpt, 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..864dcc4b0e9 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 @@ -944,8 +261,9 @@ class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel): col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL' +# 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 +517,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 +528,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,22 +577,13 @@ 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") @@ -1289,10 +595,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 +612,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 +622,30 @@ 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", open="image.open") + colsub.operator("image.new", text="New").gen_context = 'PAINT_STENCIL' - 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 +710,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 +735,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 +758,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 +779,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 +813,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 +860,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,8 +890,9 @@ 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'} @@ -1580,16 +901,18 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): 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 toolsettings = context.tool_settings sculpt = toolsettings.sculpt @@ -1598,7 +921,8 @@ 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'): row = sub.row(align=True) @@ -1608,20 +932,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 == 'CONSTANT'): + 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 +980,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 +995,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 +1087,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 +1100,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 +1131,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 +1147,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 +1163,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 +1185,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 +1197,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 +1248,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 +1268,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 +1377,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 +1397,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 +1412,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 3826b2b10de..713dbdafcc5 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): @@ -141,62 +133,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"), @@ -217,36 +186,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("ShaderNodeOutputLamp", 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"), @@ -261,7 +231,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"), @@ -270,7 +240,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"), @@ -280,10 +250,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"), @@ -294,11 +265,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"), ]), |