diff options
Diffstat (limited to 'release/scripts/startup/bl_ui')
29 files changed, 1210 insertions, 361 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 25484e905c3..1fb40ad8bc8 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -117,6 +117,8 @@ def register(): for cls in mod.classes: register_class(cls) + space_filebrowser.register_props() + from bpy.props import ( EnumProperty, StringProperty, diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py index 6c3c1fd1721..28e456d023d 100644 --- a/release/scripts/startup/bl_ui/properties_animviz.py +++ b/release/scripts/startup/bl_ui/properties_animviz.py @@ -68,21 +68,28 @@ class MotionPathButtonsPanel: col.prop(mpath, "frame_start", text="Cache From") col.prop(mpath, "frame_end", text="To") - row = layout.row(align=True) + col = layout.column(align=True) + if bones: - row.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA') - row.operator("pose.paths_clear", text="", icon='X') + col.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA') else: - row.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA') - row.operator("object.paths_clear", text="", icon='X') + col.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA') else: col = layout.column(align=True) col.label(text="Nothing to show yet...", icon='ERROR') + if bones: col.operator("pose.paths_calculate", text="Calculate...", icon='BONE_DATA') else: col.operator("object.paths_calculate", text="Calculate...", icon='OBJECT_DATA') + row = col.row(align=True) + row.operator("object.paths_update_visible", text="Update All Paths", icon='WORLD') + if bones: + row.operator("pose.paths_clear", text="", icon='X') + else: + row.operator("object.paths_clear", text="", icon='X') + class MotionPathButtonsPanel_display: bl_space_type = 'PROPERTIES' diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 2a0cf56534c..fcac0af7e86 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -70,7 +70,7 @@ class ConstraintButtonsPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_label = "" - bl_options = {'INSTANCED', 'HEADER_LAYOUT_EXPAND', 'DRAW_BOX'} + bl_options = {'INSTANCED', 'HEADER_LAYOUT_EXPAND'} @staticmethod def draw_influence(layout, con): @@ -976,7 +976,6 @@ class ConstraintButtonsSubPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_label = "" - bl_options = {'DRAW_BOX'} def get_constraint(self, _context): con = self.custom_data @@ -1147,6 +1146,35 @@ class ConstraintButtonsSubPanel: col.prop(con, "frame_start", text="Frame Start") col.prop(con, "frame_end", text="End") + def draw_transform_cache_velocity(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_velocity + ) + + def draw_transform_cache_procedural(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_procedural + ) + + def draw_transform_cache_time(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_time_settings + ) + + def draw_transform_cache_layers(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_layers + ) + + def draw_transform_cache_subpanel(self, context, template_func): + con = self.get_constraint(context) + if con.cache_file is None: + return + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = True + template_func(con, "cache_file") # Child Of Constraint @@ -1336,7 +1364,7 @@ class BONE_PT_bLockTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel, self.draw_lock_track(context) -# Disance Limit Constraint +# Distance Limit Constraint class OBJECT_PT_bDistLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel): def draw(self, context): @@ -1535,6 +1563,70 @@ class BONE_PT_bTransformCacheConstraint(BoneConstraintPanel, ConstraintButtonsPa self.draw_transform_cache(context) +class OBJECT_PT_bTransformCacheConstraint_velocity(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Velocity" + + def draw(self, context): + self.draw_transform_cache_velocity(context) + + +class BONE_PT_bTransformCacheConstraint_velocity(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Velocity" + + def draw(self, context): + self.draw_transform_cache_velocity(context) + + +class OBJECT_PT_bTransformCacheConstraint_layers(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Override Layers" + + def draw(self, context): + self.draw_transform_cache_layers(context) + + +class BONE_PT_bTransformCacheConstraint_layers(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Override Layers" + + def draw(self, context): + self.draw_transform_cache_layers(context) + + +class OBJECT_PT_bTransformCacheConstraint_procedural(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Render Procedural" + + def draw(self, context): + self.draw_transform_cache_procedural(context) + + +class BONE_PT_bTransformCacheConstraint_procedural(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Render Procedural" + + def draw(self, context): + self.draw_transform_cache_procedural(context) + + +class OBJECT_PT_bTransformCacheConstraint_time(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Time" + + def draw(self, context): + self.draw_transform_cache_time(context) + + +class BONE_PT_bTransformCacheConstraint_time(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Time" + + def draw(self, context): + self.draw_transform_cache_time(context) + + # Python Constraint class OBJECT_PT_bPythonConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel): @@ -1621,6 +1713,10 @@ classes = ( OBJECT_PT_bCameraSolverConstraint, OBJECT_PT_bObjectSolverConstraint, OBJECT_PT_bTransformCacheConstraint, + OBJECT_PT_bTransformCacheConstraint_time, + OBJECT_PT_bTransformCacheConstraint_procedural, + OBJECT_PT_bTransformCacheConstraint_velocity, + OBJECT_PT_bTransformCacheConstraint_layers, OBJECT_PT_bPythonConstraint, OBJECT_PT_bArmatureConstraint, OBJECT_PT_bArmatureConstraint_bones, @@ -1658,6 +1754,10 @@ classes = ( BONE_PT_bCameraSolverConstraint, BONE_PT_bObjectSolverConstraint, BONE_PT_bTransformCacheConstraint, + BONE_PT_bTransformCacheConstraint_time, + BONE_PT_bTransformCacheConstraint_procedural, + BONE_PT_bTransformCacheConstraint_velocity, + BONE_PT_bTransformCacheConstraint_layers, BONE_PT_bPythonConstraint, BONE_PT_bArmatureConstraint, BONE_PT_bArmatureConstraint_bones, diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 87572fcd438..22f3d1a9c50 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -220,6 +220,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): ).pose_index = poselib.pose_markers.active_index col.operator("poselib.action_sanitize", icon='HELP', text="") # XXX: put in menu? + col.operator("poselib.convert_old_poselib", icon='ASSET_MANAGER', text="") if pose_marker_active is not None: col.operator("poselib.pose_move", icon='TRIA_UP', text="").direction = 'UP' diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index daf64642f68..1a00150d6d2 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -196,7 +196,7 @@ class BONE_PT_curved(BoneButtonsPanel, Panel): row2.prop(bone, "bbone_handle_use_scale_start", index=1, text="Y", toggle=True) row2.prop(bone, "bbone_handle_use_scale_start", index=2, text="Z", toggle=True) split2.prop(bone, "bbone_handle_use_ease_start", text="Ease", toggle=True) - row.label(icon="BLANK1") + row.label(icon='BLANK1') col = topcol.column(align=True) col.prop(bone, "bbone_handle_type_end", text="End Handle") @@ -216,7 +216,7 @@ class BONE_PT_curved(BoneButtonsPanel, Panel): row2.prop(bone, "bbone_handle_use_scale_end", index=1, text="Y", toggle=True) row2.prop(bone, "bbone_handle_use_scale_end", index=2, text="Z", toggle=True) split2.prop(bone, "bbone_handle_use_ease_end", text="Ease", toggle=True) - row.label(icon="BLANK1") + row.label(icon='BLANK1') class BONE_PT_relations(BoneButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index a8ef5c14a91..20bee833847 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -110,6 +110,13 @@ class DATA_PT_lens(CameraButtonsPanel, Panel): sub = col.column(align=True) sub.prop(ccam, "longitude_min", text="Longitude Min") sub.prop(ccam, "longitude_max", text="Max") + elif ccam.panorama_type == 'FISHEYE_LENS_POLYNOMIAL': + col.prop(ccam, "fisheye_fov") + col.prop(ccam, "fisheye_polynomial_k0", text="K0") + col.prop(ccam, "fisheye_polynomial_k1", text="K1") + col.prop(ccam, "fisheye_polynomial_k2", text="K2") + col.prop(ccam, "fisheye_polynomial_k3", text="K3") + col.prop(ccam, "fisheye_polynomial_k4", text="K4") elif engine == 'BLENDER_EEVEE': col.prop(cam, "panorama_type") if cam.panorama_type == 'FISHEYE_EQUIDISTANT': diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py index 793c4a52350..34e83573bc9 100644 --- a/release/scripts/startup/bl_ui/properties_data_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -110,7 +110,8 @@ class GPENCIL_MT_layer_context_menu(Menu): layout.separator() - layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down") + layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down").mode = 'ACTIVE' + layout.operator("gpencil.layer_merge", text="Merge All").mode = 'ALL' layout.separator() layout.operator("gpencil.layer_duplicate_object", text="Copy Layer to Selected").only_active = True diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index ba5ecd1efde..11e2cd84903 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -82,6 +82,14 @@ class MESH_MT_shape_key_context_menu(Menu): layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP' layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM' +class MESH_MT_attribute_context_menu(Menu): + bl_label = "Attribute Specials" + + def draw(self, context): + layout = self.layout + + layout.operator("geometry.attribute_convert") + class MESH_UL_vgroups(UIList): def draw_item(self, _context, layout, _data, item, icon, _active_data_, _active_propname, _index): @@ -557,6 +565,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel): col.enabled = obj is not None and obj.mode != 'EDIT' col.prop(me, "use_customdata_vertex_bevel", text="Vertex Bevel Weight") col.prop(me, "use_customdata_edge_bevel", text="Edge Bevel Weight") + col.prop(me, "use_customdata_vertex_crease", text="Vertex Crease") col.prop(me, "use_customdata_edge_crease", text="Edge Crease") @@ -614,6 +623,10 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): col.operator("geometry.attribute_add", icon='ADD', text="") col.operator("geometry.attribute_remove", icon='REMOVE', text="") + col.separator() + + col.menu("MESH_MT_attribute_context_menu", icon='DOWNARROW_HLT', text="") + self.draw_attribute_warnings(context, layout) def draw_attribute_warnings(self, context, layout): @@ -651,6 +664,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): classes = ( MESH_MT_vertex_group_context_menu, MESH_MT_shape_key_context_menu, + MESH_MT_attribute_context_menu, MESH_UL_vgroups, MESH_UL_fmaps, MESH_UL_shape_keys, diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py index 3c765c10154..802812020b7 100644 --- a/release/scripts/startup/bl_ui/properties_freestyle.py +++ b/release/scripts/startup/bl_ui/properties_freestyle.py @@ -280,7 +280,7 @@ class VIEWLAYER_PT_freestyle_lineset(ViewLayerFreestyleEditorButtonsPanel, Panel col.separator() - col.menu("RENDER_MT_lineset_context_menu", icon="DOWNARROW_HLT", text="") + col.menu("RENDER_MT_lineset_context_menu", icon='DOWNARROW_HLT', text="") if is_sortable: col.separator() @@ -526,7 +526,7 @@ class VIEWLAYER_PT_freestyle_linestyle_strokes(ViewLayerFreestyleLineStyle, Pane row = layout.row(align=True) row.alignment = 'LEFT' row.label(text=lineset.name, icon='LINE_DATA') - row.label(text="", icon='SMALL_TRI_RIGHT_VEC') + row.label(text="", icon='RIGHTARROW') row.label(text=linestyle.name) col = layout.column(align=True) @@ -830,7 +830,7 @@ class VIEWLAYER_PT_freestyle_linestyle_color(ViewLayerFreestyleLineStyle, Panel) row = layout.row(align=True) row.alignment = 'LEFT' row.label(text=lineset.name, icon='LINE_DATA') - row.label(text="", icon='SMALL_TRI_RIGHT_VEC') + row.label(text="", icon='RIGHTARROW') row.label(text=linestyle.name) col = layout.column() @@ -922,7 +922,7 @@ class VIEWLAYER_PT_freestyle_linestyle_alpha(ViewLayerFreestyleLineStyle, Panel) row = layout.row(align=True) row.alignment = 'LEFT' row.label(text=lineset.name, icon='LINE_DATA') - row.label(text="", icon='SMALL_TRI_RIGHT_VEC') + row.label(text="", icon='RIGHTARROW') row.label(text=linestyle.name) col = layout.column() @@ -1036,7 +1036,7 @@ class VIEWLAYER_PT_freestyle_linestyle_thickness(ViewLayerFreestyleLineStyle, Pa row = layout.row(align=True) row.alignment = 'LEFT' row.label(text=lineset.name, icon='LINE_DATA') - row.label(text="", icon='SMALL_TRI_RIGHT_VEC') + row.label(text="", icon='RIGHTARROW') row.label(text=linestyle.name) col = layout.column() @@ -1182,7 +1182,7 @@ class VIEWLAYER_PT_freestyle_linestyle_geometry(ViewLayerFreestyleLineStyle, Pan row = layout.row(align=True) row.alignment = 'LEFT' row.label(text=lineset.name, icon='LINE_DATA') - row.label(text="", icon='SMALL_TRI_RIGHT_VEC') + row.label(text="", icon='RIGHTARROW') row.label(text=linestyle.name) col = layout.column() @@ -1215,7 +1215,7 @@ class VIEWLAYER_PT_freestyle_linestyle_texture(ViewLayerFreestyleLineStyle, Pane row = layout.row(align=True) row.alignment = 'LEFT' row.label(text=lineset.name, icon='LINE_DATA') - row.label(text="", icon='SMALL_TRI_RIGHT_VEC') + row.label(text="", icon='RIGHTARROW') row.label(text=linestyle.name) layout.prop(linestyle, "use_nodes") diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 81a641a20cf..fbd4ed3225a 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -184,24 +184,18 @@ class OBJECT_PT_collections(ObjectButtonsPanel, Panel): row.operator("object.collection_add", text="Add to Collection") row.operator("object.collection_add", text="", icon='ADD') - obj_name = obj.name - for collection in bpy.data.collections: - # XXX this is slow and stupid!, we need 2 checks, one that's fast - # and another that we can be sure its not a name collision - # from linked library data - collection_objects = collection.objects - if obj_name in collection.objects and obj in collection_objects[:]: - col = layout.column(align=True) - - col.context_pointer_set("collection", collection) - - row = col.box().row() - row.prop(collection, "name", text="") - row.operator("object.collection_remove", text="", icon='X', emboss=False) - row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="") - - row = col.box().row() - row.prop(collection, "instance_offset", text="") + for collection in obj.users_collection: + col = layout.column(align=True) + + col.context_pointer_set("collection", collection) + + row = col.box().row() + row.prop(collection, "name", text="") + row.operator("object.collection_remove", text="", icon='X', emboss=False) + row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="") + + row = col.box().row() + row.prop(collection, "instance_offset", text="") class OBJECT_PT_display(ObjectButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index c038f5f906a..347f771d1f6 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -496,7 +496,7 @@ class DisplayPanel(BrushPanel): icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON', ) - if mode in ['PAINT_2D', 'PAINT_TEXTURE', 'PAINT_VERTEX', 'SCULPT']: + if mode in {'PAINT_2D', 'PAINT_TEXTURE', 'PAINT_VERTEX', 'SCULPT'}: row = col.row(align=True) row.prop(brush, "texture_overlay_alpha", text="Texture Opacity") row.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA') @@ -506,7 +506,7 @@ class DisplayPanel(BrushPanel): icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON', ) - if mode in ['PAINT_TEXTURE', 'PAINT_2D']: + if mode in {'PAINT_TEXTURE', 'PAINT_2D'}: row = col.row(align=True) row.prop(brush, "mask_overlay_alpha", text="Mask Texture Opacity") row.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA') @@ -1107,7 +1107,11 @@ def brush_basic_texpaint_settings(layout, context, brush, *, compact=False): capabilities = brush.image_paint_capabilities if capabilities.has_color: - UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="") + row = layout.row(align=True) + row.ui_units_x = 4 + UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="") + UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="") + row.separator() layout.prop(brush, "blend", text="" if compact else "Blend") UnifiedPaintPanel.prop_unified( @@ -1151,7 +1155,8 @@ def brush_basic__draw_color_selector(context, layout, brush, gp_settings, props) if len(txt_ma) > maxw: txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:] - sub = row.row() + sub = row.row(align=True) + sub.enabled = not gp_settings.use_material_pin sub.ui_units_x = 8 sub.popover( panel="TOPBAR_PT_gpencil_materials", diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index 6408d4096fe..47f0b399b66 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -227,7 +227,12 @@ class PHYSICS_PT_settings(PhysicButtonsPanel, Panel): split.enabled = note_flag and ob.mode == 'OBJECT' bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end) - if domain.cache_resumable and domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete: + if ( + domain.cache_resumable and + domain.has_cache_baked_data and + not domain.is_cache_baking_data and + bake_incomplete + ): col = split.column() col.operator("fluid.bake_data", text="Resume") col = split.column() @@ -1249,7 +1254,12 @@ class PHYSICS_PT_cache(PhysicButtonsPanel, Panel): split.enabled = ob.mode == 'OBJECT' bake_incomplete = (domain.cache_frame_pause_data < domain.cache_frame_end) - if domain.cache_resumable and domain.has_cache_baked_data and not domain.is_cache_baking_data and bake_incomplete: + if ( + domain.cache_resumable and + domain.has_cache_baked_data and + not domain.is_cache_baking_data and + bake_incomplete + ): col = split.column() col.operator("fluid.bake_all", text="Resume") col = split.column() diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index a55bd89ca18..9afe8415cf4 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -109,7 +109,11 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): @classmethod def poll(cls, context): obj = context.object - if obj.parent is not None and obj.parent.rigid_body is not None and not obj.parent.rigid_body.collision_shape == 'COMPOUND': + if ( + (obj.parent is not None) and + (obj.parent.rigid_body is not None) and + (not obj.parent.rigid_body.collision_shape == 'COMPOUND') + ): return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) @@ -124,7 +128,11 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): layout.prop(rbo, "collision_shape", text="Shape") if rbo.collision_shape == 'COMPOUND': - if parent is not None and parent.rigid_body is not None and parent.rigid_body.collision_shape == 'COMPOUND': + if ( + (parent is not None) and + (parent.rigid_body is not None) and + (parent.rigid_body.collision_shape == 'COMPOUND') + ): rigid_body_warning(layout, "Sub compound shapes are not allowed") else: found = False @@ -179,7 +187,11 @@ class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, P @classmethod def poll(cls, context): obj = context.object - if obj.parent is not None and obj.parent.rigid_body is not None and not obj.parent.rigid_body.collision_shape == 'COMPOUND': + if ( + (obj.parent is not None) and + (obj.parent.rigid_body is not None) and + (not obj.parent.rigid_body.collision_shape == 'COMPOUND') + ): return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) @@ -249,7 +261,7 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): # col = layout.column(align=True) # col.label(text="Activation:") - # XXX: settings such as activate on collison/etc. + # XXX: settings such as activate on collision/etc. col = flow.column() col.prop(rbo, "linear_damping", text="Damping Translation") diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 4b341e969c4..1387b1e7450 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -198,6 +198,10 @@ class ViewLayerCryptomattePanel(ViewLayerButtonsPanel, Panel): view_layer.use_pass_cryptomatte_asset)) col.prop(view_layer, "pass_cryptomatte_depth", text="Levels") + if context.engine == 'BLENDER_EEVEE': + col.prop(view_layer, "use_pass_cryptomatte_accurate", + text="Accurate Mode") + class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanel, Panel): bl_parent_id = "VIEWLAYER_PT_layer_passes" diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index c18d77987ad..86e9ef3d664 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1858,6 +1858,43 @@ class CLIP_MT_reconstruction_pie(Menu): pie.operator("clip.apply_solution_scale", icon='ARROW_LEFTRIGHT') +class CLIP_MT_view_pie(Menu): + bl_label = "View" + + @classmethod + def poll(cls, context): + space = context.space_data + + # View operators are not yet implemented in Dopesheet mode. + return space.view != 'DOPESHEET' + + def draw(self, context): + layout = self.layout + sc = context.space_data + + pie = layout.menu_pie() + + if sc.view == 'CLIP': + pie.operator("clip.view_all") + pie.operator("clip.view_selected", icon='ZOOM_SELECTED') + + if sc.mode == 'MASK': + pie.operator("clip.view_center_cursor") + pie.separator() + else: + # Add spaces so items stay in the same position through all modes. + pie.separator() + pie.separator() + + pie.operator("clip.view_all", text="Frame All Fit").fit_view = True + + if sc.view == 'GRAPH': + pie.operator_context = 'INVOKE_REGION_PREVIEW' + pie.operator("clip.graph_view_all") + pie.separator() + pie.operator("clip.graph_center_current_frame") + + classes = ( CLIP_UL_tracking_objects, CLIP_HT_header, @@ -1925,6 +1962,7 @@ classes = ( CLIP_MT_tracking_pie, CLIP_MT_reconstruction_pie, CLIP_MT_solving_pie, + CLIP_MT_view_pie, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 781c430a752..18dfa4da6c6 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -379,6 +379,18 @@ class DOPESHEET_MT_view(Menu): layout.menu("INFO_MT_area") +class DOPESHEET_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, _context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("action.view_all") + pie.operator("action.view_selected", icon='ZOOM_SELECTED') + pie.operator("action.view_frame") + + class DOPESHEET_MT_select(Menu): bl_label = "Select" @@ -527,6 +539,39 @@ class DOPESHEET_MT_key_transform(Menu): layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE' +class DopesheetActionPanelBase: + bl_region_type = 'UI' + bl_label = "Action" + + @classmethod + def draw_generic_panel(cls, _context, layout, action): + layout.label(text=action.name, icon='ACTION') + + layout.prop(action, "use_frame_range") + + col = layout.column() + col.active = action.use_frame_range + + row = col.row(align=True) + row.prop(action, "frame_start", text="Start") + row.prop(action, "frame_end", text="End") + + col.prop(action, "use_cyclic") + + +class DOPESHEET_PT_action(DopesheetActionPanelBase, Panel): + bl_space_type = 'DOPESHEET_EDITOR' + bl_category = "Item" + + @classmethod + def poll(cls, context): + return bool(context.selected_visible_actions) + + def draw(self, context): + action = context.selected_visible_actions[0] + self.draw_generic_panel(context, self.layout, action) + + ####################################### # Grease Pencil Editing @@ -778,7 +823,9 @@ classes = ( DOPESHEET_MT_context_menu, DOPESHEET_MT_channel_context_menu, DOPESHEET_MT_snap_pie, + DOPESHEET_MT_view_pie, DOPESHEET_PT_filters, + DOPESHEET_PT_action, DOPESHEET_PT_gpencil_mode, DOPESHEET_PT_gpencil_layer_masks, DOPESHEET_PT_gpencil_layer_transform, diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index b47404fd727..50005a8f7f0 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -36,15 +36,10 @@ class FILEBROWSER_HT_header(Header): space_data = context.space_data params = space_data.params - row = layout.row(align=True) - row.prop(params, "asset_library_ref", text="") - # External libraries don't auto-refresh, add refresh button. - if params.asset_library_ref != 'LOCAL': - row.operator("file.refresh", text="", icon='FILE_REFRESH') - layout.separator_spacer() - layout.prop(params, "import_type", text="") + if params.asset_library_ref != 'LOCAL': + layout.prop(params, "import_type", text="") layout.separator_spacer() @@ -57,7 +52,15 @@ class FILEBROWSER_HT_header(Header): icon_only=True, ) - layout.prop(params, "filter_search", text="", icon='VIEWZOOM') + sub = layout.row() + sub.ui_units_x = 8 + sub.prop(params, "filter_search", text="", icon='VIEWZOOM') + + layout.popover( + panel="ASSETBROWSER_PT_filter", + text="", + icon='FILTER' + ) layout.operator( "screen.region_toggle", @@ -132,7 +135,7 @@ class FILEBROWSER_PT_display(FileBrowserPanel, Panel): class FILEBROWSER_PT_filter(FileBrowserPanel, Panel): bl_region_type = 'HEADER' bl_label = "Filter Settings" # Shows as tooltip in popover - bl_ui_units_x = 8 + bl_ui_units_x = 10 def draw(self, context): layout = self.layout @@ -195,13 +198,14 @@ class FILEBROWSER_PT_filter(FileBrowserPanel, Panel): sub = row.column(align=True) - if context.preferences.experimental.use_extended_asset_browser: - sub.prop(params, "use_filter_asset_only") + sub.prop(params, "use_filter_asset_only") filter_id = params.filter_id for identifier in dir(filter_id): if identifier.startswith("category_"): - sub.prop(filter_id, identifier, toggle=True) + subrow = sub.row() + subrow.label(icon=filter_id.bl_rna.properties[identifier].icon) + subrow.prop(filter_id, identifier, toggle=False) col.separator() @@ -394,11 +398,19 @@ class FILEBROWSER_PT_advanced_filter(Panel): filter_id = params.filter_id for identifier in dir(filter_id): if identifier.startswith("filter_"): - col.prop(filter_id, identifier, toggle=True) + row = col.row() + row.label(icon=filter_id.bl_rna.properties[identifier].icon) + row.prop(filter_id, identifier, toggle=False) def is_option_region_visible(context, space): - if not space.active_operator: + from bpy_extras.asset_utils import SpaceAssetInfo + + if SpaceAssetInfo.is_asset_browser(space): + pass + # For the File Browser, there must be an operator for there to be options + # (irrelevant for the Asset Browser). + elif not space.active_operator: return False for region in context.area.regions: @@ -594,6 +606,31 @@ class ASSETBROWSER_PT_display(asset_utils.AssetBrowserPanel, Panel): col.prop(params, "show_details_datetime", text="Date") +class ASSETBROWSER_PT_filter(asset_utils.AssetBrowserPanel, Panel): + bl_region_type = 'HEADER' + bl_category = "Filter" + bl_label = "Filter" + + def draw(self, context): + layout = self.layout + space = context.space_data + params = space.params + use_extended_browser = context.preferences.experimental.use_extended_asset_browser + + if params.use_filter_blendid: + col = layout.column(align=True) + + filter_id = params.filter_asset_id + for identifier in dir(filter_id): + if ( + identifier.startswith("filter_") or + (identifier.startswith("experimental_filter_") and use_extended_browser) + ): + row = col.row() + row.label(icon=filter_id.bl_rna.properties[identifier].icon) + row.prop(filter_id, identifier, toggle=False) + + class AssetBrowserMenu: @classmethod def poll(cls, context): @@ -610,6 +647,7 @@ class ASSETBROWSER_MT_editor_menus(AssetBrowserMenu, Menu): layout.menu("ASSETBROWSER_MT_view") layout.menu("ASSETBROWSER_MT_select") + layout.menu("ASSETBROWSER_MT_edit") class ASSETBROWSER_MT_view(AssetBrowserMenu, Menu): @@ -648,28 +686,14 @@ class ASSETBROWSER_MT_select(AssetBrowserMenu, Menu): layout.operator("file.select_box") -class ASSETBROWSER_PT_navigation_bar(asset_utils.AssetBrowserPanel, Panel): - bl_label = "Asset Navigation" - bl_region_type = 'TOOLS' - bl_options = {'HIDE_HEADER'} - - @classmethod - def poll(cls, context): - return ( - asset_utils.AssetBrowserPanel.poll(context) and - context.preferences.experimental.use_extended_asset_browser - ) +class ASSETBROWSER_MT_edit(AssetBrowserMenu, Menu): + bl_label = "Edit" - def draw(self, context): + def draw(self, _context): layout = self.layout - space_file = context.space_data - - col = layout.column() - - col.scale_x = 1.3 - col.scale_y = 1.3 - col.prop(space_file.params, "asset_category", expand=True) + layout.operator("asset.catalog_undo", text="Undo") + layout.operator("asset.catalog_redo", text="Redo") class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): @@ -679,42 +703,48 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): def draw(self, context): layout = self.layout + wm = context.window_manager asset_file_handle = context.asset_file_handle if asset_file_handle is None: - layout.label(text="No asset selected", icon='INFO') + layout.label(text="No active asset", icon='INFO') return asset_library_ref = context.asset_library_ref asset_lib_path = bpy.types.AssetHandle.get_full_library_path(asset_file_handle, asset_library_ref) + prefs = context.preferences + show_asset_debug_info = prefs.view.show_developer_ui and prefs.experimental.show_asset_debug_info + + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + if asset_file_handle.local_id: # If the active file is an ID, use its name directly so renaming is possible from right here. - layout.prop(asset_file_handle.local_id, "name", text="") + layout.prop(asset_file_handle.local_id, "name") - col = layout.column(align=True) - col.label(text="Asset Catalog:") - col.prop(asset_file_handle.local_id.asset_data, "catalog_id", text="UUID") - col.prop(asset_file_handle.local_id.asset_data, "catalog_simple_name", text="Simple Name") - - row = layout.row() - row.label(text="Source: Current File") + if show_asset_debug_info: + col = layout.column(align=True) + col.label(text="Asset Catalog:") + col.prop(asset_file_handle.local_id.asset_data, "catalog_id", text="UUID") + col.prop(asset_file_handle.local_id.asset_data, "catalog_simple_name", text="Simple Name") else: - layout.prop(asset_file_handle, "name", text="") - - col = layout.column(align=True) - col.enabled = False - col.label(text="Asset Catalog:") - col.prop(asset_file_handle.asset_data, "catalog_id", text="UUID") - col.prop(asset_file_handle.asset_data, "catalog_simple_name", text="Simple Name") + layout.prop(asset_file_handle, "name") - col = layout.column(align=True) # Just to reduce margin. - col.label(text="Source:") - row = col.row() - row.label(text=asset_lib_path) + if show_asset_debug_info: + col = layout.column(align=True) + col.enabled = False + col.label(text="Asset Catalog:") + col.prop(asset_file_handle.asset_data, "catalog_id", text="UUID") + col.prop(asset_file_handle.asset_data, "catalog_simple_name", text="Simple Name") + row = layout.row(align=True) + row.prop(wm, "asset_path_dummy", text="Source") row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS') + layout.prop(asset_file_handle.asset_data, "description") + layout.prop(asset_file_handle.asset_data, "author") + class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): bl_label = "Preview" @@ -726,24 +756,20 @@ class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): row = layout.row() box = row.box() box.template_icon(icon_value=active_file.preview_icon_id, scale=5.0) - if bpy.ops.ed.lib_id_load_custom_preview.poll(): - col = row.column(align=True) - col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="") - col.separator() - col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="") + + col = row.column(align=True) + col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="") + col.separator() + col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="") + col.menu("ASSETBROWSER_MT_metadata_preview_menu", icon='DOWNARROW_HLT', text="") -class ASSETBROWSER_PT_metadata_details(asset_utils.AssetMetaDataPanel, Panel): - bl_label = "Details" +class ASSETBROWSER_MT_metadata_preview_menu(bpy.types.Menu): + bl_label = "Preview" def draw(self, context): layout = self.layout - active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context) - - layout.use_property_split = True - - if active_asset: - layout.prop(active_asset, "description") + layout.operator("ed.lib_id_generate_preview_from_object", text="Render Active Object") class ASSETBROWSER_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel): @@ -782,7 +808,7 @@ class ASSETBROWSER_MT_context_menu(AssetBrowserMenu, Menu): st = context.space_data params = st.params - layout.operator("file.refresh", text="Refresh") + layout.operator("asset.library_refresh") layout.separator() @@ -818,18 +844,48 @@ classes = ( FILEBROWSER_MT_select, FILEBROWSER_MT_context_menu, ASSETBROWSER_PT_display, + ASSETBROWSER_PT_filter, ASSETBROWSER_MT_editor_menus, ASSETBROWSER_MT_view, ASSETBROWSER_MT_select, - ASSETBROWSER_PT_navigation_bar, + ASSETBROWSER_MT_edit, + ASSETBROWSER_MT_metadata_preview_menu, ASSETBROWSER_PT_metadata, ASSETBROWSER_PT_metadata_preview, - ASSETBROWSER_PT_metadata_details, ASSETBROWSER_PT_metadata_tags, ASSETBROWSER_UL_metadata_tags, ASSETBROWSER_MT_context_menu, ) +def asset_path_str_get(_self): + asset_file_handle = bpy.context.asset_file_handle + if asset_file_handle is None: + return "" + + if asset_file_handle.local_id: + return "Current File" + + asset_library_ref = bpy.context.asset_library_ref + return bpy.types.AssetHandle.get_full_library_path(asset_file_handle, asset_library_ref) + + +def register_props(): + from bpy.props import ( + StringProperty, + ) + from bpy.types import ( + WindowManager, + ) + + # Just a dummy property to be able to show a string in a label button via + # UILayout.prop(). + WindowManager.asset_path_dummy = StringProperty( + name="Asset Blend Path", + description="Full path to the Blender file containing the active asset", + get=asset_path_str_get, + ) + + if __name__ == "__main__": # only for live edit. from bpy.utils import register_class diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 612b7ba2b09..db0020b7846 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -298,6 +298,8 @@ class GRAPH_MT_key(Menu): layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR' layout.operator_context = operator_context + layout.menu("GRAPH_MT_slider", text="Slider Operators") + layout.operator("graph.clean").channels = False layout.operator("graph.clean", text="Clean Channels").channels = True layout.operator("graph.smooth") @@ -333,10 +335,32 @@ class GRAPH_MT_key_snap(Menu): layout.operator("graph.snap", text="Selection to Nearest Second").type = 'NEAREST_SECOND' layout.operator("graph.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER' layout.operator("graph.snap", text="Flatten Handles").type = 'HORIZONTAL' + layout.operator("graph.equalize_handles", text="Equalize Handles").side = 'BOTH' layout.separator() layout.operator("graph.frame_jump", text="Cursor to Selection") layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection") +class GRAPH_MT_slider(Menu): + bl_label = "Slider Operators" + + def draw(self, _context): + layout = self.layout + + layout.operator("graph.breakdown", text="Breakdown") + layout.operator("graph.blend_to_neighbor", text="Blend To Neighbor") + + +class GRAPH_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, _context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("graph.view_all") + pie.operator("graph.view_selected", icon='ZOOM_SELECTED') + pie.operator("graph.view_frame") + class GRAPH_MT_delete(Menu): bl_label = "Delete" @@ -463,11 +487,13 @@ classes = ( GRAPH_MT_key, GRAPH_MT_key_transform, GRAPH_MT_key_snap, + GRAPH_MT_slider, GRAPH_MT_delete, GRAPH_MT_context_menu, GRAPH_MT_channel_context_menu, GRAPH_MT_pivot_pie, GRAPH_MT_snap_pie, + GRAPH_MT_view_pie, GRAPH_PT_filters, ) diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 6a769b1aecc..8e82b07716c 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -591,6 +591,31 @@ class IMAGE_MT_uvs_snap_pie(Menu): ).target = 'ADJACENT_UNSELECTED' +class IMAGE_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + sima = context.space_data + show_uvedit = sima.show_uvedit + show_maskedit = sima.show_maskedit + + pie = layout.menu_pie() + pie.operator("image.view_all") + + if show_uvedit or show_maskedit: + pie.operator("image.view_selected", text="Frame Selected", icon='ZOOM_SELECTED') + pie.operator("image.view_center_cursor", text="Center View to Cursor") + else: + # Add spaces so items stay in the same position through all modes. + pie.separator() + pie.separator() + + pie.operator("image.view_zoom_ratio", text="Zoom 1:1").ratio = 1 + pie.operator("image.view_all", text="Frame All Fit").fit_view = True + + class IMAGE_HT_tool_header(Header): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOL_HEADER' @@ -1633,6 +1658,7 @@ classes = ( IMAGE_MT_mask_context_menu, IMAGE_MT_pivot_pie, IMAGE_MT_uvs_snap_pie, + IMAGE_MT_view_pie, IMAGE_HT_tool_header, IMAGE_HT_header, IMAGE_MT_editor_menus, diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index d472352084c..2db2b11a5f9 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -22,6 +22,7 @@ from bpy.types import Header, Menu, Panel from bpy.app.translations import contexts as i18n_contexts from bl_ui.space_dopesheet import ( DopesheetFilterPopoverBase, + DopesheetActionPanelBase, dopesheet_filter, ) @@ -66,6 +67,21 @@ class NLA_PT_filters(DopesheetFilterPopoverBase, Panel): DopesheetFilterPopoverBase.draw_standard_filters(context, layout) +class NLA_PT_action(DopesheetActionPanelBase, Panel): + bl_space_type = 'NLA_EDITOR' + bl_category = "Strip" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + strip = context.active_nla_strip + return strip and strip.type == 'CLIP' and strip.action + + def draw(self, context): + action = context.active_nla_strip.action + self.draw_generic_panel(context, self.layout, action) + + class NLA_MT_editor_menus(Menu): bl_idname = "NLA_MT_editor_menus" bl_label = "" @@ -247,6 +263,18 @@ class NLA_MT_snap_pie(Menu): pie.operator("nla.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER' +class NLA_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, _context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("nla.view_all") + pie.operator("nla.view_selected", icon='ZOOM_SELECTED') + pie.operator("nla.view_frame") + + class NLA_MT_context_menu(Menu): bl_label = "NLA Context Menu" @@ -300,9 +328,11 @@ classes = ( NLA_MT_add, NLA_MT_edit_transform, NLA_MT_snap_pie, + NLA_MT_view_pie, NLA_MT_context_menu, NLA_MT_channel_context_menu, NLA_PT_filters, + NLA_PT_action, ) 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 f806fc345d1..5cf3a6109d0 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -49,6 +49,7 @@ class NODE_HT_header(Header): scene = context.scene snode = context.space_data + overlay = snode.overlay snode_id = snode.id id_from = snode.id_from tool_settings = context.tool_settings @@ -205,6 +206,13 @@ class NODE_HT_header(Header): if tool_settings.snap_node_element != 'GRID': row.prop(tool_settings, "snap_target", text="") + # Overlay toggle & popover + row = layout.row(align=True) + row.prop(overlay, "show_overlays", icon='OVERLAY', text="") + sub = row.row(align=True) + sub.active = overlay.show_overlays + sub.popover(panel="NODE_PT_overlay", text="") + class NODE_MT_editor_menus(Menu): bl_idname = "NODE_MT_editor_menus" @@ -359,6 +367,17 @@ class NODE_MT_node(Menu): layout.operator("node.read_viewlayers") +class NODE_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, _context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("node.view_all") + pie.operator("node.view_selected", icon='ZOOM_SELECTED') + + class NODE_PT_active_tool(ToolActivePanelHelper, Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' @@ -680,6 +699,34 @@ class NODE_PT_quality(bpy.types.Panel): col.prop(snode, "use_auto_render") +class NODE_PT_overlay(Panel): + bl_space_type = 'NODE_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Overlays" + bl_ui_units_x = 7 + + def draw(self, context): + layout = self.layout + layout.label(text="Node Editor Overlays") + + snode = context.space_data + overlay = snode.overlay + + layout.active = overlay.show_overlays + + col = layout.column() + col.prop(overlay, "show_wire_color", text="Wire Colors") + + col.separator() + + col.prop(overlay, "show_context_path", text="Context Path") + col.prop(snode, "show_annotation", text="Annotations") + + if snode.tree_type == 'GeometryNodeTree': + col.separator() + col.prop(overlay, "show_timing", text="Timings") + + class NODE_UL_interface_sockets(bpy.types.UIList): def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index): socket = item @@ -755,9 +802,17 @@ class NodeTreeInterfacePanel: if tree.type == 'GEOMETRY': layout.prop(active_socket, "description") field_socket_prefixes = { - "NodeSocketInt", "NodeSocketColor", "NodeSocketVector", "NodeSocketBool", "NodeSocketFloat"} - is_field_type = any(active_socket.bl_socket_idname.startswith(prefix) for prefix in field_socket_prefixes) - if in_out == "OUT" and is_field_type: + "NodeSocketInt", + "NodeSocketColor", + "NodeSocketVector", + "NodeSocketBool", + "NodeSocketFloat", + } + is_field_type = any( + active_socket.bl_socket_idname.startswith(prefix) + for prefix in field_socket_prefixes + ) + if in_out == 'OUT' and is_field_type: layout.prop(active_socket, "attribute_domain") active_socket.draw(context, layout) @@ -838,6 +893,7 @@ classes = ( NODE_MT_node, NODE_MT_node_color_context_menu, NODE_MT_context_menu, + NODE_MT_view_pie, NODE_PT_material_slots, NODE_PT_node_color_presets, NODE_PT_active_node_generic, @@ -848,6 +904,7 @@ classes = ( NODE_PT_backdrop, NODE_PT_quality, NODE_PT_annotation, + NODE_PT_overlay, NODE_UL_interface_sockets, NODE_PT_node_tree_interface_inputs, NODE_PT_node_tree_interface_outputs, diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 3d18160d90f..d85538a37e0 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -142,6 +142,17 @@ class OUTLINER_MT_context_menu_view(Menu): layout.operator("outliner.show_one_level", text="Hide One Level").open = False +class OUTLINER_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("outliner.show_hierarchy") + pie.operator("outliner.show_active", icon='ZOOM_SELECTED') + + class OUTLINER_MT_edit_datablocks(Menu): bl_label = "Edit" @@ -313,10 +324,6 @@ class OUTLINER_MT_object(Menu): class OUTLINER_MT_asset(Menu): bl_label = "Assets" - @classmethod - def poll(cls, context): - return context.preferences.experimental.use_extended_asset_browser - def draw(self, context): layout = self.layout @@ -475,6 +482,7 @@ classes = ( OUTLINER_MT_asset, OUTLINER_MT_context_menu, OUTLINER_MT_context_menu_view, + OUTLINER_MT_view_pie, OUTLINER_PT_filter, ) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 7b102604587..6035170f9df 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -37,6 +37,14 @@ from bl_ui.space_toolsystem_common import ( from rna_prop_ui import PropertyPanel +def _space_view_types(st): + view_type = st.view_type + return ( + view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}, + view_type == 'PREVIEW', + ) + + def selected_sequences_len(context): selected_sequences = getattr(context, "selected_sequences", None) if selected_sequences is None: @@ -46,44 +54,85 @@ def selected_sequences_len(context): def draw_color_balance(layout, color_balance): + layout.prop(color_balance, "correction_method") + layout.use_property_split = False flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - col = flow.column() - - box = col.box() - split = box.split(factor=0.35) - col = split.column(align=True) - col.label(text="Lift:") - col.separator() - col.separator() - col.prop(color_balance, "lift", text="") - col.prop(color_balance, "invert_lift", text="Invert", icon='ARROW_LEFTRIGHT') - split.template_color_picker(color_balance, "lift", value_slider=True, cubic=True) - - col = flow.column() - - box = col.box() - split = box.split(factor=0.35) - col = split.column(align=True) - col.label(text="Gamma:") - col.separator() - col.separator() - col.prop(color_balance, "gamma", text="") - col.prop(color_balance, "invert_gamma", text="Invert", icon='ARROW_LEFTRIGHT') - split.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True) - - col = flow.column() - - box = col.box() - split = box.split(factor=0.35) - col = split.column(align=True) - col.label(text="Gain:") - col.separator() - col.separator() - col.prop(color_balance, "gain", text="") - col.prop(color_balance, "invert_gain", text="Invert", icon='ARROW_LEFTRIGHT') - split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True) + + if color_balance.correction_method == 'LIFT_GAMMA_GAIN': + col = flow.column() + + box = col.box() + split = box.split(factor=0.35) + col = split.column(align=True) + col.label(text="Lift:") + col.separator() + col.separator() + col.prop(color_balance, "lift", text="") + col.prop(color_balance, "invert_lift", text="Invert", icon='ARROW_LEFTRIGHT') + split.template_color_picker(color_balance, "lift", value_slider=True, cubic=True) + + col = flow.column() + + box = col.box() + split = box.split(factor=0.35) + col = split.column(align=True) + col.label(text="Gamma:") + col.separator() + col.separator() + col.prop(color_balance, "gamma", text="") + col.prop(color_balance, "invert_gamma", text="Invert", icon='ARROW_LEFTRIGHT') + split.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True) + + col = flow.column() + + box = col.box() + split = box.split(factor=0.35) + col = split.column(align=True) + col.label(text="Gain:") + col.separator() + col.separator() + col.prop(color_balance, "gain", text="") + col.prop(color_balance, "invert_gain", text="Invert", icon='ARROW_LEFTRIGHT') + split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True) + + elif color_balance.correction_method == 'OFFSET_POWER_SLOPE': + col = flow.column() + + box = col.box() + split = box.split(factor=0.35) + col = split.column(align=True) + col.label(text="Offset:") + col.separator() + col.separator() + col.prop(color_balance, "offset", text="") + col.prop(color_balance, "invert_offset", text="Invert", icon='ARROW_LEFTRIGHT') + split.template_color_picker(color_balance, "offset", value_slider=True, cubic=True) + + col = flow.column() + + box = col.box() + split = box.split(factor=0.35) + col = split.column(align=True) + col.label(text="Power:") + col.separator() + col.separator() + col.prop(color_balance, "power", text="") + col.prop(color_balance, "invert_power", text="Invert", icon='ARROW_LEFTRIGHT') + split.template_color_picker(color_balance, "power", value_slider=True, cubic=True) + + col = flow.column() + + box = col.box() + split = box.split(factor=0.35) + col = split.column(align=True) + col.label(text="Slope:") + col.separator() + col.separator() + col.prop(color_balance, "slope", text="") + col.prop(color_balance, "invert_slope", text="Invert", icon='ARROW_LEFTRIGHT') + split.template_color_picker(color_balance, "slope", value_slider=True, cubic=True) class SEQUENCER_PT_active_tool(ToolActivePanelHelper, Panel): @@ -128,8 +177,6 @@ class SEQUENCER_HT_header(Header): st = context.space_data - show_region_tool_header = st.show_region_tool_header - layout.template_header() layout.prop(st, "view_type", text="") @@ -148,8 +195,8 @@ class SEQUENCER_HT_header(Header): if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}: row = layout.row(align=True) row.prop(sequencer_tool_settings, "overlap_mode", text="") - row = layout.row(align=True) - row.prop(sequencer_tool_settings, "pivot_point", text="", icon_only=True) + + if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}: row = layout.row(align=True) row.prop(tool_settings, "use_snap_sequencer", text="") sub = row.row(align=True) @@ -160,11 +207,22 @@ class SEQUENCER_HT_header(Header): layout.prop(st, "display_mode", text="", icon_only=True) layout.prop(st, "preview_channels", text="", icon_only=True) + # Gizmo toggle & popover. + row = layout.row(align=True) + # FIXME: place-holder icon. + row.prop(st, "show_gizmo", text="", toggle=True, icon='GIZMO') + sub = row.row(align=True) + sub.active = st.show_gizmo + sub.popover( + panel="SEQUENCER_PT_gizmo_display", + text="", + ) + row = layout.row(align=True) - row.prop(st, "show_strip_overlay", text="", icon='OVERLAY') + row.prop(st, "show_overlays", text="", icon='OVERLAY') sub = row.row(align=True) sub.popover(panel="SEQUENCER_PT_overlay", text="") - sub.active = st.show_strip_overlay + sub.active = st.show_overlays class SEQUENCER_MT_editor_menus(Menu): @@ -174,15 +232,43 @@ class SEQUENCER_MT_editor_menus(Menu): def draw(self, context): layout = self.layout st = context.space_data + has_sequencer, _has_preview = _space_view_types(st) layout.menu("SEQUENCER_MT_view") + layout.menu("SEQUENCER_MT_select") - if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}: - layout.menu("SEQUENCER_MT_select") + if has_sequencer: if st.show_markers: layout.menu("SEQUENCER_MT_marker") layout.menu("SEQUENCER_MT_add") - layout.menu("SEQUENCER_MT_strip") + + layout.menu("SEQUENCER_MT_strip") + + if st.view_type in {'SEQUENCER', 'PREVIEW'}: + layout.menu("SEQUENCER_MT_image") + + +class SEQUENCER_PT_gizmo_display(Panel): + bl_space_type = 'SEQUENCE_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Gizmos" + bl_ui_units_x = 8 + + def draw(self, context): + layout = self.layout + + scene = context.scene + st = context.space_data + + col = layout.column() + col.label(text="Viewport Gizmos") + col.separator() + + col.active = st.show_gizmo + colsub = col.column() + colsub.prop(st, "show_gizmo_navigate", text="Navigate") + colsub.prop(st, "show_gizmo_tool", text="Active Tools") + # colsub.prop(st, "show_gizmo_context", text="Active Object") # Currently unused. class SEQUENCER_PT_overlay(Panel): @@ -212,9 +298,10 @@ class SEQUENCER_PT_preview_overlay(Panel): overlay_settings = st.preview_overlay layout = self.layout - layout.active = st.show_strip_overlay + layout.active = st.show_overlays layout.prop(overlay_settings, "show_image_outline") - layout.prop(ed, "show_overlay", text="Frame Overlay") + layout.prop(overlay_settings, "show_cursor") + layout.prop(ed, "show_overlay_frame", text="Frame Overlay") layout.prop(overlay_settings, "show_safe_areas", text="Safe Areas") layout.prop(overlay_settings, "show_metadata", text="Metadata") layout.prop(overlay_settings, "show_annotation", text="Annotations") @@ -236,7 +323,7 @@ class SEQUENCER_PT_sequencer_overlay(Panel): overlay_settings = st.timeline_overlay layout = self.layout - layout.active = st.show_strip_overlay + layout.active = st.show_overlays layout.prop(overlay_settings, "show_strip_name", text="Name") layout.prop(overlay_settings, "show_strip_source", text="Source") @@ -342,6 +429,7 @@ class SEQUENCER_MT_view(Menu): # wm_keymap_item_find_props() (see T32595). layout.operator_context = 'INVOKE_REGION_PREVIEW' layout.prop(st, "show_region_ui") + layout.prop(st, "show_region_tool_header") layout.prop(st, "show_region_toolbar") layout.operator_context = 'INVOKE_DEFAULT' @@ -480,8 +568,10 @@ class SEQUENCER_MT_select_linked(Menu): class SEQUENCER_MT_select(Menu): bl_label = "Select" - def draw(self, _context): + def draw(self, context): layout = self.layout + st = context.space_data + has_sequencer, has_preview = _space_view_types(st) layout.operator("sequencer.select_all", text="All").action = 'SELECT' layout.operator("sequencer.select_all", text="None").action = 'DESELECT' @@ -490,17 +580,20 @@ class SEQUENCER_MT_select(Menu): layout.separator() layout.operator("sequencer.select_box", text="Box Select") - props = layout.operator("sequencer.select_box", text="Box Select (Include Handles)") - props.include_handles = True + if has_sequencer: + props = layout.operator("sequencer.select_box", text="Box Select (Include Handles)") + props.include_handles = True layout.separator() - layout.operator_menu_enum("sequencer.select_side_of_frame", "side", text="Side of Frame...") - layout.menu("SEQUENCER_MT_select_handle", text="Handle") - layout.menu("SEQUENCER_MT_select_channel", text="Channel") - layout.menu("SEQUENCER_MT_select_linked", text="Linked") + if has_sequencer: + layout.operator_menu_enum("sequencer.select_side_of_frame", "side", text="Side of Frame...") + layout.menu("SEQUENCER_MT_select_handle", text="Handle") + layout.menu("SEQUENCER_MT_select_channel", text="Channel") + layout.menu("SEQUENCER_MT_select_linked", text="Linked") + + layout.separator() - layout.separator() layout.operator_menu_enum("sequencer.select_grouped", "type", text="Grouped") @@ -708,43 +801,42 @@ class SEQUENCER_MT_add_effect(Menu): col.enabled = selected_sequences_len(context) != 0 -class SEQUENCER_MT_strip_image_transform(Menu): - bl_label = "Image Transform" - - def draw(self, _context): - layout = self.layout - - layout.operator("sequencer.strip_transform_fit", text="Scale To Fit").fit_method = 'FIT' - layout.operator("sequencer.strip_transform_fit", text="Scale to Fill").fit_method = 'FILL' - layout.operator("sequencer.strip_transform_fit", text="Stretch To Fill").fit_method = 'STRETCH' - layout.separator() - - layout.operator("sequencer.strip_transform_clear", text="Clear Position").property = 'POSITION' - layout.operator("sequencer.strip_transform_clear", text="Clear Scale").property = 'SCALE' - layout.operator("sequencer.strip_transform_clear", text="Clear Rotation").property = 'ROTATION' - layout.operator("sequencer.strip_transform_clear", text="Clear All").property = 'ALL' - - class SEQUENCER_MT_strip_transform(Menu): bl_label = "Transform" - def draw(self, _context): + def draw(self, context): layout = self.layout + st = context.space_data + has_sequencer, has_preview = _space_view_types(st) - layout.operator("transform.seq_slide", text="Move") - layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND' - layout.operator("sequencer.slip", text="Slip Strip Contents") + if has_preview: + layout.operator_context = 'INVOKE_REGION_PREVIEW' + else: + layout.operator_context = 'INVOKE_REGION_WIN' - layout.separator() - layout.operator("sequencer.snap") - layout.operator("sequencer.offset_clear") + if has_preview: + layout.operator("transform.translate", text="Move") + layout.operator("transform.rotate", text="Rotate") + layout.operator("transform.resize", text="Scale") + else: + layout.operator("transform.seq_slide", text="Move") + layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND' + layout.operator("sequencer.slip", text="Slip Strip Contents") - layout.separator() - layout.operator_menu_enum("sequencer.swap", "side") + # TODO (for preview) + if has_sequencer: + layout.separator() + layout.operator("sequencer.snap") + layout.operator("sequencer.offset_clear") - layout.separator() - layout.operator("sequencer.gap_remove").all = False - layout.operator("sequencer.gap_insert") + layout.separator() + + if has_sequencer: + layout.operator_menu_enum("sequencer.swap", "side") + + layout.separator() + layout.operator("sequencer.gap_remove").all = False + layout.operator("sequencer.gap_insert") class SEQUENCER_MT_strip_input(Menu): @@ -814,69 +906,123 @@ class SEQUENCER_MT_strip(Menu): def draw(self, context): layout = self.layout + st = context.space_data + has_sequencer, has_preview = _space_view_types(st) - layout.operator_context = 'INVOKE_REGION_WIN' - - layout.separator() layout.menu("SEQUENCER_MT_strip_transform") - layout.menu("SEQUENCER_MT_strip_image_transform") - layout.separator() - layout.operator("sequencer.split", text="Split").type = 'SOFT' - layout.operator("sequencer.split", text="Hold Split").type = 'HARD' - layout.separator() - layout.operator("sequencer.copy", text="Copy") - layout.operator("sequencer.paste", text="Paste") - layout.operator("sequencer.duplicate_move") + if has_sequencer: + + layout.operator("sequencer.split", text="Split").type = 'SOFT' + layout.operator("sequencer.split", text="Hold Split").type = 'HARD' + layout.separator() + + if has_sequencer: + layout.operator("sequencer.copy", text="Copy") + layout.operator("sequencer.paste", text="Paste") + layout.operator("sequencer.duplicate_move") + layout.operator("sequencer.delete", text="Delete") strip = context.active_sequence_strip - if strip: - strip_type = strip.type + if has_sequencer: + if strip: + strip_type = strip.type - if strip_type != 'SOUND': - layout.separator() - layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier") - layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection") + if strip_type != 'SOUND': + layout.separator() + layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier") + layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection") + + if strip_type in { + 'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', + 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW', + 'TRANSFORM', 'COLOR', 'SPEED', 'MULTICAM', 'ADJUSTMENT', + 'GAUSSIAN_BLUR', + }: + layout.separator() + layout.menu("SEQUENCER_MT_strip_effect") + elif strip_type == 'MOVIE': + layout.separator() + layout.menu("SEQUENCER_MT_strip_movie") + elif strip_type == 'IMAGE': + layout.separator() + layout.operator("sequencer.rendersize") + layout.operator("sequencer.images_separate") + elif strip_type == 'TEXT': + layout.separator() + layout.menu("SEQUENCER_MT_strip_effect") + elif strip_type == 'META': + layout.separator() + layout.operator("sequencer.meta_make") + layout.operator("sequencer.meta_separate") + layout.operator("sequencer.meta_toggle", text="Toggle Meta") + if strip_type != 'META': + layout.separator() + layout.operator("sequencer.meta_make") + layout.operator("sequencer.meta_toggle", text="Toggle Meta") - if strip_type in { - 'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', - 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW', - 'TRANSFORM', 'COLOR', 'SPEED', 'MULTICAM', 'ADJUSTMENT', - 'GAUSSIAN_BLUR', - }: - layout.separator() - layout.menu("SEQUENCER_MT_strip_effect") - elif strip_type == 'MOVIE': - layout.separator() - layout.menu("SEQUENCER_MT_strip_movie") - elif strip_type == 'IMAGE': - layout.separator() - layout.operator("sequencer.rendersize") - layout.operator("sequencer.images_separate") - elif strip_type == 'TEXT': - layout.separator() - layout.menu("SEQUENCER_MT_strip_effect") - elif strip_type == 'META': - layout.separator() - layout.operator("sequencer.meta_make") - layout.operator("sequencer.meta_separate") - layout.operator("sequencer.meta_toggle", text="Toggle Meta") - if strip_type != 'META': - layout.separator() - layout.operator("sequencer.meta_make") - layout.operator("sequencer.meta_toggle", text="Toggle Meta") + if has_sequencer: + layout.separator() + layout.menu("SEQUENCER_MT_color_tag_picker") - layout.separator() - layout.menu("SEQUENCER_MT_color_tag_picker") + layout.separator() + layout.menu("SEQUENCER_MT_strip_lock_mute") - layout.separator() - layout.menu("SEQUENCER_MT_strip_lock_mute") + layout.separator() + layout.menu("SEQUENCER_MT_strip_input") - layout.separator() - layout.menu("SEQUENCER_MT_strip_input") + +class SEQUENCER_MT_image(Menu): + bl_label = "Image" + + def draw(self, context): + layout = self.layout + st = context.space_data + + if st.view_type == {'PREVIEW', 'SEQUENCER_PREVIEW'}: + layout.menu("SEQUENCER_MT_image_transform") + + layout.menu("SEQUENCER_MT_image_clear") + layout.menu("SEQUENCER_MT_image_apply") + + +class SEQUENCER_MT_image_transform(Menu): + bl_label = "Transform" + + def draw(self, _context): + layout = self.layout + + layout.operator_context = 'INVOKE_REGION_PREVIEW' + + layout.operator("transform.translate") + layout.operator("transform.rotate") + layout.operator("transform.resize", text="Scale") + + +class SEQUENCER_MT_image_clear(Menu): + bl_label = "Clear" + + def draw(self, _context): + layout = self.layout + + layout.operator("sequencer.strip_transform_clear", text="Position").property = 'POSITION' + layout.operator("sequencer.strip_transform_clear", text="Scale").property = 'SCALE' + layout.operator("sequencer.strip_transform_clear", text="Rotation").property = 'ROTATION' + layout.operator("sequencer.strip_transform_clear", text="All Transforms").property = 'ALL' + + +class SEQUENCER_MT_image_apply(Menu): + bl_label = "Apply" + + def draw(self, _context): + layout = self.layout + + layout.operator("sequencer.strip_transform_fit", text="Scale To Fit").fit_method = 'FIT' + layout.operator("sequencer.strip_transform_fit", text="Scale to Fill").fit_method = 'FILL' + layout.operator("sequencer.strip_transform_fit", text="Stretch To Fill").fit_method = 'STRETCH' class SEQUENCER_MT_context_menu(Menu): @@ -976,6 +1122,68 @@ class SEQUENCER_MT_context_menu(Menu): layout.menu("SEQUENCER_MT_strip_lock_mute") +class SEQUENCER_MT_preview_context_menu(Menu): + bl_label = "Sequencer Preview Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_REGION_WIN' + + props = layout.operator("wm.call_panel", text="Rename...") + props.name = "TOPBAR_PT_name" + props.keep_open = False + + # TODO: support in preview. + # layout.operator("sequencer.delete", text="Delete") + + strip = context.active_sequence_strip + + if strip: + pass + + +class SEQUENCER_MT_pivot_pie(Menu): + bl_label = "Pivot Point" + + def draw(self, context): + layout = self.layout + pie = layout.menu_pie() + + tool_settings = context.tool_settings + sequencer_tool_settings = context.tool_settings.sequencer_tool_settings + + pie.prop_enum(sequencer_tool_settings, "pivot_point", value='CENTER') + pie.prop_enum(sequencer_tool_settings, "pivot_point", value='CURSOR') + pie.prop_enum(sequencer_tool_settings, "pivot_point", value='INDIVIDUAL_ORIGINS') + pie.prop_enum(sequencer_tool_settings, "pivot_point", value='MEDIAN') + + +class SEQUENCER_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, _context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("sequencer.view_all") + pie.operator("sequencer.view_selected", text="Frame Selected", icon='ZOOM_SELECTED') + + +class SEQUENCER_MT_preview_view_pie(Menu): + bl_label = "View" + + def draw(self, _context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator_context = 'INVOKE_REGION_PREVIEW' + pie.operator("sequencer.view_all_preview") + pie.operator("sequencer.view_selected", text="Frame Selected", icon='ZOOM_SELECTED') + pie.separator() + pie.operator("sequencer.view_zoom_ratio", text="Zoom 1:1").ratio = 1 + + class SequencerButtonsPanel: bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' @@ -1003,35 +1211,38 @@ class SequencerButtonsPanel_Output: return cls.has_preview(context) -class SEQUENCER_PT_color_tag_picker(Panel): - bl_label = "Color Tag" +class SequencerColorTagPicker: bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' - bl_category = "Strip" - bl_options = {'HIDE_HEADER', 'INSTANCED'} + + @staticmethod + def has_sequencer(context): + return (context.space_data.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}) @classmethod def poll(cls, context): - return context.active_sequence_strip is not None + return cls.has_sequencer(context) and context.active_sequence_strip is not None - def draw(self, context): + +class SEQUENCER_PT_color_tag_picker(SequencerColorTagPicker, Panel): + bl_label = "Color Tag" + bl_category = "Strip" + bl_options = {'HIDE_HEADER', 'INSTANCED'} + + def draw(self, _context): layout = self.layout row = layout.row(align=True) - row.operator("sequencer.strip_color_tag_set", icon="X").color = 'NONE' + row.operator("sequencer.strip_color_tag_set", icon='X').color = 'NONE' for i in range(1, 10): icon = 'SEQUENCE_COLOR_%02d' % i row.operator("sequencer.strip_color_tag_set", icon=icon).color = 'COLOR_%02d' % i -class SEQUENCER_MT_color_tag_picker(Menu): +class SEQUENCER_MT_color_tag_picker(SequencerColorTagPicker, Menu): bl_label = "Set Color Tag" - @classmethod - def poll(cls, context): - return context.active_sequence_strip is not None - - def draw(self, context): + def draw(self, _context): layout = self.layout row = layout.row(align=True) @@ -1195,15 +1406,15 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): elif strip_type == 'SPEED': col = layout.column(align=True) col.prop(strip, "speed_control", text="Speed Control") - if strip.speed_control == "MULTIPLY": + if strip.speed_control == 'MULTIPLY': col.prop(strip, "speed_factor", text=" ") - elif strip.speed_control == "LENGTH": + elif strip.speed_control == 'LENGTH': col.prop(strip, "speed_length", text=" ") - elif strip.speed_control == "FRAME_NUMBER": + elif strip.speed_control == 'FRAME_NUMBER': col.prop(strip, "speed_frame_number", text=" ") row = layout.row(align=True) - row.enabled = strip.speed_control != "STRETCH" + row.enabled = strip.speed_control != 'STRETCH' row = layout.row(align=True, heading="Interpolation") row.prop(strip, "use_frame_interpolate", text="") @@ -1710,7 +1921,6 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel): def draw(self, context): layout = self.layout - layout.use_property_split = False st = context.space_data overlay_settings = st.timeline_overlay @@ -1720,16 +1930,7 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel): layout.active = not strip.mute if sound is not None: - col = layout.column() - - split = col.split(factor=0.4) - split.label(text="") - split.prop(sound, "use_mono") - if overlay_settings.waveform_display_type == 'DEFAULT_WAVEFORMS': - split = col.split(factor=0.4) - split.label(text="") - split.prop(strip, "show_waveform") - + layout.use_property_split = True col = layout.column() split = col.split(factor=0.4) @@ -1742,15 +1943,37 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel): split.label(text="Pitch") split.prop(strip, "pitch", text="") + audio_channels = context.scene.render.ffmpeg.audio_channels + pan_enabled = sound.use_mono and audio_channels != 'MONO' + pan_text = "%.2f°" % (strip.pan * 90) + split = col.split(factor=0.4) split.alignment = 'RIGHT' split.label(text="Pan") - audio_channels = context.scene.render.ffmpeg.audio_channels - pan_text = "" + split.prop(strip, "pan", text="") + split.enabled = pan_enabled + if audio_channels != 'MONO' and audio_channels != 'STEREO': - pan_text = "%.2f°" % (strip.pan * 90) - split.prop(strip, "pan", text=pan_text) - split.enabled = sound.use_mono and audio_channels != 'MONO' + split = col.split(factor=0.4) + split.alignment = 'RIGHT' + split.label(text="Pan Angle") + split.enabled = pan_enabled + subsplit = split.row() + subsplit.alignment = 'CENTER' + subsplit.label(text=pan_text) + subsplit.label(text=" ") # Compensate for no decorate. + subsplit.enabled = pan_enabled + + layout.use_property_split = False + col = layout.column() + + split = col.split(factor=0.4) + split.label(text="") + split.prop(sound, "use_mono") + if overlay_settings.waveform_display_type == 'DEFAULT_WAVEFORMS': + split = col.split(factor=0.4) + split.label(text="") + split.prop(strip, "show_waveform") @@ -2104,6 +2327,22 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel): col.prop(st, "show_separate_color") +class SEQUENCER_PT_view_cursor(SequencerButtonsPanel_Output, Panel): + bl_category = "View" + bl_label = "2D Cursor" + + def draw(self, context): + layout = self.layout + + st = context.space_data + + layout.use_property_split = True + layout.use_property_decorate = False + + col = layout.column() + col.prop(st, "cursor_location", text="Location") + + class SEQUENCER_PT_frame_overlay(SequencerButtonsPanel_Output, Panel): bl_label = "Frame Overlay" bl_category = "View" @@ -2119,7 +2358,7 @@ class SEQUENCER_PT_frame_overlay(SequencerButtonsPanel_Output, Panel): scene = context.scene ed = scene.sequence_editor - self.layout.prop(ed, "show_overlay", text="") + self.layout.prop(ed, "show_overlay_frame", text="") def draw(self, context): layout = self.layout @@ -2135,12 +2374,12 @@ class SEQUENCER_PT_frame_overlay(SequencerButtonsPanel_Output, Panel): scene = context.scene ed = scene.sequence_editor - layout.active = ed.show_overlay + layout.active = ed.show_overlay_frame col = layout.column() col.prop(ed, "overlay_frame", text="Frame Offset") - col.prop(st, "overlay_type") - col.prop(ed, "use_overlay_lock") + col.prop(st, "overlay_frame_type") + col.prop(ed, "use_overlay_frame_lock") class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel): @@ -2376,18 +2615,26 @@ classes = ( SEQUENCER_MT_strip_effect, SEQUENCER_MT_strip_movie, SEQUENCER_MT_strip, - SEQUENCER_MT_strip_image_transform, SEQUENCER_MT_strip_transform, SEQUENCER_MT_strip_input, SEQUENCER_MT_strip_lock_mute, + SEQUENCER_MT_image, + SEQUENCER_MT_image_transform, + SEQUENCER_MT_image_clear, + SEQUENCER_MT_image_apply, SEQUENCER_MT_color_tag_picker, SEQUENCER_MT_context_menu, + SEQUENCER_MT_preview_context_menu, + SEQUENCER_MT_pivot_pie, + SEQUENCER_MT_view_pie, + SEQUENCER_MT_preview_view_pie, SEQUENCER_PT_color_tag_picker, SEQUENCER_PT_active_tool, SEQUENCER_PT_strip, + SEQUENCER_PT_gizmo_display, SEQUENCER_PT_overlay, SEQUENCER_PT_preview_overlay, SEQUENCER_PT_sequencer_overlay, @@ -2418,6 +2665,7 @@ classes = ( SEQUENCER_PT_custom_props, SEQUENCER_PT_view, + SEQUENCER_PT_view_cursor, SEQUENCER_PT_frame_overlay, SEQUENCER_PT_view_safe_areas, SEQUENCER_PT_view_safe_areas_center_cut, diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index 4a598d0aa63..c4dabb5b5bc 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -64,7 +64,7 @@ from collections import namedtuple ToolDef = namedtuple( "ToolDef", ( - # Unique tool name (withing space & mode context). + # Unique tool name (within space & mode context). "idname", # The name to display in the interface. "label", @@ -106,7 +106,7 @@ ToolDef = namedtuple( # Keep this functionality since it's likely useful for add-on key-maps. # # Warning: currently 'from_dict' this is a list of one item, - # so internally we can swap the key-map function for the key-map it's self. + # so internally we can swap the key-map function for the key-map itself. # This isn't very nice and may change, tool definitions shouldn't care about this. "keymap", # Optional data-block associated with this tool. @@ -190,7 +190,7 @@ class ToolActivePanelHelper: ToolSelectPanelHelper.draw_active_tool_header( context, layout.column(), - show_tool_icon=True, + show_tool_icon_always=True, tool_key=ToolSelectPanelHelper._tool_key_from_context(context, space_type=self.bl_space_type), ) @@ -202,13 +202,41 @@ class ToolSelectPanelHelper: - 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. + Generator (context_mode, tools) tuple pairs for all tools defined. - tools_from_context(context, mode=None): - Returns tools available in this context. + A generator for all tools available in the current context. - Each tool is a 'ToolDef' or None for a separator in the toolbar, use ``None``. + Tool Sequence Structure + ======================= + + Sequences of tools as returned by tools_all() and tools_from_context() are comprised of: + + - A `ToolDef` instance (representing a tool that can be activated). + - None (a visual separator in the tool list). + - A tuple of `ToolDef` or None values + (representing a group of tools that can be selected between using a click-drag action). + Note that only a single level of nesting is supported (groups cannot contain sub-groups). + - A callable which takes a single context argument and returns a tuple of values described above. + When the context is None, all potential tools must be returned. """ + @classmethod + def tools_all(cls): + """ + Return all tools for this toolbar, this must include all available tools ignoring the current context. + The value is must be a sequence of (mode, tool_list) pairs, where mode may be object-mode edit-mode etc. + The mode may be None for tool-bars that don't make use of sub-modes. + """ + raise Exception("Sub-class %r must implement this method!" % cls) + + @classmethod + def tools_from_context(cls, context, mode=None): + """ + Return all tools for the current context, + this result is used at run-time and may filter out tools to display. + """ + raise Exception("Sub-class %r must implement this method!" % cls) + @staticmethod def _tool_class_from_space_type(space_type): return next( @@ -766,7 +794,7 @@ class ToolSelectPanelHelper: def draw_active_tool_header( context, layout, *, - show_tool_icon=False, + show_tool_icon_always=False, tool_key=None, ): if tool_key is None: @@ -783,11 +811,15 @@ class ToolSelectPanelHelper: return None # Note: we could show 'item.text' here but it makes the layout jitter when switching tools. # Add some spacing since the icon is currently assuming regular small icon size. - if show_tool_icon: + if show_tool_icon_always: layout.label(text=" " + item.label, icon_value=icon_value) layout.separator() else: - layout.label(text=item.label) + if context.space_data.show_region_toolbar: + layout.template_icon(icon_value=0, scale=0.5) + else: + layout.template_icon(icon_value=icon_value, scale=0.5) + layout.separator() draw_settings = item.draw_settings if draw_settings is not None: diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 5970d6fdf2b..889155f1858 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -185,23 +185,18 @@ class _defs_annotate: tool_settings = context.tool_settings if space_type == 'VIEW_3D': - layout.separator() - row = layout.row(align=True) row.prop(tool_settings, "annotation_stroke_placement_view3d", text="Placement") if tool_settings.gpencil_stroke_placement_view3d == 'CURSOR': row.prop(tool_settings.gpencil_sculpt, "lockaxis") elif tool_settings.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}: row.prop(tool_settings, "use_gpencil_stroke_endpoints") - elif space_type in {'IMAGE_EDITOR', 'NODE_EDITOR', 'SEQUENCE_EDITOR', 'CLIP_EDITOR'}: - layout.separator() + elif space_type in {'IMAGE_EDITOR', 'NODE_EDITOR', 'SEQUENCE_EDITOR', 'CLIP_EDITOR'}: row = layout.row(align=True) row.prop(tool_settings, "annotation_stroke_placement_view2d", text="Placement") if tool.idname == "builtin.annotate_line": - layout.separator() - props = tool.operator_properties("gpencil.annotate") if region_type == 'TOOL_HEADER': row = layout.row() @@ -223,7 +218,6 @@ class _defs_annotate: subrow.prop(props, "stabilizer_radius", text="Radius", slider=True) subrow.prop(props, "stabilizer_factor", text="Factor", slider=True) else: - layout.separator() layout.prop(props, "use_stabilizer", text="Stabilize Stroke") col = layout.column(align=False) col.active = props.use_stabilizer @@ -2435,12 +2429,26 @@ class _defs_node_edit: icon="ops.node.links_cut", widget=None, keymap="Node Tool: Links Cut", + options={'KEYMAP_FALLBACK'}, ) class _defs_sequencer_generic: @ToolDef.from_fn + def cursor(): + return dict( + idname="builtin.cursor", + label="Cursor", + description=( + "Set the cursor location, drag to transform" + ), + icon="ops.generic.cursor", + keymap="Sequencer Tool: Cursor", + options={'KEYMAP_FALLBACK'}, + ) + + @ToolDef.from_fn def blade(): def draw_settings(_context, layout, tool): props = tool.operator_properties("sequencer.split") @@ -2455,6 +2463,7 @@ class _defs_sequencer_generic: widget=None, keymap="Sequencer Tool: Blade", draw_settings=draw_settings, + options={'KEYMAP_FALLBACK'}, ) @ToolDef.from_fn @@ -2502,16 +2511,28 @@ class _defs_sequencer_generic: keymap="Sequencer Tool: Scale", ) + @ToolDef.from_fn + def transform(): + return dict( + idname="builtin.transform", + label="Transform", + description=( + "Supports any combination of grab, rotate, and scale at once" + ), + icon="ops.transform.transform", + widget="SEQUENCER_GGT_gizmo2d", + # No keymap default action, only for gizmo! + ) class _defs_sequencer_select: @ToolDef.from_fn def select(): return dict( idname="builtin.select", - label="Select", + label="Tweak", icon="ops.generic.select", widget=None, - keymap="Sequencer Tool: Select", + keymap="Sequencer Tool: Tweak", ) @ToolDef.from_fn @@ -2562,7 +2583,8 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel): def tools_all(cls): yield from cls._tools.items() - # for reuse + # Private tool lists for convenient reuse in `_tools`. + _tools_transform = ( _defs_image_uv_transform.translate, _defs_image_uv_transform.rotate, @@ -2588,6 +2610,9 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel): ), ) + # Private tools dictionary, store data to implement `tools_all` & `tools_from_context`. + # The keys match image spaces modes: 'context.space_data.mode'. + # The values represent the tools, see `ToolSelectPanelHelper` for details. _tools = { None: [ # for all modes @@ -2653,6 +2678,8 @@ class NODE_PT_tools_active(ToolSelectPanelHelper, Panel): def tools_all(cls): yield from cls._tools.items() + # Private tool lists for convenient reuse in `_tools`. + _tools_select = ( ( _defs_node_select.select, @@ -2671,6 +2698,9 @@ class NODE_PT_tools_active(ToolSelectPanelHelper, Panel): ), ) + # Private tools dictionary, store data to implement `tools_all` & `tools_from_context`. + # The keys is always `None` since nodes don't use use modes to access different tools. + # The values represent the tools, see `ToolSelectPanelHelper` for details. _tools = { None: [ *_tools_select, @@ -2709,7 +2739,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): def tools_all(cls): yield from cls._tools.items() - # for reuse + # Private tool lists for convenient reuse in `_tools`. + _tools_transform = ( _defs_transform.translate, _defs_transform.rotate, @@ -2765,6 +2796,9 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): _defs_view3d_generic.ruler, ) + # Private tools dictionary, store data to implement `tools_all` & `tools_from_context`. + # The keys match object-modes from: 'context.mode'. + # The values represent the tools, see `ToolSelectPanelHelper` for details. _tools = { None: [ # Don't use this! because of paint modes. @@ -2967,7 +3001,11 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ), None, lambda context: ( - (_defs_view3d_generic.cursor,) + ( + _defs_view3d_generic.cursor, + None, + *VIEW3D_PT_tools_active._tools_transform, + ) if context is None or context.pose_object else () ), @@ -3074,6 +3112,8 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel): def tools_all(cls): yield from cls._tools.items() + # Private tool lists for convenient reuse in `_tools`. + _tools_select = ( ( _defs_sequencer_select.select, @@ -3089,14 +3129,21 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel): ), ) + # Private tools dictionary, store data to implement `tools_all` & `tools_from_context`. + # The keys match sequence editors view type: 'context.space_data.view_type'. + # The values represent the tools, see `ToolSelectPanelHelper` for details. _tools = { None: [ ], 'PREVIEW': [ *_tools_select, + _defs_sequencer_generic.cursor, + None, _defs_sequencer_generic.translate, _defs_sequencer_generic.rotate, _defs_sequencer_generic.scale, + _defs_sequencer_generic.transform, + None, _defs_sequencer_generic.sample, *_tools_annotate, ], @@ -3106,12 +3153,10 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel): ], 'SEQUENCER_PREVIEW': [ *_tools_select, - _defs_sequencer_generic.translate, - _defs_sequencer_generic.rotate, - _defs_sequencer_generic.scale, - _defs_sequencer_generic.blade, - _defs_sequencer_generic.sample, + None, *_tools_annotate, + None, + _defs_sequencer_generic.blade, ], } diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 1d75ad8ff0a..99abc60db6f 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -481,6 +481,7 @@ class TOPBAR_MT_file_export(Menu): bl_owner_use_filter = False def draw(self, _context): + self.layout.operator("wm.obj_export", text="Wavefront OBJ (.obj) - New") if bpy.app.build_options.collada: self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") @@ -588,7 +589,7 @@ class TOPBAR_MT_edit(Menu): layout.separator() - layout.operator("ed.undo_history", text="Undo History...") + layout.menu("TOPBAR_MT_undo_history") layout.separator() @@ -634,6 +635,8 @@ class TOPBAR_MT_window(Menu): layout = self.layout + operator_context_default = layout.operator_context + layout.operator("wm.window_new") layout.operator("wm.window_new_main") @@ -655,7 +658,14 @@ class TOPBAR_MT_window(Menu): layout.separator() layout.operator("screen.screenshot") + + # Showing the status in the area doesn't work well in this case. + # - From the top-bar, the text replaces the file-menu (not so bad but strange). + # - From menu-search it replaces the area that the user may want to screen-shot. + # Setting the context to screen causes the status to show in the global status-bar. + layout.operator_context = 'INVOKE_SCREEN' layout.operator("screen.screenshot_area") + layout.operator_context = operator_context_default if sys.platform[:3] == "win": layout.separator() diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 7a8b6d42cad..0548486c786 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -398,21 +398,26 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa col = flow.column() col.prop(edit, "use_duplicate_action", text="Action") col.prop(edit, "use_duplicate_armature", text="Armature") + col.prop(edit, "use_duplicate_camera", text="Camera") col.prop(edit, "use_duplicate_curve", text="Curve") # col.prop(edit, "use_duplicate_fcurve", text="F-Curve") # Not implemented. col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil") if hasattr(edit, "use_duplicate_hair"): col.prop(edit, "use_duplicate_hair", text="Hair") - col.prop(edit, "use_duplicate_light", text="Light") + col = flow.column() + col.prop(edit, "use_duplicate_lattice", text="Lattice") + col.prop(edit, "use_duplicate_light", text="Light") col.prop(edit, "use_duplicate_lightprobe", text="Light Probe") col.prop(edit, "use_duplicate_material", text="Material") col.prop(edit, "use_duplicate_mesh", text="Mesh") col.prop(edit, "use_duplicate_metaball", text="Metaball") - col.prop(edit, "use_duplicate_particle", text="Particle") + col = flow.column() + col.prop(edit, "use_duplicate_particle", text="Particle") if hasattr(edit, "use_duplicate_pointcloud"): col.prop(edit, "use_duplicate_pointcloud", text="Point Cloud") + col.prop(edit, "use_duplicate_speaker", text="Speaker") col.prop(edit, "use_duplicate_surface", text="Surface") col.prop(edit, "use_duplicate_text", text="Text") # col.prop(edit, "use_duplicate_texture", text="Texture") # Not implemented. @@ -472,6 +477,16 @@ class USERPREF_PT_edit_weight_paint(EditingPanel, CenterAlignMixIn, Panel): col.active = view.use_weight_color_range col.template_color_ramp(view, "weight_color_range", expand=True) +class USERPREF_PT_edit_text_editor(EditingPanel, CenterAlignMixIn, Panel): + bl_label = "Text Editor" + bl_options = {'DEFAULT_CLOSED'} + + def draw_centered(self, context, layout): + prefs = context.preferences + edit = prefs.edit + + layout.prop(edit, "use_text_edit_auto_close") + class USERPREF_PT_edit_misc(EditingPanel, CenterAlignMixIn, Panel): bl_label = "Miscellaneous" @@ -581,9 +596,11 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel): @classmethod def poll(cls, _context): - # No GPU rendering on macOS currently. + # No GPU rendering on macOS x86_64 currently. + import platform import sys - return bpy.app.build_options.cycles and sys.platform != "darwin" + return bpy.app.build_options.cycles and \ + (sys.platform != "darwin" or platform.machine() == "arm64") def draw_centered(self, context, layout): prefs = context.preferences @@ -755,6 +772,17 @@ class USERPREF_PT_viewport_selection(ViewportPanel, CenterAlignMixIn, Panel): layout.prop(system, "use_select_pick_depth") +class USERPREF_PT_viewport_subdivision(ViewportPanel, CenterAlignMixIn, Panel): + bl_label = "Subdivision" + bl_options = {'DEFAULT_CLOSED'} + + def draw_centered(self, context, layout): + prefs = context.preferences + system = prefs.system + + layout.prop(system, "use_gpu_subdivision") + + # ----------------------------------------------------------------------------- # Theme Panels @@ -920,6 +948,7 @@ class USERPREF_PT_theme_interface_styles(ThemePanel, CenterAlignMixIn, Panel): flow.prop(ui, "editor_outline") flow.prop(ui, "widget_text_cursor") flow.prop(ui, "widget_emboss") + flow.prop(ui, "panel_roundness") class USERPREF_PT_theme_interface_transparent_checker(ThemePanel, CenterAlignMixIn, Panel): @@ -1404,12 +1433,18 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel): row.label(text="Path") for i, library in enumerate(paths.asset_libraries): - name_col.prop(library, "name", text="") + row = name_col.row() + row.alert = not library.name + row.prop(library, "name", text="") + row = path_col.row() - row.prop(library, "path", text="") + subrow = row.row() + subrow.alert = not library.path + subrow.prop(library, "path", text="") row.operator("preferences.asset_library_remove", text="", icon='X', emboss=False).index = i + row = box.row() - row.alignment = 'LEFT' + row.alignment = 'RIGHT' row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False) @@ -1796,7 +1831,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel): bl_options = {'HIDE_HEADER'} _support_icon_mapping = { - 'OFFICIAL': 'FILE_BLEND', + 'OFFICIAL': 'BLENDER', 'COMMUNITY': 'COMMUNITY', 'TESTING': 'EXPERIMENTAL', } @@ -1846,11 +1881,6 @@ class USERPREF_PT_addons(AddOnPanel, Panel): if p ) - # Development option for 2.8x, don't show users bundled addons - # unless they have been updated for 2.8x. - # Developers can turn them on with '--debug' - show_official_27x_addons = bpy.app.debug - # collect the categories that can be filtered on addons = [ (mod, addon_utils.module_bl_info(mod)) @@ -1927,15 +1957,6 @@ class USERPREF_PT_addons(AddOnPanel, Panel): ): continue - # Skip 2.7x add-ons included with Blender, unless in debug mode. - is_addon_27x = info.get("blender", (0,)) < (2, 80) - if ( - is_addon_27x and - (not show_official_27x_addons) and - (not mod.__file__.startswith(addon_user_dirs)) - ): - continue - # Addon UI Code col_box = col.column() box = col_box.box() @@ -1958,13 +1979,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel): sub.active = is_enabled sub.label(text="%s: %s" % (info["category"], info["name"])) - # WARNING: 2.8x exception, may be removed - # use disabled state for old add-ons, chances are they are broken. - if is_addon_27x: - sub.label(text="Upgrade to 2.8x required") - sub.label(icon='ERROR') - # Remove code above after 2.8x migration is complete. - elif info["warning"]: + if info["warning"]: sub.label(icon='ERROR') # icon showing support level. @@ -2304,6 +2319,8 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel): ({"property": "proxy_to_override_auto_conversion"}, "T91671"), ({"property": "use_cycles_debug"}, None), ({"property": "use_geometry_nodes_legacy"}, "T91274"), + ({"property": "show_asset_debug_info"}, None), + ({"property": "use_asset_indexing"}, None), ), ) @@ -2337,6 +2354,7 @@ classes = ( USERPREF_PT_viewport_quality, USERPREF_PT_viewport_textures, USERPREF_PT_viewport_selection, + USERPREF_PT_viewport_subdivision, USERPREF_PT_edit_objects, USERPREF_PT_edit_objects_new, @@ -2345,6 +2363,7 @@ classes = ( USERPREF_PT_edit_annotations, USERPREF_PT_edit_weight_paint, USERPREF_PT_edit_gpencil, + USERPREF_PT_edit_text_editor, USERPREF_PT_edit_misc, USERPREF_PT_animation_timeline, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 281c57b282f..5eca606216e 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2265,6 +2265,7 @@ class VIEW3D_MT_object(Menu): layout.separator() + layout.menu("VIEW3D_MT_object_asset") layout.menu("VIEW3D_MT_object_parent") layout.menu("VIEW3D_MT_object_collection") layout.menu("VIEW3D_MT_object_relations") @@ -2758,6 +2759,16 @@ class VIEW3D_MT_object_cleanup(Menu): layout.operator("object.material_slot_remove_unused", text="Remove Unused Material Slots") +class VIEW3D_MT_object_asset(Menu): + bl_label = "Asset" + + def draw(self, _context): + layout = self.layout + + layout.operator("asset.mark") + layout.operator("asset.clear", text="Clear Asset").set_fake_user = False + layout.operator("asset.clear", text="Clear Asset (Set Fake User)").set_fake_user = True + class VIEW3D_MT_make_single_user(Menu): bl_label = "Make Single User" @@ -3049,8 +3060,7 @@ class VIEW3D_MT_sculpt(Menu): layout.separator() - props = layout.operator("object.transfer_mode", text="Transfer Sculpt Mode") - props.use_eyedropper = True + layout.operator("object.transfer_mode", text="Transfer Sculpt Mode") class VIEW3D_MT_mask(Menu): @@ -3443,7 +3453,7 @@ class VIEW3D_MT_pose_slide(Menu): layout.operator("pose.push") layout.operator("pose.relax") layout.operator("pose.breakdown") - layout.operator("pose.blend_to_neighbour") + layout.operator("pose.blend_to_neighbor") class VIEW3D_MT_pose_propagate(Menu): @@ -3596,12 +3606,14 @@ class VIEW3D_MT_pose_context_menu(Menu): layout.operator("pose.push") layout.operator("pose.relax") layout.operator("pose.breakdown") - layout.operator("pose.blend_to_neighbour") + layout.operator("pose.blend_to_neighbor") layout.separator() layout.operator("pose.paths_calculate", text="Calculate Motion Paths") layout.operator("pose.paths_clear", text="Clear Motion Paths") + layout.operator("pose.paths_update", text="Update Armature Motion Paths") + layout.operator("object.paths_update_visible", text="Update All Motion Paths") layout.separator() @@ -4014,6 +4026,10 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): layout.separator() + layout.operator("transform.vert_crease") + + layout.separator() + layout.operator("mesh.blend_from_shape") layout.operator("mesh.shape_propagate_to_all", text="Propagate to Shapes") @@ -5978,7 +5994,7 @@ class VIEW3D_PT_shading_render_pass(Panel): class VIEW3D_PT_gizmo_display(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' - bl_label = "Gizmo" + bl_label = "Gizmos" bl_ui_units_x = 8 def draw(self, context): @@ -6492,18 +6508,38 @@ class VIEW3D_PT_overlay_sculpt(Panel): row.prop(overlay, "sculpt_mode_face_sets_opacity", text="Face Sets") -class VIEW3D_PT_overlay_pose(Panel): +class VIEW3D_PT_overlay_bones(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' bl_parent_id = 'VIEW3D_PT_overlay' - bl_label = "Pose Mode" + bl_label = "Bones" + + @staticmethod + def is_using_wireframe(context): + shading = VIEW3D_PT_shading.get_shading(context) + + if shading.type == 'WIREFRAME' or shading.show_xray: + return True + + mode = context.mode + + if mode in {'POSE', 'PAINT_WEIGHT'}: + armature = context.pose_object + elif mode == 'EDIT_ARMATURE': + armature = context.edit_object + else: + return False + + return armature and armature.display_type == 'WIRE' @classmethod def poll(cls, context): mode = context.mode return ( (mode == 'POSE') or - (mode == 'PAINT_WEIGHT' and context.pose_object) + (mode == 'PAINT_WEIGHT' and context.pose_object) or + (mode in {'EDIT_ARMATURE', 'OBJECT'} and + VIEW3D_PT_overlay_bones.is_using_wireframe(context)) ) def draw(self, context): @@ -6522,10 +6558,13 @@ class VIEW3D_PT_overlay_pose(Panel): sub = row.row() sub.active = display_all and overlay.show_xray_bone sub.prop(overlay, "xray_alpha_bone", text="Fade Geometry") - else: + elif mode == 'PAINT_WEIGHT': row = col.row() row.prop(overlay, "show_xray_bone") + if VIEW3D_PT_overlay_bones.is_using_wireframe(context): + col.prop(overlay, "bone_wire_alpha") + class VIEW3D_PT_overlay_texture_paint(Panel): bl_space_type = 'VIEW_3D' @@ -7540,6 +7579,7 @@ classes = ( VIEW3D_MT_image_add, VIEW3D_MT_object, VIEW3D_MT_object_animation, + VIEW3D_MT_object_asset, VIEW3D_MT_object_rigid_body, VIEW3D_MT_object_clear, VIEW3D_MT_object_context_menu, @@ -7692,7 +7732,7 @@ classes = ( VIEW3D_PT_overlay_texture_paint, VIEW3D_PT_overlay_vertex_paint, VIEW3D_PT_overlay_weight_paint, - VIEW3D_PT_overlay_pose, + VIEW3D_PT_overlay_bones, VIEW3D_PT_overlay_sculpt, VIEW3D_PT_snapping, VIEW3D_PT_proportional_edit, diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index acc3d933b85..4bd3d5cc3f2 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -689,13 +689,23 @@ class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel, Smooth class VIEW3D_PT_tools_weight_gradient(Panel, View3DPaintPanel): - bl_context = ".weightpaint" # dot on purpose (access from topbar) + # dont give context on purpose to not show this in the generic header toolsettings + # this is added only in the gradient tool's ToolDef + #bl_context = ".weightpaint" # dot on purpose (access from topbar) bl_label = "Falloff" bl_options = {'DEFAULT_CLOSED'} + # also dont draw as an extra panel in the sidebar (already included in the Brush settings) + bl_space_type = 'TOPBAR' + bl_region_type = 'HEADER' @classmethod def poll(cls, context): + # since we dont give context above, check mode here (to not show in other modes like sculpt) + if context.mode != 'PAINT_WEIGHT': + return False settings = context.tool_settings.weight_paint + if settings is None: + return False brush = settings.brush return brush is not None |