diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2018-08-01 15:16:41 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2018-08-01 15:16:41 +0300 |
commit | 936d1cef6e6124a8f8f3ce50182afa2e1c947c6f (patch) | |
tree | 429a7503472bd8fe38ceb062086e447cb3a83423 /release/scripts | |
parent | 4e6bcd10e559ab541df53a3d7b645faac1a7fe27 (diff) | |
parent | ddd62f1b1063d69df5171c7b3457ffcffcc6b0e4 (diff) |
Merge branch 'blender2.8' into soc-2018-bevel
Conflicts:
release/scripts/addons
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/editors/space_outliner/outliner_draw.c
Diffstat (limited to 'release/scripts')
38 files changed, 4113 insertions, 1436 deletions
diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 27970761a18926abe1b0020aa350305e3109a53 +Subproject 371960484a38fc64e0a2635170a41a0d8ab2f6b diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 86185b96e9d..f73d23c150b 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -367,14 +367,14 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non # Silent default, we know these need updating. if module_name in { - "io_anim_bvh", - "io_mesh_ply", - "io_mesh_stl", - "io_mesh_uv_layout", - "io_scene_3ds", - "io_scene_fbx", - "io_scene_obj", - "io_scene_x3d", + "io_anim_bvh", + "io_mesh_ply", + "io_mesh_stl", + "io_mesh_uv_layout", + "io_scene_3ds", + "io_scene_fbx", + "io_scene_obj", + "io_scene_x3d", }: return None diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index c629cf462aa..ec4db69986c 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -122,6 +122,12 @@ KM_HIERARCHY = [ ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region) ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint (Draw brush)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint (Fill)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint (Erase)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint Mode', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Sculpt Mode', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []), ]), ('Mask Editing', 'EMPTY', 'WINDOW', []), ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region) diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 7719e2f6e30..fff73a4285a 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -166,7 +166,7 @@ def object_data_add(context, obdata, operator=None, name=None): obj_act.select_set(action='SELECT') scene.update() # apply location - # scene.objects.active = obj_new + # layer.objects.active = obj_new # Match up UV layers, this is needed so adding an object with UV's # doesn't create new layers when there happens to be a naming mis-match. diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py index 2717a4f62a3..a94076ab61b 100644 --- a/release/scripts/startup/bl_operators/clip.py +++ b/release/scripts/startup/bl_operators/clip.py @@ -238,7 +238,7 @@ class CLIP_OT_track_to_empty(Operator): ob = bpy.data.objects.new(name=track.name, object_data=None) ob.select_set(action='SELECT') context.scene.objects.link(ob) - context.scene.objects.active = ob + context.view_layer.objects.active = ob for con in ob.constraints: if con.type == 'FOLLOW_TRACK': @@ -314,7 +314,7 @@ class CLIP_OT_bundles_to_mesh(Operator): ob.matrix_world = matrix context.scene.objects.link(ob) ob.select = True - context.scene.objects.active = ob + context.view_layer.objects.active = ob else: self.report({'WARNING'}, "No usable tracks selected") diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 530194e5bb7..0fe45f8fee3 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -257,7 +257,7 @@ class PresetMenu(Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'HEADER' bl_label = "Presets" - path_menu: Menu.path_menu + path_menu = Menu.path_menu @classmethod def draw_panel_header(cls, layout): @@ -670,6 +670,42 @@ class AddPresetUnitsLength(AddPresetBase, Operator): preset_subdir = "units_length" +class AddPresetGpencilBrush(AddPresetBase, Operator): + """Add or remove grease pencil brush preset""" + bl_idname = "scene.gpencil_brush_preset_add" + bl_label = "Add Grease Pencil Brush Preset" + preset_menu = "VIEW3D_PT_gpencil_brush_presets" + + preset_defines = [ + "brush = bpy.context.active_gpencil_brush", + "settings = brush.gpencil_settings" + ] + + preset_values = [ + "settings.input_samples", + "settings.active_smooth_factor", + "settings.angle", + "settings.angle_factor", + "settings.use_stabilizer", + "brush.smooth_stroke_radius", + "brush.smooth_stroke_factor", + "settings.pen_smooth_factor", + "settings.pen_smooth_steps", + "settings.pen_thick_smooth_factor", + "settings.pen_thick_smooth_steps", + "settings.pen_subdivision_steps", + "settings.random_subdiv", + "settings.enable_random", + "settings.random_pressure", + "settings.random_strength", + "settings.uv_random", + "settings.pen_jitter", + "settings.use_jitter_pressure", + ] + + preset_subdir = "gpencil_brush" + + classes = ( AddPresetCamera, AddPresetCloth, @@ -686,6 +722,7 @@ classes = ( AddPresetTrackingSettings, AddPresetTrackingTrackColor, AddPresetUnitsLength, + AddPresetGpencilBrush, ExecutePreset, WM_MT_operator_presets, ) diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py index 36150a63895..6b76fb96b62 100644 --- a/release/scripts/startup/bl_operators/rigidbody.py +++ b/release/scripts/startup/bl_operators/rigidbody.py @@ -60,7 +60,7 @@ class CopyRigidbodySettings(Operator): def execute(self, context): obj_act = context.object - scene = context.scene + view_layer = context.view_layer # deselect all but mesh objects for o in context.selected_objects: @@ -68,9 +68,9 @@ class CopyRigidbodySettings(Operator): o.select_set(action='DESELECT') elif o.rigid_body is None: # Add rigidbody to object! - scene.objects.active = o + view_layer.objects.active = o bpy.ops.rigidbody.object_add() - scene.objects.active = obj_act + view_layer.objects.active = obj_act objects = context.selected_objects if objects: @@ -265,7 +265,7 @@ class ConnectRigidBodies(Operator): ob = bpy.data.objects.new("Constraint", object_data=None) ob.location = loc context.scene.objects.link(ob) - context.scene.objects.active = ob + context.view_layer.objects.active = ob ob.select_set(action='SELECT') bpy.ops.rigidbody.constraint_add() @@ -278,7 +278,7 @@ class ConnectRigidBodies(Operator): con.object2 = object2 def execute(self, context): - scene = context.scene + view_layer = context.view_layer objects = context.selected_objects obj_act = context.active_object change = False @@ -312,7 +312,7 @@ class ConnectRigidBodies(Operator): bpy.ops.object.select_all(action='DESELECT') for obj in objects: obj.select_set(action='SELECT') - scene.objects.active = obj_act + view_layer.objects.active = obj_act return {'FINISHED'} else: self.report({'WARNING'}, "No other objects selected") diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 95a3d18304b..b866fb1ce40 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -579,7 +579,7 @@ def unwrap(operator, context, **kwargs): # define list of meshes meshes = [] if PREF_ACT_ONLY: - obj = context.scene.objects.active + obj = context.view_layer.objects.active if obj and obj.type == 'MESH': meshes = [obj.data] else: diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 51ba45cdcd7..89aed37f055 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -34,16 +34,19 @@ _modules = [ "properties_data_camera", "properties_data_curve", "properties_data_empty", + "properties_data_gpencil", "properties_data_light", "properties_data_lattice", "properties_data_mesh", "properties_data_metaball", "properties_data_modifier", + "properties_data_shaderfx", "properties_data_lightprobe", "properties_data_speaker", "properties_data_workspace", "properties_mask_common", "properties_material", + "properties_material_gpencil", "properties_object", "properties_paint_common", "properties_grease_pencil_common", diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index f66419a7f8e..cc0bde46189 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -88,7 +88,7 @@ class DATA_PT_lens(CameraButtonsPanel, Panel): if cam.lens_unit == 'MILLIMETERS': col.prop(cam, "lens") elif cam.lens_unit == 'FOV': - row.prop(cam, "angle") + col.prop(cam, "angle") col.prop(cam, "lens_unit") elif cam.type == 'ORTHO': @@ -250,15 +250,10 @@ class DATA_PT_camera_dof_aperture(CameraButtonsPanel, Panel): col.prop(dof_options, "rotation") col.prop(dof_options, "ratio") else: - hq_support = dof_options.is_hq_supported col = flow.column() col.label("Viewport") - sub = col.column() - sub.active = hq_support - sub.prop(dof_options, "use_high_quality") col.prop(dof_options, "fstop") - if dof_options.use_high_quality and hq_support: - col.prop(dof_options, "blades") + col.prop(dof_options, "blades") class DATA_PT_camera_background_image(CameraButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py new file mode 100644 index 00000000000..90dc86a20bb --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -0,0 +1,404 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import bpy +from bpy.types import Menu, Panel, UIList +from rna_prop_ui import PropertyPanel +from .properties_grease_pencil_common import ( + GreasePencilDataPanel, + GreasePencilOnionPanel, +) + +############################### +# Base-Classes (for shared stuff - e.g. poll, attributes, etc.) + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + return context.object and context.object.type == 'GPENCIL' + + +class LayerDataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + return (context.object and + context.object.type == 'GPENCIL' and + context.active_gpencil_layer) + + +############################### +# GP Object Properties Panels and Helper Classes + +class DATA_PT_gpencil(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + + def draw(self, context): + layout = self.layout + + # Grease Pencil data selector + gpd_owner = context.gpencil_data_owner + gpd = context.gpencil_data + + layout.template_ID(gpd_owner, "data") + + +class GPENCIL_UL_layer(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.GPencilLayer) + gpl = item + gpd = context.gpencil_data + + if self.layout_type in {'DEFAULT', 'COMPACT'}: + if gpl.lock: + layout.active = False + + row = layout.row(align=True) + if gpl.is_parented: + icon = 'BONE_DATA' + else: + icon = 'BLANK1' + + row.label(text="", icon=icon) + row.prop(gpl, "info", text="", emboss=False) + + row = layout.row(align=True) + row.prop(gpl, "lock", text="", emboss=False) + row.prop(gpl, "hide", text="", emboss=False) + row.prop(gpl, "unlock_color", text="", emboss=False) + if gpl.use_onion_skinning is False: + icon = 'GHOST_DISABLED' + else: + icon = 'GHOST_ENABLED' + subrow = row.row(align=True) + subrow.prop(gpl, "use_onion_skinning", text="", icon=icon, emboss=False) + subrow.active = gpd.use_onion_skinning + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class GPENCIL_MT_layer_specials(Menu): + bl_label = "Layer" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon + + layout.separator() + + layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All") + layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True + + layout.separator() + + layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All") + layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All") + + layout.separator() + + layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down") + + +class DATA_PT_gpencil_datapanel(Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Layers" + + @classmethod + def poll(cls, context): + if context.gpencil_data is None: + return False + + ob = context.object + if ob is not None and ob.type == 'GPENCIL': + return True + + return False + + @staticmethod + def draw(self, context): + layout = self.layout + #layout.use_property_split = True + layout.use_property_decorate = False + + gpd = context.gpencil_data + + # Grease Pencil data... + if (gpd is None) or (not gpd.layers): + layout.operator("gpencil.layer_add", text="New Layer") + else: + self.draw_layers(context, layout, gpd) + + def draw_layers(self, context, layout, gpd): + row = layout.row() + + col = row.column() + if len(gpd.layers) >= 2: + layer_rows = 5 + else: + layer_rows = 2 + col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows) + + col = row.column() + + sub = col.column(align=True) + sub.operator("gpencil.layer_add", icon='ZOOMIN', text="") + sub.operator("gpencil.layer_remove", icon='ZOOMOUT', text="") + + gpl = context.active_gpencil_layer + if gpl: + sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="") + + if len(gpd.layers) > 1: + col.separator() + + sub = col.column(align=True) + sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP' + sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN' + + col.separator() + + sub = col.column(align=True) + sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False + sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True + + row = layout.row(align=True) + if gpl: + row.prop(gpl, "opacity", text="Opacity", slider=True) + + +class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Adjustments" + bl_parent_id = 'DATA_PT_gpencil_datapanel' + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + gpl = context.active_gpencil_layer + layout.active = not gpl.lock + + # Layer options + # Offsets - Color Tint + layout.enabled = not gpl.lock + col = layout.column(align=True) + col.prop(gpl, "tint_color") + col.prop(gpl, "tint_factor", text="Factor", slider=True) + + # Offsets - Thickness + col = layout.row(align=True) + col.prop(gpl, "line_change", text="Stroke Thickness") + + +class DATA_PT_gpencil_parentpanel(LayerDataButtonsPanel, Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Relations" + bl_parent_id = 'DATA_PT_gpencil_datapanel' + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + gpl = context.active_gpencil_layer + col = layout.column() + col.active = not gpl.lock + col.prop(gpl, "parent") + col.prop(gpl, "parent_type", text="Type") + parent = gpl.parent + + if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE': + col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone") + + +class DATA_PT_gpencil_onionpanel(Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Onion Skinning" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return bool(context.active_gpencil_layer) + + @staticmethod + def draw_header(self, context): + self.layout.prop(context.gpencil_data, "use_onion_skinning", text="") + + def draw(self, context): + gpd = context.gpencil_data + + layout = self.layout + layout.use_property_split = True + layout.enabled = gpd.use_onion_skinning + + GreasePencilOnionPanel.draw_settings(layout, gpd) + + +class GPENCIL_MT_gpencil_vertex_group(Menu): + bl_label = "GP Vertex Groups" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'EXEC_AREA' + layout.operator("object.vertex_group_add") + + ob = context.active_object + if ob.vertex_groups.active: + layout.separator() + + layout.operator("gpencil.vertex_group_assign", text="Assign to Active Group") + layout.operator("gpencil.vertex_group_remove_from", text="Remove from Active Group") + + layout.separator() + layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group") + layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False + layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True + + layout.separator() + layout.operator("gpencil.vertex_group_select", text="Select Points") + layout.operator("gpencil.vertex_group_deselect", text="Deselect Points") + + +class GPENCIL_UL_vgroups(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + vgroup = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon) + # icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED' + # layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False) + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class DATA_PT_gpencil_vertexpanel(DataButtonsPanel, Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Vertex Groups" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + + ob = context.object + group = ob.vertex_groups.active + + rows = 2 + if group: + rows = 4 + + row = layout.row() + row.template_list("GPENCIL_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows) + + col = row.column(align=True) + col.operator("object.vertex_group_add", icon='ZOOMIN', text="") + col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="").all = False + + if ob.vertex_groups: + row = layout.row() + + sub = row.row(align=True) + sub.operator("gpencil.vertex_group_assign", text="Assign") + sub.operator("gpencil.vertex_group_remove_from", text="Remove") + + sub = row.row(align=True) + sub.operator("gpencil.vertex_group_select", text="Select") + sub.operator("gpencil.vertex_group_deselect", text="Deselect") + + layout.prop(context.tool_settings, "vertex_group_weight", text="Weight") + + +class DATA_PT_gpencil_display(DataButtonsPanel, Panel): + bl_label = "Viewport Display" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + + gpd = context.gpencil_data + gpl = context.active_gpencil_layer + + layout.prop(gpd, "xray_mode", text="Depth Ordering") + layout.prop(gpd, "edit_line_color", text="Edit Line Color") + layout.prop(ob, "empty_draw_size", text="Marker Size") + + col = layout.column(align=True) + col.prop(gpd, "show_constant_thickness") + sub = col.column() + sub.active = not gpd.show_constant_thickness + sub.prop(gpd, "pixfactor", text="Thickness Scale") + + if gpl: + layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions") + + +class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel): + _context_path = "object.data" + _property_type = bpy.types.GreasePencil + +############################### + + +classes = ( + DATA_PT_gpencil, + DATA_PT_gpencil_datapanel, + DATA_PT_gpencil_onionpanel, + DATA_PT_gpencil_layer_optionpanel, + DATA_PT_gpencil_parentpanel, + DATA_PT_gpencil_vertexpanel, + DATA_PT_gpencil_display, + DATA_PT_custom_props_gpencil, + + GPENCIL_UL_layer, + GPENCIL_UL_vgroups, + + GPENCIL_MT_layer_specials, + GPENCIL_MT_gpencil_vertex_group, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 214852cc826..f096ff83957 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -152,6 +152,7 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel): class DATA_PT_normals(MeshButtonsPanel, Panel): bl_label = "Normals" + bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): @@ -239,6 +240,7 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): class DATA_PT_face_maps(MeshButtonsPanel, Panel): bl_label = "Face Maps" + bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod @@ -450,13 +452,13 @@ classes = ( MESH_UL_shape_keys, MESH_UL_uvmaps_vcols, DATA_PT_context_mesh, - DATA_PT_normals, - DATA_PT_texture_space, DATA_PT_vertex_groups, - DATA_PT_face_maps, DATA_PT_shape_keys, DATA_PT_uv_texture, DATA_PT_vertex_colors, + DATA_PT_face_maps, + DATA_PT_normals, + DATA_PT_texture_space, DATA_PT_customdata, DATA_PT_custom_props_mesh, ) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 29098bdde4e..f2ed4b3b88c 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -32,6 +32,11 @@ class ModifierButtonsPanel: class DATA_PT_modifiers(ModifierButtonsPanel, Panel): bl_label = "Modifiers" + @classmethod + def poll(cls, context): + ob = context.object + return ob and ob.type != 'GPENCIL' + def draw(self, context): layout = self.layout @@ -1587,8 +1592,444 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "face_influence") +class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): + bl_label = "Modifiers" + + @classmethod + def poll(cls, context): + ob = context.object + return ob and ob.type == 'GPENCIL' + + def draw(self, context): + layout = self.layout + + ob = context.object + + layout.operator_menu_enum("object.gpencil_modifier_add", "type") + + for md in ob.grease_pencil_modifiers: + box = layout.template_greasepencil_modifier(md) + if box: + # match enum type to our functions, avoids a lookup table. + getattr(self, md.type)(box, ob, md) + + # the mt.type enum is (ab)used for a lookup on function names + # ...to avoid lengthy if statements + # so each type must have a function here. + + def GP_NOISE(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + row = col.row(align=True) + row.prop(md, "factor") + row.prop(md, "random", text="", icon="TIME", toggle=True) + row = col.row() + row.enabled = md.random + row.prop(md, "step") + col.prop(md, "full_stroke") + col.prop(md, "move_extreme") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row(align=True) + row.label("Affect:") + row = layout.row(align=True) + row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True) + row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True) + row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True) + row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True) + + def GP_SMOOTH(self, layout, ob, md): + gpd = ob.data + row = layout.row(align=False) + row.prop(md, "factor") + row.prop(md, "step") + + split = layout.split() + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col = split.column() + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row(align=True) + row.label("Affect:") + row = layout.row(align=True) + row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True) + row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True) + row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True) + row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True) + + def GP_SUBDIV(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + row = col.row(align=True) + row.prop(md, "level") + row.prop(md, "simple", text="", icon="PARTICLE_POINT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + def GP_SIMPLIFY(self, layout, ob, md): + gpd = ob.data + + row = layout.row() + row.prop(md, "mode") + + split = layout.split() + + col = split.column() + col.label("Settings:") + row = col.row(align=True) + row.enabled = md.mode == 'FIXED' + row.prop(md, "step") + + row = col.row(align=True) + row.enabled = not md.mode == 'FIXED' + row.prop(md, "factor") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + def GP_THICK(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + row = col.row(align=True) + row.prop(md, "thickness") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + col.prop(md, "normalize_thickness") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + if not md.normalize_thickness: + split = layout.split() + col = split.column() + col.prop(md, "use_custom_curve") + + if md.use_custom_curve: + col.template_curve_mapping(md, "curve") + + def GP_TINT(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.prop(md, "color") + col.prop(md, "factor") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row() + row.prop(md, "create_colors") + + def GP_COLOR(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label("Color:") + col.prop(md, "hue", text="H") + col.prop(md, "saturation", text="S") + col.prop(md, "value", text="V") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row() + row.prop(md, "create_colors") + + def GP_OPACITY(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label("Opacity:") + col.prop(md, "factor") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + def GP_INSTANCE(self, layout, ob, md): + gpd = ob.data + + col = layout.column() + col.prop(md, "count") + col.prop(md, "use_make_objects") + + split = layout.split() + col = split.column() + col.label("Offset:") + col.prop(md, "offset", text="") + + col = split.column() + col.label("Shift:") + col.prop(md, "shift", text="") + row = col.row(align=True) + row.prop(md, "lock_axis", expand=True) + + split = layout.split() + col = split.column() + col.label("Rotation:") + col.prop(md, "rotation", text="") + col.separator() + row = col.row(align=True) + row.prop(md, "random_rot", text="", icon="TIME", toggle=True) + row.prop(md, "rot_factor", text="") + + col = split.column() + col.label("Scale:") + col.prop(md, "scale", text="") + col.separator() + row = col.row(align=True) + row.prop(md, "random_scale", text="", icon="TIME", toggle=True) + row.prop(md, "scale_factor", text="") + + split = layout.split() + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + def GP_BUILD(self, layout, ob, md): + gpd = ob.data + + split = layout.split() + + col = split.column() + col.prop(md, "mode") + if md.mode == 'CONCURRENT': + col.prop(md, "concurrent_time_alignment") + else: + col.separator() # For spacing + col.separator() + col.separator() + + col.prop(md, "transition") + sub = col.column(align=True) + sub.prop(md, "start_delay") + sub.prop(md, "length") + + col = split.column(align=True) + col.prop(md, "use_restrict_frame_range") + sub = col.column(align=True) + sub.active = md.use_restrict_frame_range + sub.prop(md, "frame_start", text="Start") + sub.prop(md, "frame_end", text="End") + col.separator() + + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + def GP_LATTICE(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label(text="Object:") + col.prop(md, "object", text="") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + layout.separator() + layout.prop(md, "strength", slider=True) + + def GP_MIRROR(self, layout, ob, md): + gpd = ob.data + + row = layout.row(align=True) + row.prop(md, "x_axis") + row.prop(md, "y_axis") + row.prop(md, "z_axis") + + # GPXX: Not implemented yet + # layout.separator() + # layout.prop(md, "clip") + + layout.label("Layer:") + row = layout.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + layout.label(text="Object:") + layout.prop(md, "object", text="") + + def GP_HOOK(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label(text="Object:") + col.prop(md, "object", text="") + if md.object and md.object.type == 'ARMATURE': + col.label(text="Bone:") + col.prop_search(md, "subtarget", md.object.data, "bones", text="") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + use_falloff = (md.falloff_type != 'NONE') + split = layout.split() + + layout.separator() + + row = layout.row(align=True) + if use_falloff: + row.prop(md, "falloff_radius") + row.prop(md, "strength", slider=True) + layout.prop(md, "falloff_type") + + col = layout.column() + if use_falloff: + if md.falloff_type == 'CURVE': + col.template_curve_mapping(md, "falloff_curve") + + split = layout.split() + + col = split.column() + col.prop(md, "use_falloff_uniform") + + def GP_OFFSET(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.prop(md, "location") + col.prop(md, "scale") + + col = split.column() + col.prop(md, "rotation") + + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + classes = ( DATA_PT_modifiers, + DATA_PT_gpencil_modifiers, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py new file mode 100644 index 00000000000..3798a273e09 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py @@ -0,0 +1,135 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import bpy +from bpy.types import Panel +from bpy.app.translations import pgettext_iface as iface_ + + +class ShaderFxButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "shaderfx" + bl_options = {'HIDE_HEADER'} + + +class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel): + bl_label = "Effects" + + @classmethod + def poll(cls, context): + return True + ob = context.object + return ob and ob.type == 'GPENCIL' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + + layout.operator_menu_enum("object.shaderfx_add", "type") + + for fx in ob.shader_effects: + box = layout.template_shaderfx(fx) + if box: + # match enum type to our functions, avoids a lookup table. + getattr(self, fx.type)(box, fx) + + # the mt.type enum is (ab)used for a lookup on function names + # ...to avoid lengthy if statements + # so each type must have a function here. + + def FX_BLUR(self, layout, fx): + + layout.prop(fx, "factor", text="Factor") + layout.prop(fx, "samples", text="Samples") + + layout.separator() + layout.prop(fx, "use_dof_mode") + if fx.use_dof_mode: + layout.prop(fx, "coc") + + def FX_COLORIZE(self, layout, fx): + layout.prop(fx, "mode", text="Mode") + + if fx.mode == 'BITONE': + layout.prop(fx, "low_color", text="Low Color") + if fx.mode == 'CUSTOM': + layout.prop(fx, "low_color", text="Color") + + if fx.mode == 'BITONE': + layout.prop(fx, "high_color", text="High Color") + + if fx.mode in {'BITONE', 'CUSTOM', 'TRANSPARENT'}: + layout.prop(fx, "factor") + + def FX_WAVE(self, layout, fx): + layout.prop(fx, "orientation", expand=True) + + layout.separator() + layout.prop(fx, "amplitude") + layout.prop(fx, "period") + layout.prop(fx, "phase") + + def FX_PIXEL(self, layout, fx): + layout.prop(fx, "size", text="Size") + + layout.prop(fx, "use_lines", text="Display Lines") + + col = layout.column() + col.enabled = fx.use_lines + col.prop(fx, "color") + + def FX_RIM(self, layout, fx): + layout.prop(fx, "offset", text="Offset") + + layout.prop(fx, "rim_color") + layout.prop(fx, "mask_color") + layout.prop(fx, "mode") + layout.prop(fx, "blur") + layout.prop(fx, "samples") + + def FX_SWIRL(self, layout, fx): + layout.prop(fx, "object", text="Object") + + layout.prop(fx, "radius") + layout.prop(fx, "angle") + + layout.prop(fx, "transparent") + + def FX_FLIP(self, layout, fx): + layout.prop(fx, "flip_horizontal") + layout.prop(fx, "flip_vertical") + + def FX_LIGHT(self, layout, fx): + layout.prop(fx, "object", text="Object") + + layout.prop(fx, "energy") + layout.prop(fx, "ambient") + + +classes = ( + DATA_PT_shader_fx, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index a2ccfb4f1b8..b291cc7bd82 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -18,45 +18,30 @@ # <pep8 compliant> - +import bpy from bpy.types import Menu, UIList from bpy.app.translations import pgettext_iface as iface_ def gpencil_stroke_placement_settings(context, layout): if context.space_data.type == 'VIEW_3D': - propname = "gpencil_stroke_placement_view3d" + propname = "annotation_stroke_placement_view3d" elif context.space_data.type == 'SEQUENCE_EDITOR': - propname = "gpencil_stroke_placement_sequencer_preview" + propname = "annotation_stroke_placement_sequencer_preview" elif context.space_data.type == 'IMAGE_EDITOR': - propname = "gpencil_stroke_placement_image_editor" + propname = "annotation_stroke_placement_image_editor" else: - propname = "gpencil_stroke_placement_view2d" + propname = "annotation_stroke_placement_view2d" ts = context.tool_settings col = layout.column(align=True) - col.label(text="Stroke Placement:") - - row = col.row(align=True) - row.prop_enum(ts, propname, 'VIEW') - row.prop_enum(ts, propname, 'CURSOR') - - if context.space_data.type == 'VIEW_3D': + if context.space_data.type != 'VIEW_3D': + col.label(text="Stroke Placement:") row = col.row(align=True) - row.prop_enum(ts, propname, 'SURFACE') - row.prop_enum(ts, propname, 'STROKE') - - row = col.row(align=False) - row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'} - row.prop(ts, "use_gpencil_stroke_endpoints") - - if context.scene.tool_settings.gpencil_stroke_placement_view3d == 'CURSOR': - row = col.row(align=True) - row.label("Lock axis:") - row = col.row(align=True) - row.prop(ts.gpencil_sculpt, "lockaxis", expand=True) + row.prop_enum(ts, propname, 'VIEW') + row.prop_enum(ts, propname, 'CURSOR', text="Cursor") def gpencil_active_brush_settings_simple(context, layout): @@ -73,7 +58,7 @@ def gpencil_active_brush_settings_simple(context, layout): row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA') row.prop(brush, "name", text="") - col.prop(brush, "line_width", slider=True) + col.prop(brush, "size", slider=True) row = col.row(align=True) row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE') row.prop(brush, "pen_sensitivity_factor", slider=True) @@ -90,6 +75,7 @@ def gpencil_active_brush_settings_simple(context, layout): row.prop(brush, "angle_factor", text="Factor", slider=True) +# XXX: To be replaced with active tools class GreasePencilDrawingToolsPanel: # subclass must set # bl_space_type = 'IMAGE_EDITOR' @@ -99,8 +85,7 @@ class GreasePencilDrawingToolsPanel: @classmethod def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False + return True @staticmethod def draw(self, context): @@ -113,12 +98,12 @@ class GreasePencilDrawingToolsPanel: col.label(text="Draw:") row = col.row(align=True) - row.operator("gpencil.draw", icon='GREASEPENCIL', text="Draw").mode = 'DRAW' - row.operator("gpencil.draw", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon + row.operator("gpencil.annotate", icon='GREASEPENCIL', text="Draw").mode = 'DRAW' + row.operator("gpencil.annotate", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon row = col.row(align=True) - row.operator("gpencil.draw", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT' - row.operator("gpencil.draw", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY' + row.operator("gpencil.annotate", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT' + row.operator("gpencil.annotate", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY' col.separator() @@ -126,15 +111,15 @@ class GreasePencilDrawingToolsPanel: sub.operator("gpencil.blank_frame_add", icon='NEW') sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)") - sub = col.column(align=True) - sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing") - sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing") - sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back") + #sub = col.column(align=True) + #sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing") + #sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing") + #sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back") col.separator() col.separator() - if context.space_data.type in {'VIEW_3D', 'CLIP_EDITOR'}: + if context.space_data.type in {'CLIP_EDITOR'}: col.separator() col.label("Data Source:") row = col.row(align=True) @@ -143,8 +128,8 @@ class GreasePencilDrawingToolsPanel: elif is_clip_editor: row.prop(context.space_data, "grease_pencil_source", expand=True) - col.separator() - col.separator() + # col.separator() + # col.separator() gpencil_stroke_placement_settings(context, col) @@ -157,28 +142,16 @@ class GreasePencilDrawingToolsPanel: col = layout.column(align=True) col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True) - if is_3d_view: - col.separator() - col.separator() - - col.label(text="Tools:") - col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type") - col.operator("view3d.ruler") - class GreasePencilStrokeEditPanel: # subclass must set # bl_space_type = 'IMAGE_EDITOR' bl_label = "Edit Strokes" - bl_category = "Grease Pencil" + bl_category = "Tools" bl_region_type = 'TOOLS' - bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False - if context.gpencil_data is None: return False @@ -204,7 +177,7 @@ class GreasePencilStrokeEditPanel: col.operator("gpencil.select_linked") col.operator("gpencil.select_more") col.operator("gpencil.select_less") - col.operator("gpencil.palettecolor_select") + col.operator("gpencil.select_alternate") layout.label(text="Edit:") row = layout.row(align=True) @@ -228,261 +201,125 @@ class GreasePencilStrokeEditPanel: layout.separator() - col = layout.column(align=True) - col.operator("transform.bend", text="Bend") - col.operator("transform.mirror", text="Mirror") - col.operator("transform.shear", text="Shear") - col.operator("transform.tosphere", text="To Sphere") - layout.separator() col = layout.column(align=True) col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction") - col.operator("gpencil.stroke_change_color", text="Move to Color") - - if is_3d_view: - layout.separator() + col.operator("gpencil.stroke_change_color", text="Assign Material") layout.separator() col = layout.column(align=True) col.operator("gpencil.stroke_subdivide", text="Subdivide") - col.operator("gpencil.stroke_join", text="Join").type = 'JOIN' - col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY' - col.operator("gpencil.stroke_flip", text="Flip Direction") - - gpd = context.gpencil_data - if gpd: - col.prop(gpd, "show_stroke_direction", text="Show Directions") - - if is_3d_view: - layout.separator() - layout.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type") - - -class GreasePencilInterpolatePanel: - bl_space_type = 'VIEW_3D' - bl_label = "Interpolate" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False - - if context.gpencil_data is None: - return False - elif context.space_data.type != 'VIEW_3D': - return False - - gpd = context.gpencil_data - return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) - - @staticmethod - def draw(self, context): - layout = self.layout - settings = context.tool_settings.gpencil_interpolate - - col = layout.column(align=True) - col.operator("gpencil.interpolate", text="Interpolate") - col.operator("gpencil.interpolate_sequence", text="Sequence") - col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns") - - col = layout.column(align=True) - col.label(text="Options:") - col.prop(settings, "interpolate_all_layers") - col.prop(settings, "interpolate_selected_only") - - col = layout.column(align=True) - col.label(text="Sequence Options:") - col.prop(settings, "type") - if settings.type == 'CUSTOM': - box = layout.box() - # TODO: Options for loading/saving curve presets? - box.template_curve_mapping(settings, "interpolation_curve", brush=True) - elif settings.type != 'LINEAR': - col.prop(settings, "easing") - - if settings.type == 'BACK': - layout.prop(settings, "back") - elif setting.type == 'ELASTIC': - sub = layout.column(align=True) - sub.prop(settings, "amplitude") - sub.prop(settings, "period") - - -class GreasePencilBrushPanel: - # subclass must set - # bl_space_type = 'IMAGE_EDITOR' - bl_label = "Drawing Brushes" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' - - @classmethod - def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False + row = col.row(align=True) + row.operator("gpencil.stroke_simplify_fixed", text="Simplify") + row.operator("gpencil.stroke_simplify", text="Adaptative") - @staticmethod - def draw(self, context): - layout = self.layout + col.separator() - row = layout.row() - col = row.column() - ts = context.scene.tool_settings - if len(ts.gpencil_brushes) >= 2: - brows = 3 - else: - brows = 2 - col.template_list("GPENCIL_UL_brush", "", ts, "gpencil_brushes", ts.gpencil_brushes, "active_index", rows=brows) + row = col.row(align=True) + row.operator("gpencil.stroke_join", text="Join").type = 'JOIN' + row.operator("gpencil.stroke_join", text="& Copy").type = 'JOINCOPY' - col = row.column() + col.operator("gpencil.stroke_flip", text="Flip Direction") - sub = col.column(align=True) - sub.operator("gpencil.brush_add", icon='ZOOMIN', text="") - sub.operator("gpencil.brush_remove", icon='ZOOMOUT', text="") - sub.menu("GPENCIL_MT_brush_specials", icon='DOWNARROW_HLT', text="") - brush = context.active_gpencil_brush - if brush: - if len(ts.gpencil_brushes) > 1: - col.separator() - sub = col.column(align=True) - sub.operator("gpencil.brush_move", icon='TRIA_UP', text="").type = 'UP' - sub.operator("gpencil.brush_move", icon='TRIA_DOWN', text="").type = 'DOWN' + if is_3d_view: + layout.separator() - # Brush details - if brush is not None: - row = layout.row() - row.prop(brush, "line_width") - row = layout.row(align=True) - row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE') - row.prop(brush, "pen_sensitivity_factor", slider=True) - row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE') - row = layout.row(align=True) - row.prop(brush, "use_random_strength", text="", icon='RNDCURVE') - row.prop(brush, "strength", slider=True) - row.prop(brush, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') - row = layout.row(align=True) - row.prop(brush, "random_press", slider=True) + col = layout.column(align=True) + col.operator_menu_enum("gpencil.stroke_separate", text="Separate...", property="mode") + col.operator("gpencil.stroke_split", text="Split") - row = layout.row(align=True) - row.prop(brush, "jitter", slider=True) - row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE') - row = layout.row() - row.prop(brush, "angle", slider=True) - row.prop(brush, "angle_factor", text="Factor", slider=True) - - box = layout.box() - col = box.column(align=True) - col.label(text="Stroke Quality:") - col.prop(brush, "pen_smooth_factor") - col.prop(brush, "pen_smooth_steps") - col.separator() - row = col.row(align=False) - row.prop(brush, "pen_subdivision_steps") - row.prop(brush, "random_subdiv", text="Randomness", slider=True) + col = layout.column(align=True) + col.label(text="Cleanup:") + col.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type") + col.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode") class GreasePencilStrokeSculptPanel: # subclass must set # bl_space_type = 'IMAGE_EDITOR' bl_label = "Sculpt Strokes" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' - - @classmethod - def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False - - if context.gpencil_data is None: - return False - - gpd = context.gpencil_data - return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) + bl_category = "Tools" @staticmethod def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False settings = context.tool_settings.gpencil_sculpt tool = settings.tool brush = settings.brush - layout.column().prop(settings, "tool") + layout.template_icon_view(settings, "tool", show_labels=True) - col = layout.column() - col.prop(brush, "size", slider=True) - row = col.row(align=True) + layout.prop(brush, "size", slider=True) + row = layout.row(align=True) row.prop(brush, "strength", slider=True) row.prop(brush, "use_pressure_strength", text="") - col.prop(brush, "use_falloff") - if tool in {'SMOOTH', 'RANDOMIZE'}: - row = layout.row(align=True) - row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True) - row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True) - row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True) - layout.separator() + layout.prop(brush, "use_falloff") - if tool == 'THICKNESS': - layout.row().prop(brush, "direction", expand=True) - elif tool == 'PINCH': - row = layout.row(align=True) - row.prop_enum(brush, "direction", 'ADD', text="Pinch") - row.prop_enum(brush, "direction", 'SUBTRACT', text="Inflate") - elif settings.tool == 'TWIST': - row = layout.row(align=True) - row.prop_enum(brush, "direction", 'SUBTRACT', text="CW") - row.prop_enum(brush, "direction", 'ADD', text="CCW") + if tool in {'SMOOTH', 'RANDOMIZE'}: + layout.prop(settings, "affect_position", text="Affect Position") + layout.prop(settings, "affect_strength", text="Affect Strength") + layout.prop(settings, "affect_thickness", text="Affect Thickness") - row = layout.row(align=True) - row.prop(settings, "use_select_mask") - row = layout.row(align=True) - row.prop(settings, "selection_alpha", slider=True) + if tool == 'SMOOTH': + layout.prop(brush, "affect_pressure") - if tool == 'SMOOTH': - layout.prop(brush, "affect_pressure") + layout.prop(settings, "affect_uv", text="Affect UV") + if tool in {'THICKNESS', 'PINCH', 'TWIST'}: + layout.prop(brush, "direction", expand=True) -class GreasePencilBrushCurvesPanel: - # subclass must set - # bl_space_type = 'IMAGE_EDITOR' - bl_label = "Brush Curves" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' + +# GP Object Tool Settings +class GreasePencilAppearancePanel: + bl_label = "Brush Appearance" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False - - if context.active_gpencil_brush is None: - return False - - brush = context.active_gpencil_brush - return bool(brush) + ob = context.active_object + return ob and ob.type == 'GPENCIL' @staticmethod def draw(self, context): layout = self.layout - brush = context.active_gpencil_brush - # Brush - layout.label("Sensitivity") - box = layout.box() - box.template_curve_mapping(brush, "curve_sensitivity", brush=True) + layout.use_property_split = True + layout.use_property_decorate = False + + ob = context.active_object + + if ob.mode == 'GPENCIL_PAINT': + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings - layout.label("Strength") - box = layout.box() - box.template_curve_mapping(brush, "curve_strength", brush=True) + layout.prop(gp_settings, "gpencil_brush_type", text="Brush Type") - layout.label("Jitter") - box = layout.box() - box.template_curve_mapping(brush, "curve_jitter", brush=True) + sub = layout.column(align=True) + sub.enabled = not brush.use_custom_icon + sub.prop(gp_settings, "gp_icon", text="Icon") + layout.prop(brush, "use_custom_icon") + sub = layout.column() + sub.active = brush.use_custom_icon + sub.prop(brush, "icon_filepath", text="") + + layout.prop(gp_settings, "use_cursor", text="Show Brush") + + if gp_settings.gpencil_brush_type == 'FILL': + layout.prop(brush, "cursor_color_add", text="Color") + + elif ob.mode in ('GPENCIL_SCULPT', 'GPENCIL_WEIGHT'): + settings = context.tool_settings.gpencil_sculpt + brush = settings.brush + + col = layout.column(align=True) + col.prop(brush, "use_cursor", text="Show Brush") + col.row().prop(brush, "cursor_color_add", text="Add") + col.row().prop(brush, "cursor_color_sub", text="Subtract") -############################### class GPENCIL_MT_pie_tool_palette(Menu): """A pie menu for quick access to Grease Pencil tools""" @@ -539,6 +376,7 @@ class GPENCIL_MT_pie_tool_palette(Menu): col.operator("gpencil.select_border", text="Border Select", icon='BORDER_RECT') col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY') col.operator("gpencil.select_lasso", text="Lasso Select", icon='BORDER_LASSO') + col.operator("gpencil.select_alternate", text="Alternate Select", icon='BORDER_LASSO') # SW - Edit Tools col = pie.column() @@ -566,7 +404,7 @@ class GPENCIL_MT_pie_settings_palette(Menu): pie = layout.menu_pie() gpd = context.gpencil_data gpl = context.active_gpencil_layer - palcolor = context.active_gpencil_palettecolor + palcolor = None # context.active_gpencil_palettecolor brush = context.active_gpencil_brush is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes) @@ -668,7 +506,7 @@ class GPENCIL_MT_pie_tools_more(Menu): class GPENCIL_MT_pie_sculpt(Menu): - """A pie menu for accessing Grease Pencil stroke sculpting settings""" + """A pie menu for accessing Grease Pencil stroke sculpt settings""" bl_label = "Grease Pencil Sculpt" @classmethod @@ -717,9 +555,6 @@ class GPENCIL_MT_pie_sculpt(Menu): row.prop_enum(settings, "tool", value='RANDOMIZE') -############################### - - class GPENCIL_MT_snap(Menu): bl_label = "Snap" @@ -728,7 +563,7 @@ class GPENCIL_MT_snap(Menu): layout.operator("gpencil.snap_to_grid", text="Selection to Grid") layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor").use_offset = False - layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor (Offset)").use_offset = True + layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True layout.separator() @@ -737,6 +572,16 @@ class GPENCIL_MT_snap(Menu): layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid") +class GPENCIL_MT_separate(Menu): + bl_label = "Separate" + + def draw(self, context): + layout = self.layout + layout.operator("gpencil.stroke_separate", text="Selected Points").mode = 'POINT' + layout.operator("gpencil.stroke_separate", text="Selected Strokes").mode = 'STROKE' + layout.operator("gpencil.stroke_separate", text="Active Layer").mode = 'LAYER' + + class GPENCIL_MT_gpencil_edit_specials(Menu): bl_label = "GPencil Specials" @@ -747,6 +592,14 @@ class GPENCIL_MT_gpencil_edit_specials(Menu): layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.operator("gpencil.stroke_simplify_fixed", text="Simplify") + layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative") + + layout.separator() + layout.menu("GPENCIL_MT_separate", text="Separate") + + layout.separator() + layout.operator("gpencil.stroke_split", text="Split") layout.separator() @@ -754,168 +607,128 @@ class GPENCIL_MT_gpencil_edit_specials(Menu): layout.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY' layout.operator("gpencil.stroke_flip", text="Flip Direction") + layout.separator() + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL' + if is_3d_view: layout.separator() layout.operator("gpencil.reproject") -############################### - - -class GPENCIL_UL_brush(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.GPencilBrush) - brush = item - - if self.layout_type in {'DEFAULT', 'COMPACT'}: - row = layout.row(align=True) - row.prop(brush, "name", text="", emboss=False, icon='BRUSH_DATA') - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) - - -class GPENCIL_UL_palettecolor(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.PaletteColor) - palcolor = item - - if self.layout_type in {'DEFAULT', 'COMPACT'}: - if palcolor.lock: - layout.active = False - - split = layout.split(percentage=0.25) - row = split.row(align=True) - row.enabled = not palcolor.lock - row.prop(palcolor, "color", text="", emboss=palcolor.is_stroke_visible) - row.prop(palcolor, "fill_color", text="", emboss=palcolor.is_fill_visible) - split.prop(palcolor, "name", text="", emboss=False) - - row = layout.row(align=True) - row.prop(palcolor, "lock", text="", emboss=False) - row.prop(palcolor, "hide", text="", emboss=False) - if palcolor.ghost is True: - icon = 'GHOST_DISABLED' - else: - icon = 'GHOST_ENABLED' - row.prop(palcolor, "ghost", text="", icon=icon, emboss=False) - - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) - +class GPENCIL_MT_gpencil_sculpt_specials(Menu): + bl_label = "GPencil Specials" -class GPENCIL_UL_layer(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.GPencilLayer) - gpl = item + def draw(self, context): + layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' - if self.layout_type in {'DEFAULT', 'COMPACT'}: - if gpl.lock: - layout.active = False + layout.operator_context = 'INVOKE_REGION_WIN' - row = layout.row(align=True) - if gpl.is_parented: - icon = 'BONE_DATA' - else: - icon = 'BLANK1' + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL' - row.label(text="", icon=icon) - row.prop(gpl, "info", text="", emboss=False) + layout.separator() - row = layout.row(align=True) - row.prop(gpl, "lock", text="", emboss=False) - row.prop(gpl, "hide", text="", emboss=False) - row.prop(gpl, "unlock_color", text="", emboss=False) - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) + layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.operator("gpencil.stroke_simplify_fixed", text="Simplify") + layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative") -class GPENCIL_MT_layer_specials(Menu): - bl_label = "Layer" +class GPENCIL_MT_gpencil_draw_specials(Menu): + bl_label = "GPencil Draw Specials" def draw(self, context): layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' - layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon - - layout.separator() + layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All") - layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL' layout.separator() + layout.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE' + layout.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX' + layout.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE' - layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All") - layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All") - + # Colors. layout.separator() + layout.operator("gpencil.colorpick", text="Colors", icon="GROUP_VCOL") - layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down") - -class GPENCIL_MT_brush_specials(Menu): - bl_label = "Layer" +class GPENCIL_MT_gpencil_draw_delete(Menu): + bl_label = "GPencil Draw Delete" def draw(self, context): layout = self.layout - layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy Current Drawing Brush") - layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a Set of Predefined Brushes") - + is_3d_view = context.space_data.type == 'VIEW_3D' -class GPENCIL_MT_palettecolor_specials(Menu): - bl_label = "Layer" + layout.operator_context = 'INVOKE_REGION_WIN' - def draw(self, context): - layout = self.layout + layout.operator("gpencil.active_frames_delete_all", text="Delete Frame") - layout.operator("gpencil.palettecolor_reveal", icon='RESTRICT_VIEW_OFF', text="Show All") - layout.operator("gpencil.palettecolor_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True - layout.separator() +class GPENCIL_UL_annotation_layer(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.GPencilLayer) + gpl = item + gpd = context.gpencil_data - layout.operator("gpencil.palettecolor_lock_all", icon='LOCKED', text="Lock All") - layout.operator("gpencil.palettecolor_unlock_all", icon='UNLOCKED', text="UnLock All") - layout.operator("gpencil.palettecolor_copy", icon='PASTEDOWN', text="Copy Color") + if self.layout_type in {'DEFAULT', 'COMPACT'}: + if gpl.lock: + layout.active = False - layout.separator() + split = layout.split(percentage=0.2) + split.prop(gpl, "color", text="", emboss=True) + split.prop(gpl, "info", text="", emboss=False) - layout.operator("gpencil.palettecolor_select", icon='COLOR', text="Select Strokes") - layout.operator("gpencil.stroke_change_color", icon='MAN_TRANS', text="Move to Color") + row = layout.row(align=True) + # row.prop(gpl, "lock", text="", emboss=False) + row.prop(gpl, "hide", text="", emboss=False) + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) class GreasePencilDataPanel: - # subclass must set - # bl_space_type = 'IMAGE_EDITOR' - bl_label = "Grease Pencil Layers" + bl_label = "Annotations" bl_region_type = 'UI' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + # Show this panel as long as someone that might own this exists + # AND the owner isn't an object (e.g. GP Object) + if context.gpencil_data_owner is None: + return False + elif type(context.gpencil_data_owner) is bpy.types.Object: + return False + else: + return True @staticmethod def draw_header(self, context): - self.layout.prop(context.space_data, "show_grease_pencil", text="") + if context.space_data.type != 'VIEW_3D': + self.layout.prop(context.space_data, "show_annotation", text="") @staticmethod def draw(self, context): layout = self.layout + layout.use_property_decorate = False - # owner of Grease Pencil data + # Grease Pencil owner. gpd_owner = context.gpencil_data_owner gpd = context.gpencil_data - # Owner Selector - if context.space_data.type == 'VIEW_3D': - layout.row().prop(context.tool_settings, "grease_pencil_source", expand=True) - elif context.space_data.type == 'CLIP_EDITOR': + # Owner selector. + if context.space_data.type == 'CLIP_EDITOR': layout.row().prop(context.space_data, "grease_pencil_source", expand=True) - # Grease Pencil data selector layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink") - # Grease Pencil data... - if (gpd is None) or (not gpd.layers): - layout.operator("gpencil.layer_add", text="New Layer") - else: + # List of layers/notes. + if gpd and gpd.layers: self.draw_layers(context, layout, gpd) def draw_layers(self, context, layout, gpd): @@ -926,7 +739,7 @@ class GreasePencilDataPanel: layer_rows = 5 else: layer_rows = 2 - col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows) + col.template_list("GPENCIL_UL_annotation_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows) col = row.column() @@ -936,8 +749,6 @@ class GreasePencilDataPanel: gpl = context.active_gpencil_layer if gpl: - sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="") - if len(gpd.layers) > 1: col.separator() @@ -945,211 +756,69 @@ class GreasePencilDataPanel: sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP' sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN' - col.separator() - - sub = col.column(align=True) - sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False - sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True - if gpl: - self.draw_layer(context, layout, gpl) + # layout.prop(gpl, "opacity", text="Opacity", slider=True) + # layout.prop(gpl, "thickness", text="Thickness") + # + # layout.separator() - def draw_layer(self, context, layout, gpl): - row = layout.row(align=True) - row.prop(gpl, "opacity", text="Opacity", slider=True) - - # Layer options - split = layout.split(percentage=0.5) - split.active = not gpl.lock - split.prop(gpl, "show_x_ray") - split.prop(gpl, "show_points") - - # Offsets + Parenting (where available) - if context.space_data.type == 'VIEW_3D': - split = layout.split(percentage=0.5) - else: - split = layout.column() # parenting is not available in 2D editors... - split.active = not gpl.lock - - # Offsets - Color Tint - col = split.column() - subcol = col.column(align=True) - subcol.label("Tint") - subcol.enabled = not gpl.lock - subcol.prop(gpl, "tint_color", text="") - subcol.prop(gpl, "tint_factor", text="Factor", slider=True) - - # Offsets - Thickness - row = col.row(align=True) - row.prop(gpl, "line_change", text="Thickness Change", slider=True) - row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="") - - # Parenting - if context.space_data.type == 'VIEW_3D': - col = split.column(align=True) - col.label(text="Parent:") - col.prop(gpl, "parent", text="") - - sub = col.column() - sub.prop(gpl, "parent_type", text="") - parent = gpl.parent - if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE': - sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="") - - layout.separator() + # Full-Row - Frame Locking (and Delete Frame) + row = layout.row(align=True) + row.active = not gpl.lock - # Full-Row - Frame Locking (and Delete Frame) - row = layout.row(align=True) - row.active = not gpl.lock + if gpl.active_frame: + lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked") + lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status) + else: + lock_label = iface_("Lock Frame") + row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED') + row.operator("gpencil.active_frame_delete", text="", icon='X') - if gpl.active_frame: - lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked") - lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status) + tool_settings = context.tool_settings + if gpd and gpl: + layout.prop(gpl, "thickness") else: - lock_label = iface_("Lock Frame") - row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED') - row.operator("gpencil.active_frame_delete", text="", icon='X') - - layout.separator() - - # Onion skinning - col = layout.column(align=True) - col.active = not gpl.lock - - row = col.row() - row.prop(gpl, "use_onion_skinning") - sub = row.row(align=True) - icon = 'RESTRICT_RENDER_OFF' if gpl.use_ghosts_always else 'RESTRICT_RENDER_ON' - sub.prop(gpl, "use_ghosts_always", text="", icon=icon) - sub.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR') - - split = col.split(percentage=0.5) - split.active = gpl.use_onion_skinning - - # - Before Frames - sub = split.column(align=True) - row = sub.row(align=True) - row.active = gpl.use_ghost_custom_colors - row.prop(gpl, "before_color", text="") - sub.prop(gpl, "ghost_before_range", text="Before") - - # - After Frames - sub = split.column(align=True) - row = sub.row(align=True) - row.active = gpl.use_ghost_custom_colors - row.prop(gpl, "after_color", text="") - sub.prop(gpl, "ghost_after_range", text="After") - - -class GreasePencilPaletteColorPanel: - # subclass must set - bl_label = "Grease Pencil Colors" - bl_region_type = 'UI' + layout.prop(tool_settings, "annotation_thickness", text="Thickness") - @classmethod - def poll(cls, context): - # XXX - disabled in 2.8 branch. - return False - - if context.gpencil_data is None: - return False - - gpd = context.gpencil_data - return bool(gpd.layers.active) +class GreasePencilOnionPanel: @staticmethod - def draw(self, context): - layout = self.layout - palette = context.active_gpencil_palette - - if palette: - row = layout.row(align=True) - row.operator_context = 'EXEC_REGION_WIN' - row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR') - row.prop(palette, "name", text="") - row.operator("gpencil.palette_add", icon='ZOOMIN', text="") - row.operator("gpencil.palette_remove", icon='X', text="") - - # Palette colors - row = layout.row() - col = row.column() - if len(palette.colors) >= 2: - color_rows = 5 - else: - color_rows = 2 - col.template_list("GPENCIL_UL_palettecolor", "", palette, "colors", palette.colors, "active_index", - rows=color_rows) + def draw_settings(layout, gp): + col = layout.column() + col.prop(gp, "onion_mode") + col.prop(gp, "onion_factor", text="Opacity", slider=True) - col = row.column() + if gp.onion_mode in ('ABSOLUTE', 'RELATIVE'): + col = layout.column(align=True) + col.prop(gp, "ghost_before_range", text="Frames Before") + col.prop(gp, "ghost_after_range", text="After") - sub = col.column(align=True) - sub.operator("gpencil.palettecolor_add", icon='ZOOMIN', text="") - sub.operator("gpencil.palettecolor_remove", icon='ZOOMOUT', text="") + layout.prop(gp, "use_ghost_custom_colors", text="Use Custom Colors") - palcol = context.active_gpencil_palettecolor - if palcol: - sub.menu("GPENCIL_MT_palettecolor_specials", icon='DOWNARROW_HLT', text="") + if gp.use_ghost_custom_colors: + col = layout.column(align=True) + col.active = gp.use_ghost_custom_colors + col.prop(gp, "before_color", text="Color Before") + col.prop(gp, "after_color", text="After") - if len(palette.colors) > 1: - col.separator() + layout.prop(gp, "use_ghosts_always", text="View In Render") - sub = col.column(align=True) - sub.operator("gpencil.palettecolor_move", icon='TRIA_UP', text="").direction = 'UP' - sub.operator("gpencil.palettecolor_move", icon='TRIA_DOWN', text="").direction = 'DOWN' - - row = layout.row() - sub = row.row(align=True) - sub.label(text="Isolate:") # based on active color only - sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False - sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True - sub = row.row(align=True) - sub.label(text="Lock:") # based on other stuff... - sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="") - sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="") - - pcolor = palette.colors.active - if pcolor: - self.draw_palettecolors(layout, pcolor) - - # Draw palette colors - def draw_palettecolors(self, layout, pcolor): - # color settings - split = layout.split(percentage=0.5) - split.active = not pcolor.lock - - # Column 1 - Stroke - col = split.column(align=True) - col.enabled = not pcolor.lock - col.label(text="Stroke:") - col.prop(pcolor, "color", text="") - col.prop(pcolor, "alpha", slider=True) - - # Column 2 - Fill - col = split.column(align=True) - col.enabled = not pcolor.lock - col.label(text="Fill:") - col.prop(pcolor, "fill_color", text="") - col.prop(pcolor, "fill_alpha", text="Opacity", slider=True) - - # Options - split = layout.split(percentage=0.5) - split.active = not pcolor.lock - - col = split.column(align=True) - col.active = not pcolor.lock - col.prop(pcolor, "use_volumetric_strokes") - col = split.column(align=True) - col.active = not pcolor.lock - col.prop(pcolor, "use_hq_fill") + col = layout.column(align=True) + col.active = gp.use_onion_skinning + col.prop(gp, "use_onion_fade", text="Fade") + if hasattr(gp, "use_onion_loop"): # XXX + sub = layout.column() + sub.active = gp.onion_mode in ('RELATIVE', 'SELECTED') + sub.prop(gp, "use_onion_loop", text="Loop") class GreasePencilToolsPanel: # For use in "2D" Editors without their own toolbar # subclass must set # bl_space_type = 'IMAGE_EDITOR' - # bl_options = {'DEFAULT_CLOSED'} bl_label = "Grease Pencil Settings" bl_region_type = 'UI' + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): @@ -1189,14 +858,16 @@ classes = ( GPENCIL_MT_pie_settings_palette, GPENCIL_MT_pie_tools_more, GPENCIL_MT_pie_sculpt, + GPENCIL_MT_snap, + GPENCIL_MT_separate, + GPENCIL_MT_gpencil_edit_specials, - GPENCIL_UL_brush, - GPENCIL_UL_palettecolor, - GPENCIL_UL_layer, - GPENCIL_MT_layer_specials, - GPENCIL_MT_brush_specials, - GPENCIL_MT_palettecolor_specials, + GPENCIL_MT_gpencil_sculpt_specials, + GPENCIL_MT_gpencil_draw_specials, + GPENCIL_MT_gpencil_draw_delete, + + GPENCIL_UL_annotation_layer, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 0e3e50b3497..5d12f762073 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -86,8 +86,11 @@ class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): @classmethod def poll(cls, context): - engine = context.engine - return (context.material or context.object) and (engine in cls.COMPAT_ENGINES) + if context.active_object and context.active_object.type == 'GPENCIL': + return False + else: + engine = context.engine + return (context.material or context.object) and (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py new file mode 100644 index 00000000000..d83639a361c --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py @@ -0,0 +1,321 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import bpy +from bpy.types import Menu, Panel, UIList +from rna_prop_ui import PropertyPanel + + +class GPENCIL_MT_color_specials(Menu): + bl_label = "Layer" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.color_reveal", icon='RESTRICT_VIEW_OFF', text="Show All") + layout.operator("gpencil.color_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True + + layout.separator() + + layout.operator("gpencil.color_lock_all", icon='LOCKED', text="Lock All") + layout.operator("gpencil.color_unlock_all", icon='UNLOCKED', text="UnLock All") + + layout.separator() + + layout.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="Lock Unselected") + layout.operator("gpencil.lock_layer", icon='COLOR', text="Lock Unused") + + +class GPENCIL_UL_matslots(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + slot = item + ma = slot.material + if (ma is not None) and (ma.grease_pencil is not None): + gpcolor = ma.grease_pencil + + if self.layout_type in {'DEFAULT', 'COMPACT'}: + if gpcolor.lock: + layout.active = False + + row = layout.row(align=True) + row.enabled = not gpcolor.lock + row.prop(ma, "name", text="", emboss=False, icon_value=icon) + + row = layout.row(align=True) + row.prop(gpcolor, "lock", text="", emboss=False) + row.prop(gpcolor, "hide", text="", emboss=False) + if gpcolor.ghost is True: + icon = 'GHOST_DISABLED' + else: + icon = 'GHOST_ENABLED' + row.prop(gpcolor, "ghost", text="", icon=icon, emboss=False) + + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class GPMaterialButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "material" + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'GPENCIL' and + ob.active_material and + ob.active_material.grease_pencil) + + +class MATERIAL_PT_gpencil_slots(Panel): + bl_label = "Grease Pencil Material Slots" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "material" + bl_options = {'HIDE_HEADER'} + + @classmethod + def poll(cls, context): + ob = context.object + return ob and ob.type == 'GPENCIL' + + @staticmethod + def draw(self, context): + layout = self.layout + gpd = context.gpencil_data + + mat = context.object.active_material + ob = context.object + slot = context.material_slot + space = context.space_data + + if ob: + is_sortable = len(ob.material_slots) > 1 + rows = 1 + if (is_sortable): + rows = 4 + + row = layout.row() + + row.template_list("GPENCIL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows) + + col = row.column(align=True) + col.operator("object.material_slot_add", icon='ZOOMIN', text="") + col.operator("object.material_slot_remove", icon='ZOOMOUT', text="") + + col.menu("GPENCIL_MT_color_specials", icon='DOWNARROW_HLT', text="") + + if is_sortable: + col.separator() + + col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP' + col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN' + + col.separator() + + sub = col.column(align=True) + sub.operator("gpencil.color_isolate", icon='LOCKED', text="").affect_visibility = False + sub.operator("gpencil.color_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True + + row = layout.row() + + if ob: + row.template_ID(ob, "active_material", new="material.new", live_icon=True) + + if slot: + icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA' + row.prop(slot, "link", icon=icon_link, icon_only=True) + + if gpd.use_stroke_edit_mode: + row = layout.row(align=True) + row.operator("gpencil.stroke_change_color", text="Assign") + row.operator("gpencil.color_select", text="Select") + + elif mat: + row.template_ID(space, "pin_id") + + +# Used as parent for "Stroke" and "Fill" panels +class MATERIAL_PT_gpencil_surface(GPMaterialButtonsPanel, Panel): + bl_label = "Surface" + + @classmethod + def poll(cls, context): + ob = context.object + ma = context.object.active_material + if ma is None or ma.grease_pencil is None: + return False + + return ob and ob.type == 'GPENCIL' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + +class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel): + bl_label = "Stroke" + bl_parent_id = 'MATERIAL_PT_gpencil_surface' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ma = context.object.active_material + if ma is not None and ma.grease_pencil is not None: + gpcolor = ma.grease_pencil + + col = layout.column() + col.active = not gpcolor.lock + + col.prop(gpcolor, "mode") + + col.prop(gpcolor, "stroke_style", text="Style") + + if gpcolor.stroke_style == 'TEXTURE': + row = col.row() + row.enabled = not gpcolor.lock + col = row.column(align=True) + col.template_ID(gpcolor, "stroke_image", open="image.open") + col.prop(gpcolor, "pixel_size", text="UV Factor") + col.prop(gpcolor, "use_stroke_pattern", text="Use As Pattern") + + if gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern is True: + col.prop(gpcolor, "color", text="Color") + + +class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel): + bl_label = "Fill" + bl_parent_id = 'MATERIAL_PT_gpencil_surface' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ma = context.object.active_material + if ma is not None and ma.grease_pencil: + gpcolor = ma.grease_pencil + + # color settings + col = layout.column() + col.active = not gpcolor.lock + col.prop(gpcolor, "fill_style", text="Style") + + if gpcolor.fill_style == 'GRADIENT': + col.prop(gpcolor, "gradient_type") + + if gpcolor.fill_style != 'TEXTURE': + col.prop(gpcolor, "fill_color", text="Color") + + if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'): + col.prop(gpcolor, "mix_color", text="Secondary Color") + + if gpcolor.fill_style == 'GRADIENT': + col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) + + if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'): + col.prop(gpcolor, "flip", text="Flip Colors") + + col.prop(gpcolor, "pattern_shift", text="Location") + col.prop(gpcolor, "pattern_scale", text="Scale") + + if gpcolor.gradient_type == 'RADIAL' and gpcolor.fill_style not in ('SOLID', 'CHESSBOARD'): + col.prop(gpcolor, "pattern_radius", text="Radius") + else: + if gpcolor.fill_style != 'SOLID': + col.prop(gpcolor, "pattern_angle", text="Angle") + + if gpcolor.fill_style == 'CHESSBOARD': + col.prop(gpcolor, "pattern_gridsize", text="Box Size") + + # Texture + if gpcolor.fill_style == 'TEXTURE' or (gpcolor.texture_mix is True and gpcolor.fill_style == 'SOLID'): + col.template_ID(gpcolor, "fill_image", open="image.open") + + if gpcolor.fill_style == 'TEXTURE': + col.prop(gpcolor, "use_fill_pattern", text="Use As Pattern") + if gpcolor.use_fill_pattern is True: + col.prop(gpcolor, "fill_color", text="Color") + + col.prop(gpcolor, "texture_offset", text="Offset") + col.prop(gpcolor, "texture_scale", text="Scale") + col.prop(gpcolor, "texture_angle") + col.prop(gpcolor, "texture_opacity") + col.prop(gpcolor, "texture_clamp", text="Clip Image") + + if gpcolor.use_fill_pattern is False: + col.prop(gpcolor, "texture_mix", text="Mix With Color") + + if gpcolor.texture_mix is True: + col.prop(gpcolor, "fill_color", text="Mix Color") + col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) + + +class MATERIAL_PT_gpencil_preview(GPMaterialButtonsPanel, Panel): + bl_label = "Preview" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + ma = context.object.active_material + self.layout.label(ma.name) + self.layout.template_preview(ma) + + +class MATERIAL_PT_gpencil_custom_props(GPMaterialButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_OPENGL'} + _context_path = "object.active_material" + _property_type = bpy.types.Material + + +class MATERIAL_PT_gpencil_options(GPMaterialButtonsPanel, Panel): + bl_label = "Options" + bl_options = {'DEFAULT_CLOSED'} + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ma = context.object.active_material + if ma is not None and ma.grease_pencil is not None: + gpcolor = ma.grease_pencil + layout.prop(gpcolor, "pass_index") + + +classes = ( + GPENCIL_UL_matslots, + GPENCIL_MT_color_specials, + MATERIAL_PT_gpencil_slots, + MATERIAL_PT_gpencil_preview, + MATERIAL_PT_gpencil_surface, + MATERIAL_PT_gpencil_strokecolor, + MATERIAL_PT_gpencil_fillcolor, + MATERIAL_PT_gpencil_options, + MATERIAL_PT_gpencil_custom_props, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 9d891a07989..393c9784be8 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -662,164 +662,336 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): if part.physics_type == 'FLUID': fluid = part.fluid - col.label(text="Fluid") + col.separator() col.prop(fluid, "solver") col.prop(fluid, "stiffness", text="Stiffness") col.prop(fluid, "linear_viscosity", text="Viscosity") col.prop(fluid, "buoyancy", text="Buoyancy", slider=True) - col.label(text="Advanced") + elif part.physics_type == 'KEYED': - if fluid.solver == 'DDR': - sub = col.column() - sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion) - sub.prop(fluid, "factor_repulsion") + sub = col.column() + sub.active = not psys.use_keyed_timing + sub.prop(part, "keyed_loops", text="Loops") + if psys: + col.prop(psys, "use_keyed_timing", text="Use Timing") - sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity) - sub.prop(fluid, "factor_stiff_viscosity") + col.label(text="Keys") + + +class PARTICLE_PT_physics_fluid_advanced(ParticleButtonsPanel, Panel): + bl_label = "Advanced" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID': + return True + else: + return False + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + col = layout.column() + + if fluid.solver == 'DDR': sub = col.column() - sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius) - sub.prop(fluid, "factor_radius") + sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion) + sub.prop(fluid, "factor_repulsion") - sub.prop(fluid, "rest_density", slider=fluid.use_factor_density) - sub.prop(fluid, "use_factor_density") + sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity) + sub.prop(fluid, "factor_stiff_viscosity") - if fluid.solver == 'CLASSICAL': - # With the classical solver, it is possible to calculate the - # spacing between particles when the fluid is at rest. This - # makes it easier to set stable initial conditions. - particle_volume = part.mass / fluid.rest_density - spacing = pow(particle_volume, 1.0 / 3.0) + sub = col.column() + sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius) + sub.prop(fluid, "factor_radius") - sub.label(text="Spacing: %g" % spacing) + sub.prop(fluid, "rest_density", slider=fluid.use_factor_density) + sub.prop(fluid, "use_factor_density") - elif fluid.solver == 'DDR': + if fluid.solver == 'CLASSICAL': + # With the classical solver, it is possible to calculate the + # spacing between particles when the fluid is at rest. This + # makes it easier to set stable initial conditions. + particle_volume = part.mass / fluid.rest_density + spacing = pow(particle_volume, 1.0 / 3.0) - col.label(text="Springs") - col.prop(fluid, "spring_force", text="Force") - col.prop(fluid, "use_viscoelastic_springs") + sub.label(text="Spacing: %g" % spacing) - sub = col.column() - sub.active = fluid.use_viscoelastic_springs - sub.prop(fluid, "yield_ratio", slider=True) - sub.prop(fluid, "plasticity", slider=True) - col.label(text="Advanced") - sub = col.column() - sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length) - sub.prop(fluid, "factor_rest_length", text="") +class PARTICLE_PT_physics_fluid_springs(ParticleButtonsPanel, Panel): + bl_label = "Springs" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - sub = col.column() - sub.active = fluid.use_viscoelastic_springs - sub.prop(fluid, "use_initial_rest_length") - sub.prop(fluid, "spring_frames", text="Frames") + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID' and fluid.solver == 'DDR': + return True + else: + return False - elif part.physics_type == 'KEYED': + def draw(self, context): + layout = self.layout + layout.use_property_split = True - sub = col.column() - sub.active = not psys.use_keyed_timing - sub.prop(part, "keyed_loops", text="Loops") - if psys: - col.prop(psys, "use_keyed_timing", text="Use Timing") + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid - col.label(text="Keys") + col = layout.column() - elif part.physics_type == 'BOIDS': - boids = part.boids + col.prop(fluid, "spring_force", text="Force") - row = layout.row() - row.prop(boids, "use_flight") - row.prop(boids, "use_land") - row.prop(boids, "use_climb") - - split = layout.split() - - col = split.column(align=True) - col.active = boids.use_flight - col.prop(boids, "air_speed_max") - col.prop(boids, "air_speed_min", slider=True) - col.prop(boids, "air_acc_max", slider=True) - col.prop(boids, "air_ave_max", slider=True) - col.prop(boids, "air_personal_space") - row = col.row(align=True) - row.active = (boids.use_land or boids.use_climb) and boids.use_flight - row.prop(boids, "land_smooth") - - col = split.column(align=True) - col.active = boids.use_land or boids.use_climb - col.prop(boids, "land_speed_max") - col.prop(boids, "land_jump_speed") - col.prop(boids, "land_acc_max", slider=True) - col.prop(boids, "land_ave_max", slider=True) - col.prop(boids, "land_personal_space") - col.prop(boids, "land_stick_force") - - layout.prop(part, "collision_group") - - split = layout.split() - - col = split.column(align=True) - col.label(text="Battle:") - col.prop(boids, "health") - col.prop(boids, "strength") - col.prop(boids, "aggression") - col.prop(boids, "accuracy") - col.prop(boids, "range") - col = split.column() - col.label(text="Misc:") - col.prop(boids, "bank", slider=True) - col.prop(boids, "pitch", slider=True) - col.prop(boids, "height", slider=True) - - if psys and part.physics_type in {'KEYED', 'BOIDS', 'FLUID'}: - if part.physics_type == 'BOIDS': - layout.label(text="Relations:") - elif part.physics_type == 'FLUID': - layout.label(text="Fluid Interaction:") +class PARTICLE_PT_physics_fluid_springs_viscoelastic(ParticleButtonsPanel, Panel): + bl_label = "Viscoelastic Springs" + bl_parent_id = "PARTICLE_PT_physics_fluid_springs" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - row = layout.row() - row.template_list("UI_UL_list", "particle_targets", psys, "targets", - psys, "active_particle_target_index", rows=4) - - col = row.column() - sub = col.row() - subsub = sub.column(align=True) - subsub.operator("particle.new_target", icon='ZOOMIN', text="") - subsub.operator("particle.target_remove", icon='ZOOMOUT', text="") - sub = col.row() - subsub = sub.column(align=True) - subsub.operator("particle.target_move_up", icon='TRIA_UP', text="") - subsub.operator("particle.target_move_down", icon='TRIA_DOWN', text="") - - key = psys.active_particle_target - if key: - row = layout.row() - if part.physics_type == 'KEYED': - col = row.column() - # doesn't work yet - #col.alert = key.valid - col.prop(key, "object", text="") - col.prop(key, "system", text="System") - col = row.column() - col.active = psys.use_keyed_timing - col.prop(key, "time") - col.prop(key, "duration") - elif part.physics_type == 'BOIDS': - sub = row.row() - # doesn't work yet - #sub.alert = key.valid - sub.prop(key, "object", text="") - sub.prop(key, "system", text="System") - - layout.row().prop(key, "alliance", expand=True) - elif part.physics_type == 'FLUID': - sub = row.row() - # doesn't work yet - #sub.alert = key.valid - sub.prop(key, "object", text="") - sub.prop(key, "system", text="System") + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID' and fluid.solver == 'DDR': + return True + else: + return False + + def draw_header(self, context): + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + self.layout.prop(fluid, "use_viscoelastic_springs", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + col = layout.column() + col.active = fluid.use_viscoelastic_springs + col.prop(fluid, "yield_ratio", slider=True) + col.prop(fluid, "plasticity", slider=True) + + col.separator() + + col.prop(fluid, "use_initial_rest_length") + col.prop(fluid, "spring_frames", text="Frames") + + +class PARTICLE_PT_physics_fluid_springs_advanced(ParticleButtonsPanel, Panel): + bl_label = "Advanced" + bl_parent_id = "PARTICLE_PT_physics_fluid_springs" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID' and fluid.solver == 'DDR': + return True + else: + return False + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + sub = layout.column() + sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length) + sub.prop(fluid, "factor_rest_length") + + +class PARTICLE_PT_physics_boids_movement(ParticleButtonsPanel, Panel): + bl_label = "Movement" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'BOIDS'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + boids = part.boids + + col = layout.column() + + col.prop(boids, "use_flight") + col.prop(boids, "use_land") + col.prop(boids, "use_climb") + + col = layout.column() + + col.active = boids.use_flight + sub = col.column() + sub.prop(boids, "air_speed_max") + sub.prop(boids, "air_speed_min", slider=True) + col.prop(boids, "air_acc_max", slider=True) + col.prop(boids, "air_ave_max", slider=True) + col.prop(boids, "air_personal_space") + row = col.row(align=True) + row.active = (boids.use_land or boids.use_climb) and boids.use_flight + row.prop(boids, "land_smooth") + + layout.separator() + + col = layout.column() + col.active = boids.use_land or boids.use_climb + col.prop(boids, "land_speed_max") + col.prop(boids, "land_jump_speed") + col.prop(boids, "land_acc_max", slider=True) + col.prop(boids, "land_ave_max", slider=True) + col.prop(boids, "land_personal_space") + col.prop(boids, "land_stick_force") + + layout.separator() + + layout.prop(part, "collision_group") + + +class PARTICLE_PT_physics_boids_battle(ParticleButtonsPanel, Panel): + bl_label = "Battle" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'BOIDS'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + boids = part.boids + + col = layout.column() + + col.prop(boids, "health") + col.prop(boids, "strength") + col.prop(boids, "aggression") + col.prop(boids, "accuracy") + col.prop(boids, "range") + + +class PARTICLE_PT_physics_boids_misc(ParticleButtonsPanel, Panel): + bl_label = "Misc" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'BOIDS'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + boids = part.boids + + col = layout.column() + + col.prop(boids, "bank", slider=True) + col.prop(boids, "pitch", slider=True) + col.prop(boids, "height", slider=True) + + +class PARTICLE_PT_physics_relations(ParticleButtonsPanel, Panel): + bl_label = "Relations" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'KEYED', 'BOIDS', 'FLUID'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + + row = layout.row() + row.template_list("UI_UL_list", "particle_targets", psys, "targets", + psys, "active_particle_target_index", rows=4) + + col = row.column() + sub = col.row() + subsub = sub.column(align=True) + subsub.operator("particle.new_target", icon='ZOOMIN', text="") + subsub.operator("particle.target_remove", icon='ZOOMOUT', text="") + sub = col.row() + subsub = sub.column(align=True) + subsub.operator("particle.target_move_up", icon='TRIA_UP', text="") + subsub.operator("particle.target_move_down", icon='TRIA_DOWN', text="") + + key = psys.active_particle_target + + if key: + if part.physics_type == 'KEYED': + col = layout.column() + # doesn't work yet + #col.alert = key.valid + col.prop(key, "object") + col.prop(key, "system", text="System") + + col.active = psys.use_keyed_timing + col.prop(key, "time") + col.prop(key, "duration") + elif part.physics_type == 'BOIDS': + sub = layout.column() + # doesn't work yet + #sub.alert = key.valid + sub.prop(key, "object") + sub.prop(key, "system", text="System") + layout.prop(key, "alliance") + elif part.physics_type == 'FLUID': + sub = layout.column() + # doesn't work yet + #sub.alert = key.valid + sub.prop(key, "object") + sub.prop(key, "system", text="System") class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel): @@ -911,6 +1083,9 @@ class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel): class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): bl_label = "Boid Brain" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = "PARTICLE_PT_physics" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod @@ -1941,9 +2116,17 @@ classes = ( PARTICLE_PT_rotation, PARTICLE_PT_rotation_angular_velocity, PARTICLE_PT_physics, + PARTICLE_PT_physics_fluid_springs, + PARTICLE_PT_physics_fluid_springs_viscoelastic, + PARTICLE_PT_physics_fluid_springs_advanced, + PARTICLE_PT_physics_fluid_advanced, + PARTICLE_PT_physics_boids_movement, + PARTICLE_PT_physics_boids_battle, + PARTICLE_PT_physics_boids_misc, PARTICLE_PT_physics_forces, PARTICLE_PT_physics_deflection, PARTICLE_PT_physics_integration, + PARTICLE_PT_physics_relations, PARTICLE_PT_boidbrain, PARTICLE_PT_render, PARTICLE_PT_render_line, diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index 7775722784b..0a7318864a3 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -17,8 +17,11 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> + import bpy -from bpy.types import Menu, Panel +from bpy.types import ( + Panel, +) from bl_operators.presets import PresetMenu from .properties_physics_common import ( @@ -58,6 +61,7 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True md = context.cloth ob = context.object @@ -65,64 +69,82 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel): layout.active = cloth_panel_enabled(md) - split = layout.split(percentage=0.25) - - split.label(text="Quality:") - split.prop(cloth, "quality", text="Steps") - - split = layout.split(percentage=0.25) + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - split.label(text="Speed:") - split.prop(cloth, "time_scale", text="Multiplier") + col = flow.column() + col.prop(cloth, "quality", text="Quality Steps") + col.prop(cloth, "time_scale", text="Speed Multiplier") - split = layout.split() + col.separator() - col = split.column() - - col.label(text="Material:") - col.prop(cloth, "mass") + col = flow.column() + col.prop(cloth, "mass", text="Material Mass") col.prop(cloth, "structural_stiffness", text="Structural") col.prop(cloth, "bending_stiffness", text="Bending") - col = split.column() + col.separator() - col.label(text="Damping:") - col.prop(cloth, "spring_damping", text="Spring") + col = flow.column() + col.prop(cloth, "spring_damping", text="Damping Spring") col.prop(cloth, "air_damping", text="Air") col.prop(cloth, "vel_damping", text="Velocity") - split = layout.split() + col = flow.column() + col.prop(cloth, "use_dynamic_mesh", text="Dynamic Mesh") - col = split.column() + key = ob.data.shape_keys - col.prop(cloth, "use_pin_cloth", text="Pinning:") - sub = col.column() - sub.active = cloth.use_pin_cloth - sub.prop_search(cloth, "vertex_group_mass", ob, "vertex_groups", text="") - sub.prop(cloth, "pin_stiffness", text="Stiffness") + if key: + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.active = not cloth.use_dynamic_mesh + row.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="Rest Shape Key") + row.label(text="", icon='BLANK1') - # Disabled for now - """ - if cloth.vertex_group_mass: - layout.label(text="Goal:") - col = layout.column_flow() - col.prop(cloth, "goal_default", text="Default") - col.prop(cloth, "goal_spring", text="Stiffness") - col.prop(cloth, "goal_friction", text="Friction") - """ +class PHYSICS_PT_cloth_pinning(PhysicButtonsPanel, Panel): + bl_label = "Pinning" + bl_parent_id = 'PHYSICS_PT_cloth' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - col = split.column() + def draw_header(self, context): + md = context.cloth + cloth = md.settings - col.prop(cloth, "use_dynamic_mesh", text="Dynamic Mesh") + self.layout.active = cloth_panel_enabled(md) and cloth.use_pin_cloth + self.layout.prop(cloth, "use_pin_cloth", text="") - key = ob.data.shape_keys + def draw(self, context): + layout = self.layout + layout.use_property_split = True - if key: - sub = col.column() - sub.active = not cloth.use_dynamic_mesh - sub.label(text="Rest Shape Key:") - sub.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="") + md = context.cloth + ob = context.object + cloth = md.settings + + layout.active = cloth_panel_enabled(md) and cloth.use_pin_cloth + + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) + + col = flow.column() + + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(cloth, "vertex_group_mass", ob, "vertex_groups", text="Mass Group") + row.label(text="", icon='BLANK1') + + col = flow.column() + col.prop(cloth, "pin_stiffness", text="Stiffness") + + # Disabled for now. + """ + if cloth.vertex_group_mass: + col = flow.column() + col.prop(cloth, "goal_default", text="Goal Default") + col.prop(cloth, "goal_spring", text="Stiffness") + col.prop(cloth, "goal_friction", text="Friction") + """ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel): @@ -150,31 +172,59 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True cloth = context.cloth.collision_settings md = context.cloth - ob = context.object layout.active = cloth.use_collision and cloth_panel_enabled(md) - split = layout.split() + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - col = split.column() + col = flow.column() col.prop(cloth, "collision_quality", text="Quality") col.prop(cloth, "distance_min", slider=True, text="Distance") col.prop(cloth, "repel_force", slider=True, text="Repel") + + col = flow.column() col.prop(cloth, "distance_repel", slider=True, text="Repel Distance") col.prop(cloth, "friction") + col.prop(cloth, "group") - col = split.column() - col.prop(cloth, "use_self_collision", text="Self Collision") - sub = col.column() - sub.active = cloth.use_self_collision - sub.prop(cloth, "self_collision_quality", text="Quality") - sub.prop(cloth, "self_distance_min", slider=True, text="Distance") - sub.prop_search(cloth, "vertex_group_self_collisions", ob, "vertex_groups", text="") - layout.prop(cloth, "group") +class PHYSICS_PT_cloth_self_collision(PhysicButtonsPanel, Panel): + bl_label = "Self Collision" + bl_parent_id = 'PHYSICS_PT_cloth_collision' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + cloth = context.cloth.collision_settings + + self.layout.active = cloth_panel_enabled(context.cloth) and cloth.use_self_collision + self.layout.prop(cloth, "use_self_collision", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + cloth = context.cloth.collision_settings + md = context.cloth + ob = context.object + + layout.active = cloth.use_collision and cloth_panel_enabled(md) and cloth.use_self_collision + + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) + + col = flow.column() + col.prop(cloth, "self_collision_quality", text="Quality") + col.prop(cloth, "self_distance_min", slider=True, text="Distance") + + col = flow.column() + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(cloth, "vertex_group_self_collisions", ob, "vertex_groups", text="Vertex Group") + row.label(text="", icon='BLANK1') class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): @@ -191,6 +241,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True md = context.cloth ob = context.object @@ -198,16 +249,27 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): layout.active = (cloth.use_stiffness_scale and cloth_panel_enabled(md)) - split = layout.split() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - col = split.column() - col.label(text="Structural Stiffness:") - col.prop_search(cloth, "vertex_group_structural_stiffness", ob, "vertex_groups", text="") + col = flow.column() + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search( + cloth, "vertex_group_structural_stiffness", ob, "vertex_groups", + text="Structural Group" + ) + row.label(text="", icon='BLANK1') col.prop(cloth, "structural_stiffness_max", text="Max") - col = split.column() - col.label(text="Bending Stiffness:") - col.prop_search(cloth, "vertex_group_bending", ob, "vertex_groups", text="") + col.separator() + + col = flow.column() + row = col.row(align=True) + row.prop_search( + cloth, "vertex_group_bending", ob, "vertex_groups", + text="Bending Group" + ) + row.label(text="", icon='BLANK1') col.prop(cloth, "bending_stiffness_max", text="Max") @@ -225,23 +287,27 @@ class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True md = context.cloth ob = context.object cloth = context.cloth.settings layout.active = (cloth.use_sewing_springs and cloth_panel_enabled(md)) + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - layout.prop(cloth, "sewing_force_max", text="Sewing Force") + col = flow.column() + col.prop(cloth, "sewing_force_max", text="Sewing Force") - split = layout.split() + col.separator() - col = split.column(align=True) - col.label(text="Shrinking:") - col.prop_search(cloth, "vertex_group_shrink", ob, "vertex_groups", text="") + col = col.column() + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(cloth, "vertex_group_shrink", ob, "vertex_groups", text="Shrinking Group") + row.label(text="", icon='BLANK1') - col = split.column(align=True) - col.label() + col = flow.column(align=True) col.prop(cloth, "shrink_min", text="Min") col.prop(cloth, "shrink_max", text="Max") @@ -262,6 +328,8 @@ classes = ( PHYSICS_PT_cloth, PHYSICS_PT_cloth_cache, PHYSICS_PT_cloth_collision, + PHYSICS_PT_cloth_self_collision, + PHYSICS_PT_cloth_pinning, PHYSICS_PT_cloth_stiffness, PHYSICS_PT_cloth_sewing, PHYSICS_PT_cloth_field_weights, diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py index 611f477a31b..3a475c82f5c 100644 --- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py +++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py @@ -87,24 +87,21 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel): col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="") col.operator("dpaint.surface_slot_remove", icon='ZOOMOUT', text="") + layout.use_property_split = True + if surface: layout.prop(surface, "surface_format") col = layout.column() if surface.surface_format != 'VERTEX': - col.label(text="Quality:") col.prop(surface, "image_resolution") col.prop(surface, "use_antialiasing") - col = layout.column() - col.label(text="Frames:") - split = col.split() - - col = split.column(align=True) - col.prop(surface, "frame_start", text="Start") - col.prop(surface, "frame_end", text="End") + sub = col.column(align=True) + sub.prop(surface, "frame_start", text="Frame Start") + sub.prop(surface, "frame_end", text="End") - split.prop(surface, "frame_substeps") + col.prop(surface, "frame_substeps") elif md.ui_type == 'BRUSH': brush = md.brush_settings @@ -114,16 +111,14 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel): else: layout.operator("dpaint.type_toggle", text="Remove Brush", icon='X').type = 'BRUSH' - split = layout.split() + layout.use_property_split = True - col = split.column() + col = layout.column() + col.prop(brush, "paint_color") + col.prop(brush, "paint_alpha", text="Alpha", slider=True) + col.prop(brush, "paint_wetness", text="Wetness", slider=True) col.prop(brush, "use_absolute_alpha") col.prop(brush, "use_paint_erase") - col.prop(brush, "paint_wetness", text="Wetness") - - col = split.column() - col.prop(brush, "paint_color", text="") - col.prop(brush, "paint_alpha", text="Alpha") class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel): @@ -141,65 +136,112 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel): canvas = context.dynamic_paint.canvas_settings surface = canvas.canvas_surfaces.active - surface_type = surface.surface_type + layout.use_property_split = True + layout.prop(surface, "surface_type") + layout.separator() - # dissolve - if surface_type == 'PAINT': - split = layout.split(percentage=0.35) - split.prop(surface, "use_drying", text="Dry:") - - col = split.column() - col.active = surface.use_drying - split = col.split(percentage=0.7) - col = split.column(align=True) - col.prop(surface, "dry_speed", text="Time") - col.prop(surface, "color_dry_threshold") - split.prop(surface, "use_dry_log", text="Slow") - - if surface_type != 'WAVE': - split = layout.split(percentage=0.35) - col = split.column() - if surface_type == 'WEIGHT': - col.prop(surface, "use_dissolve", text="Fade:") - else: - col.prop(surface, "use_dissolve", text="Dissolve:") - col = split.column() - col.active = surface.use_dissolve - split = col.split(percentage=0.7) - split.prop(surface, "dissolve_speed", text="Time") - split.prop(surface, "use_dissolve_log", text="Slow") + col = layout.column() # per type settings if surface_type == 'DISPLACE': - layout.prop(surface, "use_incremental_displace") + col.prop(surface, "use_incremental_displace") if surface.surface_format == 'VERTEX': - row = layout.row() - row.prop(surface, "depth_clamp") - row.prop(surface, "displace_factor") + col.prop(surface, "depth_clamp") + col.prop(surface, "displace_factor") - elif surface_type == 'WAVE': - layout.prop(surface, "use_wave_open_border") + col.separator() - split = layout.split() - - col = split.column(align=True) + elif surface_type == 'WAVE': + col.prop(surface, "use_wave_open_border") col.prop(surface, "wave_timescale") col.prop(surface, "wave_speed") - - col = split.column(align=True) col.prop(surface, "wave_damping") col.prop(surface, "wave_spring") col.prop(surface, "wave_smoothness") - layout.separator() - layout.prop(surface, "brush_group") - row = layout.row() - row.prop(surface, "brush_influence_scale") - row.prop(surface, "brush_radius_scale") + col.separator() + + col.prop(surface, "brush_group") + col.prop(surface, "brush_influence_scale") + col.prop(surface, "brush_radius_scale") + + +class PHYSICS_PT_dp_advanced_canvas_paint_dry(PhysicButtonsPanel, Panel): + bl_label = "Dry" + bl_parent_id = "PHYSICS_PT_dp_advanced_canvas" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + md = context.dynamic_paint + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and surface_type == 'PAINT' and context.engine in cls.COMPAT_ENGINES + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + self.layout.prop(surface, "use_drying", text="") + + def draw(self, context): + layout = self.layout + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + layout.use_property_split = True + + layout.active = surface.use_drying + + col = layout.column() + col.prop(surface, "dry_speed", text="Time") + col.prop(surface, "color_dry_threshold") + col.prop(surface, "use_dry_log", text="Slow") + + +class PHYSICS_PT_dp_advanced_canvas_paint_dissolve(PhysicButtonsPanel, Panel): + bl_label = "Dissolve" + bl_parent_id = "PHYSICS_PT_dp_advanced_canvas" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + md = context.dynamic_paint + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and surface_type != 'WAVE' and context.engine in cls.COMPAT_ENGINES + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + self.layout.prop(surface, "use_dissolve", text="") + + def draw(self, context): + layout = self.layout + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + layout.use_property_split = True + + layout.active = surface.use_dissolve + + col = layout.column() + + col.prop(surface, "dissolve_speed", text="Time") + col.prop(surface, "use_dissolve_log", text="Slow") class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): @@ -220,6 +262,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True canvas = context.dynamic_paint.canvas_settings surface = canvas.canvas_surfaces.active @@ -317,6 +360,8 @@ class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel): surface = canvas.canvas_surfaces.active ob = context.object + layout.use_property_split = True + layout.prop(surface, "init_color_type", expand=False) if surface.init_color_type != 'NONE': layout.separator() @@ -350,37 +395,86 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + +class PHYSICS_PT_dp_effects_spread(PhysicButtonsPanel, Panel): + bl_label = "Spread" + bl_parent_id = "PHYSICS_PT_dp_effects" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): canvas = context.dynamic_paint.canvas_settings surface = canvas.canvas_surfaces.active - layout.row().prop(surface, "effect_ui", expand=True) + self.layout.prop(surface, "use_spread", text="") - if surface.effect_ui == 'SPREAD': - layout.prop(surface, "use_spread") + def draw(self, context): + layout = self.layout - row = layout.row() - row.active = surface.use_spread - row.prop(surface, "spread_speed") - row.prop(surface, "color_spread_speed") + layout.use_property_split = True - elif surface.effect_ui == 'DRIP': - layout.prop(surface, "use_drip") + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + layout.active = surface.use_spread - col = layout.column() - col.active = surface.use_drip - effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT') + col = layout.column() - layout.label(text="Surface Movement:") - row = layout.row() - row.prop(surface, "drip_velocity", slider=True) - row.prop(surface, "drip_acceleration", slider=True) + col.prop(surface, "spread_speed") + col.prop(surface, "color_spread_speed") - elif surface.effect_ui == 'SHRINK': - layout.prop(surface, "use_shrink") - row = layout.row() - row.active = surface.use_shrink - row.prop(surface, "shrink_speed") +class PHYSICS_PT_dp_effects_drip(PhysicButtonsPanel, Panel): + bl_label = "Drip" + bl_parent_id = "PHYSICS_PT_dp_effects" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + + self.layout.prop(surface, "use_drip", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + + layout.active = surface.use_drip + + col = layout.column() + col.prop(surface, "drip_velocity", slider=True) + col.prop(surface, "drip_acceleration", slider=True) + + col.separator() + + effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT') + + +class PHYSICS_PT_dp_effects_shrink(PhysicButtonsPanel, Panel): + bl_label = "Shrink" + bl_parent_id = "PHYSICS_PT_dp_effects" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + + self.layout.prop(surface, "use_shrink", text="") + + def draw(self, context): + layout = self.layout + + layout.use_property_split = True + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + layout.active = surface.use_shrink + + layout.prop(surface, "shrink_speed") class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel): @@ -418,6 +512,7 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True brush = context.dynamic_paint.brush_settings ob = context.object @@ -427,7 +522,7 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): col.prop(brush, "paint_source") if brush.paint_source == 'PARTICLE_SYSTEM': - col.prop_search(brush, "particle_system", ob, "particle_systems", text="") + col.prop_search(brush, "particle_system", ob, "particle_systems") if brush.particle_system: col.label(text="Particle Effect:") sub = col.column() @@ -438,22 +533,19 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}: col.prop(brush, "paint_distance", text="Paint Distance") - split = layout.row().split(percentage=0.4) - sub = split.column() + if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}: - sub.prop(brush, "use_proximity_project") + col.prop(brush, "use_proximity_project") if brush.paint_source == 'VOLUME_DISTANCE': - sub.prop(brush, "invert_proximity") - sub.prop(brush, "use_negative_volume") - - sub = split.column() + col.prop(brush, "invert_proximity") + col.prop(brush, "use_negative_volume") if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}: - column = sub.column() - column.active = brush.use_proximity_project - column.prop(brush, "ray_direction") - sub.prop(brush, "proximity_falloff") + sub = col.column() + sub.active = brush.use_proximity_project + sub.prop(brush, "ray_direction") + col.prop(brush, "proximity_falloff") if brush.proximity_falloff == 'RAMP': - col = layout.row().column() + col.separator() col.prop(brush, "use_proximity_ramp_alpha", text="Only Use Alpha") col.template_color_ramp(brush, "paint_ramp", expand=True) @@ -472,28 +564,45 @@ class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True brush = context.dynamic_paint.brush_settings - split = layout.split() - - col = split.column() + col = layout.column() col.prop(brush, "use_velocity_alpha") col.prop(brush, "use_velocity_color") - - split.prop(brush, "use_velocity_depth") + col.prop(brush, "use_velocity_depth") col = layout.column() col.active = (brush.use_velocity_alpha or brush.use_velocity_color or brush.use_velocity_depth) col.prop(brush, "velocity_max") col.template_color_ramp(brush, "velocity_ramp", expand=True) - layout.separator() - row = layout.row() - row.prop(brush, "use_smudge") - sub = row.row() - sub.active = brush.use_smudge - sub.prop(brush, "smudge_strength") + +class PHYSICS_PT_dp_brush_velocity_smudge(PhysicButtonsPanel, Panel): + bl_label = "Smudge" + bl_parent_id = "PHYSICS_PT_dp_brush_velocity" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + md = context.dynamic_paint + return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + brush = context.dynamic_paint.brush_settings + + self.layout.prop(brush, "use_smudge", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + brush = context.dynamic_paint.brush_settings + + layout.active = brush.use_smudge + layout.prop(brush, "smudge_strength", slider=True) class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel): @@ -509,26 +618,33 @@ class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True brush = context.dynamic_paint.brush_settings layout.prop(brush, "wave_type") if brush.wave_type != 'REFLECT': - row = layout.row() - row.prop(brush, "wave_factor") - row.prop(brush, "wave_clamp") + col = layout.column() + col.prop(brush, "wave_factor") + col.prop(brush, "wave_clamp") classes = ( PHYSICS_UL_dynapaint_surfaces, PHYSICS_PT_dynamic_paint, PHYSICS_PT_dp_advanced_canvas, + PHYSICS_PT_dp_advanced_canvas_paint_dry, + PHYSICS_PT_dp_advanced_canvas_paint_dissolve, PHYSICS_PT_dp_canvas_output, PHYSICS_PT_dp_canvas_initial_color, PHYSICS_PT_dp_effects, + PHYSICS_PT_dp_effects_spread, + PHYSICS_PT_dp_effects_drip, + PHYSICS_PT_dp_effects_shrink, PHYSICS_PT_dp_cache, PHYSICS_PT_dp_brush_source, PHYSICS_PT_dp_brush_velocity, + PHYSICS_PT_dp_brush_velocity_smudge, PHYSICS_PT_dp_brush_wave, ) diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index 013822793de..d121b6a389d 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -39,20 +39,22 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object rbo = ob.rigid_body if rbo is not None: layout.prop(rbo, "type", text="Type") - row = layout.row() - if rbo.type == 'ACTIVE': - row.prop(rbo, "enabled", text="Dynamic") - row.prop(rbo, "kinematic", text="Animated") if rbo.type == 'ACTIVE': layout.prop(rbo, "mass") + col = layout.column() + if rbo.type == 'ACTIVE': + col.prop(rbo, "enabled", text="Dynamic") + col.prop(rbo, "kinematic", text="Animated") + class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): bl_label = "Collisions" @@ -70,6 +72,7 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): ob = context.object rbo = ob.rigid_body + layout.use_property_split = True layout.prop(rbo, "collision_shape", text="Shape") @@ -79,15 +82,52 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): if rbo.collision_shape == 'MESH' and rbo.mesh_source == 'DEFORM': layout.prop(rbo, "use_deform", text="Deforming") - split = layout.split() - col = split.column() - col.label(text="Surface Response:") +class PHYSICS_PT_rigid_body_collisions_surface(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Surface Response" + bl_parent_id = 'PHYSICS_PT_rigid_body_collisions' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + (context.engine in cls.COMPAT_ENGINES)) + + def draw(self, context): + layout = self.layout + + ob = context.object + rbo = ob.rigid_body + layout.use_property_split = True + + col = layout.column() col.prop(rbo, "friction") col.prop(rbo, "restitution", text="Bounciness") - col = split.column() - col.label(text="Sensitivity:") + +class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Sensitivity" + bl_parent_id = 'PHYSICS_PT_rigid_body_collisions' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + (context.engine in cls.COMPAT_ENGINES)) + + def draw(self, context): + layout = self.layout + + ob = context.object + rbo = ob.rigid_body + layout.use_property_split = True + + col = layout.column() + if rbo.collision_shape in {'MESH', 'CONE'}: col.prop(rbo, "collision_margin", text="Margin") else: @@ -96,7 +136,26 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): sub.active = rbo.use_margin sub.prop(rbo, "collision_margin", text="Margin") - layout.prop(rbo, "collision_groups") + +class PHYSICS_PT_rigid_body_collisions_collections(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Collision Collections" + bl_parent_id = 'PHYSICS_PT_rigid_body_collisions' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + (context.engine in cls.COMPAT_ENGINES)) + + def draw(self, context): + layout = self.layout + + ob = context.object + rbo = ob.rigid_body + + layout.prop(rbo, "collision_groups", text="") class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): @@ -114,6 +173,7 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object rbo = ob.rigid_body @@ -122,28 +182,53 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): # col.label(text="Activation:") # XXX: settings such as activate on collison/etc. - split = layout.split() + col = layout.column() + col.prop(rbo, "linear_damping", text="Translation Damping") + col.prop(rbo, "angular_damping", text="Rotation Damping") - col = split.column() - col.label(text="Deactivation:") - col.prop(rbo, "use_deactivation") - sub = col.column() - sub.active = rbo.use_deactivation - sub.prop(rbo, "use_start_deactivated") - sub.prop(rbo, "deactivate_linear_velocity", text="Linear Vel") - sub.prop(rbo, "deactivate_angular_velocity", text="Angular Vel") - # TODO: other params such as time? - col = split.column() - col.label(text="Damping:") - col.prop(rbo, "linear_damping", text="Translation") - col.prop(rbo, "angular_damping", text="Rotation") +class PHYSICS_PT_rigid_body_dynamics_deactivation(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Deactivation" + bl_parent_id = 'PHYSICS_PT_rigid_body_dynamics' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + obj.rigid_body.type == 'ACTIVE' and + (context.engine in cls.COMPAT_ENGINES)) + + def draw_header(self, context): + ob = context.object + rbo = ob.rigid_body + self.layout.prop(rbo, "use_deactivation", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + rbo = ob.rigid_body + + layout.active = rbo.use_deactivation + + col = layout.column() + col.prop(rbo, "use_start_deactivated") + col.prop(rbo, "deactivate_linear_velocity", text="Linear Velocity") + col.prop(rbo, "deactivate_angular_velocity", text="Angular Velocity") + # TODO: other params such as time? classes = ( PHYSICS_PT_rigid_body, PHYSICS_PT_rigid_body_collisions, + PHYSICS_PT_rigid_body_collisions_surface, + PHYSICS_PT_rigid_body_collisions_sensitivity, + PHYSICS_PT_rigid_body_collisions_collections, PHYSICS_PT_rigid_body_dynamics, + PHYSICS_PT_rigid_body_dynamics_deactivation, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py index 69491f36c63..5e67caadc90 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py @@ -139,6 +139,11 @@ class PHYSICS_PT_rigid_body_constraint(PHYSICS_PT_rigidbody_constraint_panel, Pa sub.prop(rbc, "motor_ang_max_impulse", text="Max Impulse") elif rbc.type in {'GENERIC', 'GENERIC_SPRING'}: + if rbc.type == 'GENERIC_SPRING': + row = layout.row() + row.label("Spring Type:") + row.prop(rbc, "spring_type", text="") + col = layout.column(align=True) col.label("Limits:") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index b1c5edf97e7..2b91eec67c4 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -120,7 +120,7 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): return args @staticmethod - def draw_framerate(sub, rd): + def draw_framerate(layout, sub, rd): if RENDER_PT_dimensions._preset_class is None: RENDER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets @@ -130,8 +130,9 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): sub.menu("RENDER_MT_framerate_presets", text=fps_label_text) if show_framerate: - sub.prop(rd, "fps") - sub.prop(rd, "fps_base", text="/") + col = layout.column(align=True) + col.prop(rd, "fps") + col.prop(rd, "fps_base", text="Base") def draw(self, context): layout = self.layout @@ -161,10 +162,10 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): col.prop(scene, "frame_end", text="End") col.prop(scene, "frame_step", text="Step") - col = layout.split(percentage=0.5) + col = layout.split() col.alignment = 'RIGHT' col.label(text="Frame Rate") - self.draw_framerate(col, rd) + self.draw_framerate(layout, col, rd) class RENDER_PT_frame_remapping(RenderButtonsPanel, Panel): @@ -218,23 +219,35 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel): split = layout.split() col = split.column(align=True) - col.prop(rd, "use_stamp_time", text="Time") col.prop(rd, "use_stamp_date", text="Date") - col.prop(rd, "use_stamp_render_time", text="RenderTime") + col.prop(rd, "use_stamp_time", text="Time") + + col.separator() + + col.prop(rd, "use_stamp_render_time", text="Render Time") col.prop(rd, "use_stamp_frame", text="Frame") - col.prop(rd, "use_stamp_scene", text="Scene") + col.prop(rd, "use_stamp_frame_range", text="Frame Range") col.prop(rd, "use_stamp_memory", text="Memory") col = split.column(align=True) col.prop(rd, "use_stamp_camera", text="Camera") col.prop(rd, "use_stamp_lens", text="Lens") - col.prop(rd, "use_stamp_filename", text="Filename") - col.prop(rd, "use_stamp_frame_range", text="Frame range") + + col.separator() + + col.prop(rd, "use_stamp_scene", text="Scene") col.prop(rd, "use_stamp_marker", text="Marker") - col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip") + + col.separator() + + col.prop(rd, "use_stamp_filename", text="Filename") + + col.separator() + + col.prop(rd, "use_stamp_sequencer_strip", text="Strip Name") if rd.use_sequencer: - col.prop(rd, "use_stamp_strip_meta", text="Sequence Strip") + col.prop(rd, "use_stamp_strip_meta", text="Use Strip Metadata") row = layout.split(percentage=0.3) row.prop(rd, "use_stamp_note", text="Note") @@ -594,8 +607,6 @@ class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel): sub = col.column() sub.active = props.use_volumetric_shadows sub.prop(props, "volumetric_shadow_samples", text="Shadow Samples") - col.separator() - col.prop(props, "use_volumetric_colored_transmittance") class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 38bfc6ad294..e324e7a9882 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -568,6 +568,35 @@ class SCENE_PT_simplify_render(SceneButtonsPanel, Panel): col.prop(rd, "simplify_child_particles_render", text="Max Child Particles") +class SCENE_PT_simplify_greasepencil(SceneButtonsPanel, Panel): + bl_label = "Grease Pencil" + bl_parent_id = "SCENE_PT_simplify" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'} + bl_options = {'DEFAULT_CLOSED'} + + def draw_header(self, context): + rd = context.scene.render + self.layout.prop(rd, "simplify_gpencil", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + rd = context.scene.render + + layout.active = rd.simplify_gpencil + + col = layout.column() + col.prop(rd, "simplify_gpencil_onplay", text="Playback Only") + col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers") + + col = layout.column(align=True) + col.prop(rd, "simplify_gpencil_view_fill") + sub = col.column() + sub.active = rd.simplify_gpencil_view_fill + sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines") + + class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "scene" @@ -593,6 +622,7 @@ classes = ( SCENE_PT_simplify, SCENE_PT_simplify_viewport, SCENE_PT_simplify_render, + SCENE_PT_simplify_greasepencil, SCENE_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index d937f2470b8..a4f6f753669 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -17,19 +17,21 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> -import bpy -from bpy.types import Menu, Panel, UIList +import bpy +from bpy.types import ( + Menu, + Panel, + UIList, +) from bpy.types import ( Brush, FreestyleLineStyle, - Object, ParticleSettings, Texture, ) from rna_prop_ui import PropertyPanel - from .properties_paint_common import brush_texture_settings @@ -47,9 +49,9 @@ class TEXTURE_MT_specials(Menu): class TEXTURE_UL_texslots(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - ma = data slot = item tex = slot.texture if slot else None + if self.layout_type in {'DEFAULT', 'COMPACT'}: if tex: layout.prop(tex, "name", text="", emboss=False, icon_value=icon) @@ -131,18 +133,18 @@ class TEXTURE_PT_context(TextureButtonsPanel, Panel): if not pin_id: col.template_texture_user() - col.separator() - if user or pin_id: + col.separator() + if pin_id: col.template_ID(space, "pin_id") else: propname = context.texture_user_property.identifier col.template_ID(user, propname, new="texture.new") - col.separator() - if tex: + col.separator() + split = col.split(percentage=0.2) split.label(text="Type") split.prop(tex, "type", text="") @@ -179,25 +181,35 @@ class TEXTURE_PT_node_mapping(TextureButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) node = context.texture_node mapping = node.texture_mapping - layout.prop(mapping, "vector_type", expand=True) + col = flow.column() + col.prop(mapping, "vector_type") + + col.separator() + + col = col.column(align=True) + col.prop(mapping, "mapping_x", text="Projection X") + col.prop(mapping, "mapping_y", text="Y") + col.prop(mapping, "mapping_z", text="Z") - row = layout.row() + col.separator() - row.column().prop(mapping, "translation") - row.column().prop(mapping, "rotation") - row.column().prop(mapping, "scale") + col = flow.column() + col.column().prop(mapping, "translation") - layout.label(text="Projection:") + col = flow.column() + col.column().prop(mapping, "rotation") - row = layout.row() - row.prop(mapping, "mapping_x", text="") - row.prop(mapping, "mapping_y", text="") - row.prop(mapping, "mapping_z", text="") + col = flow.column() + col.column().prop(mapping, "scale") class TextureTypePanel(TextureButtonsPanel): @@ -216,21 +228,29 @@ class TEXTURE_PT_clouds(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.row().prop(tex, "cloud_type", expand=True) - layout.label(text="Noise:") - layout.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() + + col.prop(tex, "noise_type", text="Type") + + col.separator() - split = layout.split() + col = flow.column() + col.prop(tex, "cloud_type") - col = split.column() + col.separator() + + col = flow.column() col.prop(tex, "noise_scale", text="Size") col.prop(tex, "noise_depth", text="Depth") - - split.prop(tex, "nabla", text="Nabla") + col.prop(tex, "nabla", text="Nabla") class TEXTURE_PT_wood(TextureTypePanel, Panel): @@ -240,26 +260,34 @@ class TEXTURE_PT_wood(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=False) tex = context.texture - layout.row().prop(tex, "noise_basis_2", expand=True) - layout.row().prop(tex, "wood_type", expand=True) + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") - col = layout.column() - col.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} - col.label(text="Noise:") - col.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col.separator() - split = layout.split() - split.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} + col.prop(tex, "wood_type") - col = split.column() - col.prop(tex, "noise_scale", text="Size") - col.prop(tex, "turbulence") + col.separator() - split.prop(tex, "nabla") + col = flow.column() + col.prop(tex, "noise_basis_2", text="Second Basis") + + col = col.column() + col.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} + col.prop(tex, "noise_type", text="Type") + + col.separator() + + sub = flow.column() + sub.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} + sub.prop(tex, "noise_scale", text="Size") + sub.prop(tex, "turbulence") + sub.prop(tex, "nabla") class TEXTURE_PT_marble(TextureTypePanel, Panel): @@ -269,22 +297,29 @@ class TEXTURE_PT_marble(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.row().prop(tex, "marble_type", expand=True) - layout.row().prop(tex, "noise_basis_2", expand=True) - layout.label(text="Noise:") - layout.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() + + col.prop(tex, "marble_type") - split = layout.split() + col.separator() - col = split.column() + col = flow.column() + col.prop(tex, "noise_basis_2", text="Second Basis") + col.prop(tex, "noise_type", text="Type") + + col.separator() + + col = flow.column() col.prop(tex, "noise_scale", text="Size") col.prop(tex, "noise_depth", text="Depth") - - col = split.column() col.prop(tex, "turbulence") col.prop(tex, "nabla") @@ -296,12 +331,16 @@ class TEXTURE_PT_magic(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - row = layout.row() - row.prop(tex, "noise_depth", text="Depth") - row.prop(tex, "turbulence") + col = flow.column() + col.prop(tex, "noise_depth", text="Depth") + + col = flow.column() + col.prop(tex, "turbulence") class TEXTURE_PT_blend(TextureTypePanel, Panel): @@ -311,15 +350,19 @@ class TEXTURE_PT_blend(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.prop(tex, "progression") + col = flow.column() + col.prop(tex, "progression") - sub = layout.row() + col.separator() - sub.active = (tex.progression in {'LINEAR', 'QUADRATIC', 'EASING', 'RADIAL'}) - sub.prop(tex, "use_flip_axis", expand=True) + col = flow.column() + col.active = (tex.progression in {'LINEAR', 'QUADRATIC', 'EASING', 'RADIAL'}) + col.prop(tex, "use_flip_axis", text="Orientation") class TEXTURE_PT_stucci(TextureTypePanel, Panel): @@ -329,17 +372,28 @@ class TEXTURE_PT_stucci(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - layout.row().prop(tex, "stucci_type", expand=True) - layout.label(text="Noise:") - layout.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() - row = layout.row() - row.prop(tex, "noise_scale", text="Size") - row.prop(tex, "turbulence") + col.row().prop(tex, "stucci_type") + + col.separator() + + col = flow.column() + col.prop(tex, "noise_type", text="Type") + + col.separator() + + col = flow.column() + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "turbulence") class TEXTURE_PT_image(TextureTypePanel, Panel): @@ -348,6 +402,18 @@ class TEXTURE_PT_image(TextureTypePanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): + # TODO: maybe expose the template_ID from the template image here. + layout = self.layout + del layout + + +class TEXTURE_PT_image_settings(TextureTypePanel, Panel): + bl_label = "Settings" + bl_parent_id = 'TEXTURE_PT_image' + tex_type = 'IMAGE' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): layout = self.layout tex = context.texture @@ -356,11 +422,13 @@ class TEXTURE_PT_image(TextureTypePanel, Panel): def texture_filter_common(tex, layout): layout.prop(tex, "filter_type", text="Filter Type") + if tex.use_mipmap and tex.filter_type in {'AREA', 'EWA', 'FELINE'}: + col = layout.column() if tex.filter_type == 'FELINE': - layout.prop(tex, "filter_lightprobes", text="Light Probes") + col.prop(tex, "filter_lightprobes", text="Light Probes") else: - layout.prop(tex, "filter_eccentricity", text="Eccentricity") + col.prop(tex, "filter_eccentricity", text="Eccentricity") layout.prop(tex, "filter_size", text="Size") layout.prop(tex, "use_filter_size_min", text="Minimum Size") @@ -376,14 +444,11 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): def draw(self, context): layout = self.layout layout.use_property_split = True - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - idblock = context_tex_datablock(context) tex = context.texture - slot = getattr(context, "texture_slot", None) col = flow.column() - col.prop(tex, "use_flip_axis", text="Flip X/Y Axis") col.prop(tex, "use_interpolation") col.separator() @@ -396,8 +461,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): col.separator() - col = flow.column() - texture_filter_common(tex, col) + texture_filter_common(tex, flow) class TEXTURE_PT_image_alpha(TextureTypePanel, Panel): @@ -433,43 +497,70 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, Panel): def draw(self, context): layout = self.layout layout.use_property_split = True - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - col = flow.column() - col.prop(tex, "extension") + col = layout.column() + col.prop(tex, "use_flip_axis", text="Flip Axes") + + col.separator() + + subcol = layout.column() + subcol.prop(tex, "extension") # use layout, to keep the same location in case of button cycling. + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) if tex.extension == 'REPEAT': + + col = flow.column() sub = col.column(align=True) sub.prop(tex, "repeat_x", text="Repeat X") sub.prop(tex, "repeat_y", text="Y") + col = flow.column() sub = col.column() - sub.prop(tex, "use_mirror_x", text="Mirror X") sub.active = (tex.repeat_x > 1) + sub.prop(tex, "use_mirror_x", text="Mirror X") sub = col.column() - sub.prop(tex, "use_mirror_y", text="Y") sub.active = (tex.repeat_y > 1) + sub.prop(tex, "use_mirror_y", text="Y") elif tex.extension == 'CHECKER': - col = layout.column(align=True) - col.prop(tex, "use_checker_even", text="Even") - col.prop(tex, "use_checker_odd", text="Odd") + subcol.separator() - col = layout.column() + col = flow.column() col.prop(tex, "checker_distance", text="Distance") - col = flow.column() - sub = col.column(align=True) + col = flow.column() + col.prop(tex, "use_checker_even", text="Tiles Even") + col.prop(tex, "use_checker_odd", text="Odd") + else: + del flow + + +class TEXTURE_PT_image_mapping_crop(TextureTypePanel, Panel): + bl_label = "Crop" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'TEXTURE_PT_image_mapping' + tex_type = 'IMAGE' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + tex = context.texture + + col = flow.column(align=True) # col.prop(tex, "crop_rectangle") - sub.prop(tex, "crop_min_x", text="Crop Minimum X") - sub.prop(tex, "crop_min_y", text="Y") + col.prop(tex, "crop_min_x", text="Minimum X") + col.prop(tex, "crop_min_y", text="Y") - sub = col.column(align=True) - sub.prop(tex, "crop_max_x", text="Crop Maximum X") - sub.prop(tex, "crop_max_y", text="Y") + col = flow.column(align=True) + col.prop(tex, "crop_max_x", text="Maximum X") + col.prop(tex, "crop_max_y", text="Y") class TEXTURE_PT_musgrave(TextureTypePanel, Panel): @@ -479,34 +570,43 @@ class TEXTURE_PT_musgrave(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.prop(tex, "musgrave_type") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() + + col.prop(tex, "musgrave_type") + + col.separator() + + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "nabla") - split = layout.split() + col.separator() - col = split.column() + col = flow.column() col.prop(tex, "dimension_max", text="Dimension") col.prop(tex, "lacunarity") col.prop(tex, "octaves") + col.separator() + musgrave_type = tex.musgrave_type - col = split.column() + + col = flow.column() + if musgrave_type in {'HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}: col.prop(tex, "offset") col.prop(tex, "noise_intensity", text="Intensity") + if musgrave_type in {'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}: col.prop(tex, "gain") - layout.label(text="Noise:") - - layout.prop(tex, "noise_basis", text="Basis") - - row = layout.row() - row.prop(tex, "noise_scale", text="Size") - row.prop(tex, "nabla") - class TEXTURE_PT_voronoi(TextureTypePanel, Panel): bl_label = "Voronoi" @@ -515,33 +615,51 @@ class TEXTURE_PT_voronoi(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - split = layout.split() + col = flow.column() + col.prop(tex, "distance_metric") - col = split.column() - col.label(text="Distance Metric:") - col.prop(tex, "distance_metric", text="") sub = col.column() sub.active = tex.distance_metric == 'MINKOVSKY' sub.prop(tex, "minkovsky_exponent", text="Exponent") - col.label(text="Coloring:") - col.prop(tex, "color_mode", text="") + + sub.separator() + + col = flow.column() + col.prop(tex, "color_mode") col.prop(tex, "noise_intensity", text="Intensity") - col = split.column() - sub = col.column(align=True) - sub.label(text="Feature Weights:") - sub.prop(tex, "weight_1", text="1", slider=True) - sub.prop(tex, "weight_2", text="2", slider=True) - sub.prop(tex, "weight_3", text="3", slider=True) - sub.prop(tex, "weight_4", text="4", slider=True) + col.separator() + + col = flow.column() + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "nabla") + + +class TEXTURE_PT_voronoi_feature_weights(TextureTypePanel, Panel): + bl_label = "Feature Weights" + bl_parent_id = "TEXTURE_PT_voronoi" + tex_type = 'VORONOI' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) + + tex = context.texture - layout.label(text="Noise:") - row = layout.row() - row.prop(tex, "noise_scale", text="Size") - row.prop(tex, "nabla") + col = flow.column(align=True) + col.prop(tex, "weight_1", text="First", slider=True) + col.prop(tex, "weight_2", text="Second", slider=True) + + sub = flow.column(align=True) + sub.prop(tex, "weight_3", text="Third", slider=True) + sub.prop(tex, "weight_4", text="Fourth", slider=True) class TEXTURE_PT_distortednoise(TextureTypePanel, Panel): @@ -551,19 +669,24 @@ class TEXTURE_PT_distortednoise(TextureTypePanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.prop(tex, "noise_distortion") - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") - split = layout.split() + col.separator() - col = split.column() - col.prop(tex, "distortion", text="Distortion") - col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "noise_distortion", text="Distortion") - split.prop(tex, "nabla") + col.separator() + + col = flow.column() + col.prop(tex, "distortion", text="Amount") + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "nabla") class TextureSlotPanel(TextureButtonsPanel): @@ -595,68 +718,64 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) idblock = context_tex_datablock(context) tex = context.texture_slot - if not isinstance(idblock, Brush): - split = layout.split(percentage=0.3) - col = split.column() - col.label(text="Coordinates:") - col = split.column() - col.prop(tex, "texture_coords", text="") + if isinstance(idblock, Brush): + if context.sculpt_object or context.image_paint_object: + brush_texture_settings(layout, idblock, context.sculpt_object) + else: + col = flow.column() - if tex.texture_coords == 'ORCO': - """ - ob = context.object - if ob and ob.type == 'MESH': - split = layout.split(percentage=0.3) - split.label(text="Mesh:") - split.prop(ob.data, "texco_mesh", text="") - """ - elif tex.texture_coords == 'UV': - split = layout.split(percentage=0.3) - split.label(text="Map:") + col.prop(tex, "texture_coords", text="Coordinates") + + # Note: the ORCO case used to call ob.data, "texco_mesh" prop. + if tex.texture_coords == 'UV': ob = context.object + if ob and ob.type == 'MESH': - split.prop_search(tex, "uv_layer", ob.data, "uv_layers", text="") + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(tex, "uv_layer", ob.data, "uv_layers", text="Map") + row.label(text="", icon='BLANK1') else: - split.prop(tex, "uv_layer", text="") + col.prop(tex, "uv_layer", text="Map") elif tex.texture_coords == 'OBJECT': - split = layout.split(percentage=0.3) - split.label(text="Object:") - split.prop(tex, "object", text="") + col.prop(tex, "object", text="Object") elif tex.texture_coords == 'ALONG_STROKE': - split = layout.split(percentage=0.3) - split.label(text="Use Tips:") - split.prop(tex, "use_tips", text="") + col.prop(tex, "use_tips", text="Use Tips") + + col.separator() - if isinstance(idblock, Brush): - if context.sculpt_object or context.image_paint_object: - brush_texture_settings(layout, idblock, context.sculpt_object) - else: if isinstance(idblock, FreestyleLineStyle): - split = layout.split(percentage=0.3) - split.label(text="Projection:") - split.prop(tex, "mapping", text="") + col = flow.column() + col.prop(tex, "mapping", text="Projection") + + col.separator() + + col = flow.column() + col.prop(tex, "mapping_x", text="Mapping X") + col.prop(tex, "mapping_y", text="Y") + col.prop(tex, "mapping_z", text="Z") - split = layout.split(percentage=0.3) - split.separator() - row = split.row() - row.prop(tex, "mapping_x", text="") - row.prop(tex, "mapping_y", text="") - row.prop(tex, "mapping_z", text="") + col.separator() - row = layout.row() - row.column().prop(tex, "offset") - row.column().prop(tex, "scale") + col = flow.column(align=True) + col.column().prop(tex, "offset") + + col = flow.column(align=True) + col.column().prop(tex, "scale") class TEXTURE_PT_influence(TextureSlotPanel, Panel): bl_label = "Influence" + bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod @@ -672,107 +791,126 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel): return (engine in cls.COMPAT_ENGINES) def draw(self, context): - layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False) idblock = context_tex_datablock(context) - tex = context.texture_slot def factor_but(layout, toggle, factor, name): row = layout.row(align=True) - row.prop(tex, toggle, text="") + row.active = getattr(tex, toggle) + + row.prop(tex, factor, text=name, slider=True) sub = row.row(align=True) - sub.active = getattr(tex, toggle) - sub.prop(tex, factor, text=name, slider=True) + sub.prop(tex, toggle, text="") return sub # XXX, temp. use_map_normal needs to override. if isinstance(idblock, ParticleSettings): - split = layout.split() - - col = split.column() - col.label(text="General:") - factor_but(col, "use_map_time", "time_factor", "Time") + col = flow.column() + factor_but(col, "use_map_time", "time_factor", "General Time") factor_but(col, "use_map_life", "life_factor", "Lifetime") factor_but(col, "use_map_density", "density_factor", "Density") factor_but(col, "use_map_size", "size_factor", "Size") - col = split.column() - col.label(text="Physics:") - factor_but(col, "use_map_velocity", "velocity_factor", "Velocity") + col.separator() + + col = flow.column() + factor_but(col, "use_map_velocity", "velocity_factor", "Physics Velocity") factor_but(col, "use_map_damp", "damp_factor", "Damp") factor_but(col, "use_map_gravity", "gravity_factor", "Gravity") factor_but(col, "use_map_field", "field_factor", "Force Fields") - layout.label(text="Hair:") - - split = layout.split() + col.separator() - col = split.column() - factor_but(col, "use_map_length", "length_factor", "Length") + col = flow.column() + factor_but(col, "use_map_length", "length_factor", "Hair Length") factor_but(col, "use_map_clump", "clump_factor", "Clump") factor_but(col, "use_map_twist", "twist_factor", "Twist") - col = split.column() + col = flow.column() factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude") factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency") factor_but(col, "use_map_rough", "rough_factor", "Rough") elif isinstance(idblock, FreestyleLineStyle): - split = layout.split() - - col = split.column() + col = flow.column() factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") - col = split.column() factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") - layout.separator() - if not isinstance(idblock, ParticleSettings): - split = layout.split() + col = flow.column() - col = split.column() col.prop(tex, "blend_type", text="Blend") col.prop(tex, "use_rgb_to_intensity") + # color is used on gray-scale textures even when use_rgb_to_intensity is disabled. col.prop(tex, "color", text="") - col = split.column() + col = flow.column() col.prop(tex, "invert", text="Negative") col.prop(tex, "use_stencil") -class TEXTURE_PT_colors(TextureButtonsPanel, Panel): - bl_label = "Colors" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - +class TextureColorsPoll: @classmethod def poll(cls, context): tex = context.texture return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES) + +class TEXTURE_PT_colors(TextureButtonsPanel, TextureColorsPoll, Panel): + bl_label = "Colors" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + def draw(self, context): layout = self.layout layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False) tex = context.texture - col = layout.column() - sub = col.column(align=True) - sub.prop(tex, "factor_red", text="Multiply R") - sub.prop(tex, "factor_green", text="G") - sub.prop(tex, "factor_blue", text="B") + col = flow.column() + col.prop(tex, "use_clamp", text="Clamp") + + col = flow.column(align=True) + col.prop(tex, "factor_red", text="Multiply R") + col.prop(tex, "factor_green", text="G") + col.prop(tex, "factor_blue", text="B") + col.separator() + + col = flow.column() col.prop(tex, "intensity") col.prop(tex, "contrast") col.prop(tex, "saturation") - col.prop(tex, "use_clamp", text="Clamp") - col.prop(tex, "use_color_ramp", text="Ramp") - if tex.use_color_ramp: - layout.use_property_split = False + +class TEXTURE_PT_colors_ramp(TextureButtonsPanel, TextureColorsPoll, Panel): + bl_label = "Color Ramp" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'TEXTURE_PT_colors' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + tex = context.texture + self.layout.prop(tex, "use_color_ramp", text="") + + def draw(self, context): + layout = self.layout + + tex = context.texture + + # Note: TODO after creation of a new texture, the template_color_ramp will be blank. + # Possibly needs to be fixed in the template itself. + is_active = bool(tex and tex.use_color_ramp) + if is_active: layout.template_color_ramp(tex, "color_ramp", expand=True) + else: + layout.alignment = 'RIGHT' + layout.label("Please enable the Color Ramp first") class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel): @@ -792,8 +930,6 @@ classes = ( TEXTURE_PT_context, TEXTURE_PT_node, TEXTURE_PT_node_mapping, - TEXTURE_PT_mapping, - TEXTURE_PT_influence, TEXTURE_PT_clouds, TEXTURE_PT_wood, TEXTURE_PT_marble, @@ -801,13 +937,19 @@ classes = ( TEXTURE_PT_blend, TEXTURE_PT_stucci, TEXTURE_PT_image, + TEXTURE_PT_image_settings, TEXTURE_PT_image_alpha, - TEXTURE_PT_image_sampling, TEXTURE_PT_image_mapping, + TEXTURE_PT_image_mapping_crop, + TEXTURE_PT_image_sampling, TEXTURE_PT_musgrave, TEXTURE_PT_voronoi, + TEXTURE_PT_voronoi_feature_weights, TEXTURE_PT_distortednoise, + TEXTURE_PT_influence, + TEXTURE_PT_mapping, TEXTURE_PT_colors, + TEXTURE_PT_colors_ramp, TEXTURE_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 23c3e97ac9a..1564204c613 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -24,12 +24,7 @@ from bpy.app.translations import pgettext_iface as iface_ from bl_operators.presets import PresetMenu from .properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, - GreasePencilStrokeEditPanel, - GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel, GreasePencilDataPanel, - GreasePencilPaletteColorPanel, ) @@ -1154,39 +1149,10 @@ class CLIP_PT_grease_pencil(GreasePencilDataPanel, CLIP_PT_clip_view_panel, Pane # But, this should only be visible in "clip" view -# Grease Pencil palette colors -class CLIP_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, CLIP_PT_clip_view_panel, Panel): - bl_space_type = 'CLIP_EDITOR' - bl_region_type = 'UI' - bl_options = {'DEFAULT_CLOSED'} - - # NOTE: this is just a wrapper around the generic GP Panel - # But, this should only be visible in "clip" view - - # Grease Pencil drawing tools class CLIP_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil stroke editing tools -class CLIP_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): - bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil stroke sculpting tools -class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil drawing brushes -class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil drawing curves -class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): - bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'TOOLS' class CLIP_MT_view(Menu): @@ -1515,12 +1481,7 @@ classes = ( CLIP_PT_footage_info, CLIP_PT_tools_scenesetup, CLIP_PT_grease_pencil, - CLIP_PT_grease_pencil_palettecolor, CLIP_PT_tools_grease_pencil_draw, - CLIP_PT_tools_grease_pencil_edit, - CLIP_PT_tools_grease_pencil_sculpt, - CLIP_PT_tools_grease_pencil_brush, - CLIP_PT_tools_grease_pencil_brushcurves, CLIP_MT_view, CLIP_MT_clip, CLIP_MT_proxy, diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 9d903829bbb..a85dd591b2f 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -56,6 +56,8 @@ class FILEBROWSER_HT_header(Header): layout.separator_spacer() + layout.template_running_jobs() + if params: layout.prop(params, "use_filter", text="", icon='FILTER') @@ -86,8 +88,6 @@ class FILEBROWSER_HT_header(Header): row.separator() row.prop(params, "filter_search", text="", icon='VIEWZOOM') - layout.template_running_jobs() - class FILEBROWSER_UL_dir(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 1303e46ab6c..7a1d4117451 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -28,12 +28,7 @@ from .properties_paint_common import ( ) from .properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, - GreasePencilStrokeEditPanel, - GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel, GreasePencilDataPanel, - GreasePencilPaletteColorPanel, ) from bpy.app.translations import pgettext_iface as iface_ @@ -1346,38 +1341,12 @@ class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel): # NOTE: this is just a wrapper around the generic GP Panel - -# Grease Pencil palette colors -class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - - # Grease Pencil drawing tools -class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - - -# Grease Pencil stroke editing tools -class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - - -# Grease Pencil stroke sculpting tools -class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' -# Grease Pencil drawing brushes -class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - - -# Grease Pencil drawing curves -class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): +class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_space_type = 'IMAGE_EDITOR' + bl_region_type = 'TOOLS' classes = ( @@ -1430,12 +1399,7 @@ classes = ( IMAGE_PT_sample_line, IMAGE_PT_scope_sample, IMAGE_PT_grease_pencil, - IMAGE_PT_grease_pencil_palettecolor, IMAGE_PT_tools_grease_pencil_draw, - IMAGE_PT_tools_grease_pencil_edit, - IMAGE_PT_tools_grease_pencil_sculpt, - IMAGE_PT_tools_grease_pencil_brush, - IMAGE_PT_tools_grease_pencil_brushcurves, ) 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 9d8c14ba9c3..43a124cd48f 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -24,13 +24,8 @@ from bpy.app.translations import pgettext_iface as iface_ from bl_operators.presets import PresetMenu from .properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, - GreasePencilStrokeEditPanel, - GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel, GreasePencilDataPanel, - GreasePencilPaletteColorPanel, - GreasePencilToolsPanel + GreasePencilToolsPanel, ) @@ -364,7 +359,6 @@ class NODE_PT_active_node_generic(Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' bl_label = "Node" -# bl_options = {'HIDE_HEADER'} @classmethod def poll(cls, context): @@ -383,6 +377,7 @@ class NODE_PT_active_node_color(Panel): bl_region_type = 'UI' bl_label = "Color" bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'NODE_PT_active_node_generic' @classmethod def poll(cls, context): @@ -410,6 +405,8 @@ class NODE_PT_active_node_properties(Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' bl_label = "Properties" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'NODE_PT_active_node_generic' @classmethod def poll(cls, context): @@ -453,18 +450,22 @@ class NODE_PT_backdrop(Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True snode = context.space_data layout.active = snode.show_backdrop - layout.prop(snode, "backdrop_channels", text="") - layout.prop(snode, "backdrop_zoom", text="Zoom") - col = layout.column(align=True) - col.label(text="Offset:") - col.prop(snode, "backdrop_offset", text="") - col.operator("node.backimage_move", text="Move") + col = layout.column() - layout.operator("node.backimage_fit", text="Fit") + col.prop(snode, "backdrop_channels", text="Channels") + col.prop(snode, "backdrop_zoom", text="Zoom") + + col.prop(snode, "backdrop_offset", text="Offset") + + col.separator() + + col.operator("node.backimage_move", text="Move") + col.operator("node.backimage_fit", text="Fit") class NODE_PT_quality(bpy.types.Panel): @@ -479,6 +480,7 @@ class NODE_PT_quality(bpy.types.Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True snode = context.space_data tree = snode.node_tree @@ -522,19 +524,7 @@ class NODE_UL_interface_sockets(bpy.types.UIList): class NODE_PT_grease_pencil(GreasePencilDataPanel, Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - - @classmethod - def poll(cls, context): - snode = context.space_data - return snode is not None and snode.node_tree is not None - - -# Grease Pencil palette colors -class NODE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'UI' + bl_options = {'DEFAULT_CLOSED'} # NOTE: this is just a wrapper around the generic GP Panel @@ -563,31 +553,6 @@ class NODE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_region_type = 'TOOLS' -# Grease Pencil stroke editing tools -class NODE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - - -# Grease Pencil stroke sculpting tools -class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - -# Grease Pencil drawing brushes - - -class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - -# Grease Pencil drawing curves - - -class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - # ----------------------------- @@ -612,13 +577,8 @@ classes = ( NODE_PT_quality, NODE_UL_interface_sockets, NODE_PT_grease_pencil, - NODE_PT_grease_pencil_palettecolor, NODE_PT_grease_pencil_tools, NODE_PT_tools_grease_pencil_draw, - NODE_PT_tools_grease_pencil_edit, - NODE_PT_tools_grease_pencil_sculpt, - NODE_PT_tools_grease_pencil_brush, - NODE_PT_tools_grease_pencil_brushcurves, ) diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 8f722c4d3ce..20ef5ae0c53 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -142,8 +142,15 @@ class OUTLINER_MT_collection_view_layer(Menu): space = context.space_data - layout.operator("outliner.collection_exclude_set", text="Exclude") - layout.operator("outliner.collection_include_set", text="Include") + layout.operator("outliner.collection_exclude_set") + layout.operator("outliner.collection_exclude_clear") + + if context.engine == 'CYCLES': + layout.operator("outliner.collection_indirect_only_set") + layout.operator("outliner.collection_indirect_only_clear") + + layout.operator("outliner.collection_holdout_set") + layout.operator("outliner.collection_holdout_clear") class OUTLINER_MT_collection(Menu): diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 5fc9be2aa5b..84ae59772b6 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -22,7 +22,6 @@ from bpy.types import Header, Menu, Panel from rna_prop_ui import PropertyPanel from .properties_grease_pencil_common import ( GreasePencilDataPanel, - GreasePencilPaletteColorPanel, GreasePencilToolsPanel, ) from bpy.app.translations import pgettext_iface as iface_ @@ -343,9 +342,21 @@ class SEQUENCER_MT_add(Menu): layout.operator("sequencer.image_strip_add", text="Image") layout.operator("sequencer.sound_strip_add", text="Sound") + layout.menu("SEQUENCER_MT_add_generate") layout.menu("SEQUENCER_MT_add_effect") +class SEQUENCER_MT_add_generate(Menu): + bl_label = "Generate" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR' + layout.operator("sequencer.effect_strip_add", text="Text").type = 'TEXT' + + class SEQUENCER_MT_add_effect(Menu): bl_label = "Effect Strip" @@ -365,10 +376,8 @@ class SEQUENCER_MT_add_effect(Menu): layout.operator("sequencer.effect_strip_add", text="Over Drop").type = 'OVER_DROP' layout.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE' layout.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW' - layout.operator("sequencer.effect_strip_add", text="Text").type = 'TEXT' layout.operator("sequencer.effect_strip_add", text="Color Mix").type = 'COLORMIX' layout.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM' - layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR' layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED' layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM' layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT' @@ -1271,14 +1280,6 @@ class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Ou # But, it should only show up when there are images in the preview region -class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel): - bl_space_type = 'SEQUENCE_EDITOR' - bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - # But, it should only show up when there are images in the preview region - - class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel): bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' @@ -1304,6 +1305,7 @@ classes = ( SEQUENCER_MT_marker, SEQUENCER_MT_frame, SEQUENCER_MT_add, + SEQUENCER_MT_add_generate, SEQUENCER_MT_add_effect, SEQUENCER_MT_strip, SEQUENCER_MT_strip_transform, @@ -1322,7 +1324,6 @@ classes = ( SEQUENCER_PT_view_safe_areas, SEQUENCER_PT_modifiers, SEQUENCER_PT_grease_pencil, - SEQUENCER_PT_grease_pencil_palettecolor, SEQUENCER_PT_grease_pencil_tools, SEQUENCER_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index eeb47595213..8ce4a52fbbc 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -24,6 +24,7 @@ # For now keep this in a single file since it's an area that may change, # so avoid making changes all over the place. +import bpy from bpy.types import Panel from .space_toolsystem_common import ( @@ -39,21 +40,77 @@ def generate_from_brushes_ex( brush_category_attr, brush_category_layout, ): + def draw_settings(context, layout, tool): + _defs_gpencil_paint.draw_settings_common(context, layout, tool) + # Categories brush_categories = {} - for brush in context.blend_data.brushes: - if getattr(brush, brush_test_attr): - category = getattr(brush, brush_category_attr) - name = brush.name - brush_categories.setdefault(category, []).append( - ToolDef.from_dict( - dict( - text=name, - icon=icon_prefix + category.lower(), - data_block=name, + if context.mode != 'GPENCIL_PAINT': + for brush in context.blend_data.brushes: + if getattr(brush, brush_test_attr) and brush.gpencil_settings is None: + category = getattr(brush, brush_category_attr) + name = brush.name + brush_categories.setdefault(category, []).append( + ToolDef.from_dict( + dict( + text=name, + icon=icon_prefix + category.lower(), + data_block=name, + ) ) ) - ) + else: + for brush_type in brush_category_layout: + for brush in context.blend_data.brushes: + if getattr(brush, brush_test_attr) and brush.gpencil_settings.gp_icon == brush_type[0]: + category = brush_type[0] + name = brush.name + + # rename default brushes for tool bar + if name.startswith("Draw "): + text = name.replace("Draw ", "") + elif name.startswith("Eraser "): + text = name.replace("Eraser ", "") + elif name.startswith("Fill "): + text = name.replace(" Area", "") + else: + text = name + + # define icon + gp_icon = brush.gpencil_settings.gp_icon + if gp_icon == 'PENCIL': + icon_name = 'draw_pencil' + elif gp_icon == 'PEN': + icon_name = 'draw_pen' + elif gp_icon == 'INK': + icon_name = 'draw_ink' + elif gp_icon == 'INKNOISE': + icon_name = 'draw_noise' + elif gp_icon == 'BLOCK': + icon_name = 'draw_block' + elif gp_icon == 'MARKER': + icon_name = 'draw_marker' + elif gp_icon == 'FILL': + icon_name = 'draw_fill' + elif gp_icon == 'SOFT': + icon_name = 'draw.eraser_soft' + elif gp_icon == 'HARD': + icon_name = 'draw.eraser_hard' + elif gp_icon == 'STROKE': + icon_name = 'draw.eraser_stroke' + + brush_categories.setdefault(category, []).append( + ToolDef.from_dict( + dict( + text=text, + icon=icon_prefix + icon_name, + data_block=name, + widget=None, + operator="gpencil.draw", + draw_settings=draw_settings, + ) + ) + ) def tools_from_brush_group(groups): assert(type(groups) is tuple) @@ -61,6 +118,7 @@ def generate_from_brushes_ex( tool_defs = tuple(brush_categories.pop(groups[0], ())) else: tool_defs = tuple(item for g in groups for item in brush_categories.pop(g, ())) + if len(tool_defs) > 1: return (tool_defs,) else: @@ -125,6 +183,93 @@ class _defs_view3d_generic: ) +class _defs_annotate: + @classmethod + def draw_settings_common(cls, context, layout, tool): + ts = context.tool_settings + + space_type = tool.space_type + if space_type == 'VIEW_3D': + layout.separator() + + row = layout.row(align=True) + row.prop(ts, "annotation_stroke_placement_view3d", text="Placement") + if ts.gpencil_stroke_placement_view3d == 'CURSOR': + row.prop(ts.gpencil_sculpt, "lockaxis") + elif ts.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}: + row.prop(ts, "use_gpencil_stroke_endpoints") + + @ToolDef.from_fn + def scribble(): + def draw_settings(context, layout, tool): + _defs_annotate.draw_settings_common(context, layout, tool) + + return dict( + text="Annotate", + icon="ops.gpencil.draw", + cursor='PAINT_BRUSH', + keymap=( + ("gpencil.annotate", + dict(mode='DRAW', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def line(): + def draw_settings(context, layout, tool): + _defs_annotate.draw_settings_common(context, layout, tool) + + return dict( + text="Draw Line", + icon="ops.gpencil.draw.line", + cursor='CROSSHAIR', + keymap=( + ("gpencil.annotate", + dict(mode='DRAW_STRAIGHT', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def poly(): + def draw_settings(context, layout, tool): + _defs_annotate.draw_settings_common(context, layout, tool) + + return dict( + text="Draw Polygon", + icon="ops.gpencil.draw.poly", + cursor='CROSSHAIR', + keymap=( + ("gpencil.annotate", + dict(mode='DRAW_POLY', wait_for_input=False), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def eraser(): + def draw_settings(context, layout, tool): + # TODO: Move this setting to toolsettings + user_prefs = context.user_preferences + layout.prop(user_prefs.edit, "grease_pencil_eraser_radius", text="Radius") + + return dict( + text="Eraser", + icon="ops.gpencil.draw.eraser", + cursor='CROSSHAIR', # XXX: Always show brush circle when enabled + keymap=( + ("gpencil.annotate", + dict(mode='ERASER', wait_for_input=False), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + class _defs_transform: @ToolDef.from_fn @@ -182,7 +327,7 @@ class _defs_transform: def transform(): def draw_settings(context, layout, tool): tool_settings = context.tool_settings - layout.prop(tool_settings, "use_gizmo") + layout.prop(tool_settings, "use_gizmo_mode") return dict( text="Transform", @@ -866,6 +1011,331 @@ class _defs_uv_select: ) +class _defs_gpencil_paint: + @classmethod + def draw_color_selector(cls, context, layout): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + ts = context.tool_settings + row = layout.row(align=True) + row.prop(ts, "use_gpencil_thumbnail_list", text="", icon="IMGDISPLAY") + if ts.use_gpencil_thumbnail_list is False: + row.template_ID(gp_settings, "material", live_icon=True) + else: + row.template_greasepencil_color(gp_settings, "material", rows=3, cols=8, scale=0.8) + + @classmethod + def draw_settings_common(cls, context, layout, tool): + ob = context.active_object + if ob and ob.mode == 'GPENCIL_PAINT': + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + tool_settings = context.tool_settings + + if gp_settings.gpencil_brush_type == 'ERASE': + row = layout.row() + row.prop(brush, "size", text="Radius") + elif gp_settings.gpencil_brush_type == 'FILL': + row = layout.row() + row.prop(gp_settings, "gpencil_fill_leak", text="Leak Size") + row.prop(brush, "size", text="Thickness") + row.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify") + + _defs_gpencil_paint.draw_color_selector(context, layout) + + row = layout.row(align=True) + row.prop(gp_settings, "gpencil_fill_draw_mode", text="") + row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID') + + else: # bgpsettings.gpencil_brush_type == 'DRAW': + row = layout.row(align=True) + row.prop(brush, "size", text="Radius") + row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE') + row = layout.row(align=True) + row.prop(gp_settings, "pen_strength", slider=True) + row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') + + _defs_gpencil_paint.draw_color_selector(context, layout) + + @staticmethod + def generate_from_brushes(context): + return generate_from_brushes_ex( + context, + icon_prefix="brush.gpencil.", + brush_test_attr="use_paint_grease_pencil", + brush_category_attr="grease_pencil_tool", + brush_category_layout=( + ('PENCIL',), + ('PEN',), + ('INK',), + ('INKNOISE',), + ('BLOCK',), + ('MARKER',), + ('FILL',), + ('SOFT',), + ('HARD',), + ('STROKE',), + ) + ) + + +class _defs_gpencil_edit: + @ToolDef.from_fn + def bend(): + return dict( + text="Bend", + icon="ops.gpencil.edit_bend", + widget=None, + keymap=( + ("transform.bend", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def mirror(): + return dict( + text="Mirror", + icon="ops.gpencil.edit_mirror", + widget=None, + keymap=( + ("transform.mirror", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def shear(): + return dict( + text="Shear", + icon="ops.gpencil.edit_shear", + widget=None, + keymap=( + ("transform.shear", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def tosphere(): + return dict( + text="To Sphere", + icon="ops.gpencil.edit_to_sphere", + widget=None, + keymap=( + ("transform.tosphere", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + +class _defs_gpencil_sculpt: + @classmethod + def draw_settings_common(cls, context, layout, tool): + ob = context.active_object + if ob and ob.mode == 'GPENCIL_SCULPT': + ts = context.tool_settings + settings = ts.gpencil_sculpt + brush = settings.brush + + layout.prop(brush, "size", slider=True) + + row = layout.row(align=True) + row.prop(brush, "strength", slider=True) + row.prop(brush, "use_pressure_strength", text="") + row.separator() + row.prop(ts.gpencil_sculpt, "use_select_mask", text="") + + @ToolDef.from_fn + def smooth(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Smooth", + icon="ops.gpencil.sculpt_smooth", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='SMOOTH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def thickness(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Thickness", + icon="ops.gpencil.sculpt_thickness", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='THICKNESS', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def strength(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Strength", + icon="ops.gpencil.sculpt_strength", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='STRENGTH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def grab(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Grab", + icon="ops.gpencil.sculpt_grab", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='GRAB', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def push(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Push", + icon="ops.gpencil.sculpt_push", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='PUSH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def twist(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Twist", + icon="ops.gpencil.sculpt_twist", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='TWIST', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def pinch(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Pinch", + icon="ops.gpencil.sculpt_pinch", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='PINCH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def randomize(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Randomize", + icon="ops.gpencil.sculpt_randomize", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='RANDOMIZE', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def clone(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Clone", + icon="ops.gpencil.sculpt_clone", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='CLONE', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + +class _defs_gpencil_weight: + @classmethod + def draw_settings_common(cls, context, layout, tool): + ob = context.active_object + if ob and ob.mode == 'GPENCIL_WEIGHT': + settings = context.tool_settings.gpencil_sculpt + brush = settings.brush + + layout.prop(brush, "size", slider=True) + + row = layout.row(align=True) + row.prop(brush, "strength", slider=True) + row.prop(brush, "use_pressure_strength", text="") + + @ToolDef.from_fn + def paint(): + def draw_settings(context, layout, tool): + _defs_gpencil_weight.draw_settings_common(context, layout, tool) + + return dict( + text="Draw", + icon="ops.gpencil.sculpt_weight", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='WEIGHT', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' @@ -951,8 +1421,6 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): _defs_transform.scale, _defs_transform.scale_cage, ), - None, - _defs_view3d_generic.ruler, ) _tools_select = ( @@ -963,6 +1431,16 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ), ) + _tools_annotate = ( + ( + _defs_annotate.scribble, + _defs_annotate.line, + _defs_annotate.poly, + _defs_annotate.eraser, + ), + _defs_view3d_generic.ruler, + ) + _tools = { None: [ _defs_view3d_generic.cursor, @@ -972,21 +1450,27 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): *_tools_select, None, *_tools_transform, + None, + *_tools_annotate, ], 'POSE': [ *_tools_select, *_tools_transform, None, + *_tools_annotate, + None, ( _defs_pose.breakdown, _defs_pose.push, _defs_pose.relax, - ) + ), ], 'EDIT_ARMATURE': [ *_tools_select, None, *_tools_transform, + None, + *_tools_annotate, _defs_edit_armature.roll, ( _defs_edit_armature.bone_size, @@ -996,13 +1480,15 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ( _defs_edit_armature.extrude, _defs_edit_armature.extrude_cursor, - ) + ), ], 'EDIT_MESH': [ *_tools_select, None, *_tools_transform, None, + *_tools_annotate, + None, _defs_edit_mesh.cube_add, None, ( @@ -1047,6 +1533,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): None, *_tools_transform, None, + *_tools_annotate, + None, _defs_edit_curve.draw, _defs_edit_curve.extrude_cursor, ], @@ -1075,6 +1563,33 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): None, _defs_weight_paint.gradient, ], + 'GPENCIL_PAINT': [ + _defs_gpencil_paint.generate_from_brushes, + ], + 'GPENCIL_EDIT': [ + *_tools_select, + None, + *_tools_transform, + None, + _defs_gpencil_edit.bend, + _defs_gpencil_edit.mirror, + _defs_gpencil_edit.shear, + _defs_gpencil_edit.tosphere, + ], + 'GPENCIL_SCULPT': [ + _defs_gpencil_sculpt.smooth, + _defs_gpencil_sculpt.thickness, + _defs_gpencil_sculpt.strength, + _defs_gpencil_sculpt.grab, + _defs_gpencil_sculpt.push, + _defs_gpencil_sculpt.twist, + _defs_gpencil_sculpt.pinch, + _defs_gpencil_sculpt.randomize, + _defs_gpencil_sculpt.clone, + ], + 'GPENCIL_WEIGHT': [ + _defs_gpencil_weight.paint, + ], } diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 96ef2e51e60..6712e495498 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -128,6 +128,8 @@ class TOPBAR_HT_lower_bar(Header): pass elif mode == 'PARTICLE': layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") + elif mode == 'GPENCIL_PAINT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_paint", category="") def draw_center(self, context): pass @@ -165,6 +167,15 @@ class TOPBAR_HT_lower_bar(Header): layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="") elif mode == 'OBJECT': layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="") + elif mode == 'GPENCIL_PAINT': + layout.prop(context.tool_settings, "gpencil_stroke_placement_view3d", text='') + if context.tool_settings.gpencil_stroke_placement_view3d in ('ORIGIN', 'CURSOR'): + layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='') + layout.prop(context.tool_settings, "use_gpencil_draw_onback", text="", icon='ORTHO') + layout.prop(context.tool_settings, "use_gpencil_additive_drawing", text="", icon='FREEZE') + + elif mode == 'GPENCIL_SCULPT': + layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='') class _draw_left_context_mode: @@ -265,8 +276,8 @@ class INFO_MT_file(Menu): layout.separator() layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.link", text="Link", icon='LINK_BLEND') - layout.operator("wm.append", text="Append", icon='APPEND_BLEND') + layout.operator("wm.link", text="Link...", icon='LINK_BLEND') + layout.operator("wm.append", text="Append...", icon='APPEND_BLEND') layout.menu("INFO_MT_file_previews") layout.separator() @@ -495,12 +506,25 @@ class INFO_MT_help(Menu): def draw(self, context): layout = self.layout + show_developer = context.user_preferences.view.show_developer_ui + layout.operator( "wm.url_open", text="Manual", icon='HELP', ).url = "https://docs.blender.org/manual/en/dev/" + layout.operator( - "wm.url_open", text="Release Log", icon='URL', - ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2] + "wm.url_open", text="Report a Bug", icon='URL', + ).url = "https://developer.blender.org/maniphest/task/edit/form/1" + + layout.separator() + + layout.operator( + "wm.url_open", text="User Communities", icon='URL', + ).url = "https://www.blender.org/community/" + layout.operator( + "wm.url_open", text="Developer Community", icon='URL', + ).url = "https://www.blender.org/get-involved/developers/" + layout.separator() layout.operator( @@ -509,24 +533,22 @@ class INFO_MT_help(Menu): layout.operator( "wm.url_open", text="Blender Store", icon='URL', ).url = "https://store.blender.org" + layout.operator( - "wm.url_open", text="Developer Community", icon='URL', - ).url = "https://www.blender.org/get-involved/" - layout.operator( - "wm.url_open", text="User Community", icon='URL', - ).url = "https://www.blender.org/support/user-community" - layout.separator() - layout.operator( - "wm.url_open", text="Report a Bug", icon='URL', - ).url = "https://developer.blender.org/maniphest/task/edit/form/1" + "wm.url_open", text="Release Notes", icon='URL', + ).url = "https://www.blender.org/download/releases/%d-%d/" % bpy.app.version[:2] + layout.separator() - layout.operator( - "wm.url_open", text="Python API Reference", icon='URL', - ).url = bpy.types.WM_OT_doc_view._prefix + if show_developer: + layout.operator( + "wm.url_open", text="Python API Reference", icon='URL', + ).url = bpy.types.WM_OT_doc_view._prefix + + layout.operator("wm.operator_cheat_sheet", icon='TEXT') + + layout.operator("wm.sysinfo") - layout.operator("wm.operator_cheat_sheet", icon='TEXT') - layout.operator("wm.sysinfo", icon='TEXT') layout.separator() layout.operator("wm.splash", icon='BLENDER') @@ -539,8 +561,13 @@ class TOPBAR_MT_file_specials(Menu): layout = self.layout layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.link", text="Link", icon='LINK_BLEND') - layout.operator("wm.append", text="Append", icon='APPEND_BLEND') + layout.operator("wm.read_homefile", text="New", icon='NEW') + layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER') + + layout.separator() + + layout.operator("wm.link", text="Link...", icon='LINK_BLEND') + layout.operator("wm.append", text="Append...", icon='APPEND_BLEND') layout.separator() diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index ed0389942ad..52d4640806d 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -361,14 +361,16 @@ class USERPREF_PT_edit(Panel): row.separator() col = row.column() - col.label(text="Grease Pencil:") + col.label(text="Annotations:") + sub = col.row() + sub.prop(edit, "grease_pencil_default_color", text="Default Color") col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius") col.separator() + col.label(text="Grease Pencil/Annotations:") + col.separator() col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance") col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance") col.separator() - col.prop(edit, "grease_pencil_default_color", text="Default Color") - col.separator() col.prop(edit, "use_grease_pencil_simplify_stroke", text="Simplify Stroke") col.separator() col.separator() @@ -527,9 +529,14 @@ class USERPREF_PT_system(Panel): col.prop(system, "gpu_viewport_quality") col.separator() + col.label(text="Grease Pencil Options:") + col.prop(system, "gpencil_multi_sample", text="") + col.separator() col.label(text="Text Draw Options:") col.prop(system, "use_text_antialiasing") + if system.use_text_antialiasing: + col.prop(system, "use_text_hinting") # 3. Column column = split.column() diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 0b4032c8aaa..88e785d8fef 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -19,11 +19,8 @@ # <pep8 compliant> import bpy from bpy.types import Header, Menu, Panel -from .properties_grease_pencil_common import ( - GreasePencilDataPanel, - GreasePencilPaletteColorPanel, -) from .properties_paint_common import UnifiedPaintPanel +from .properties_grease_pencil_common import GreasePencilDataPanel from bpy.app.translations import contexts as i18n_contexts @@ -80,18 +77,40 @@ class VIEW3D_HT_header(Header): row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True - # GPencil - if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode: - row = layout.row(align=True) - row.operator("gpencil.copy", text="", icon='COPYDOWN') - row.operator("gpencil.paste", text="", icon='PASTEDOWN') + # Grease Pencil + if obj and obj.type == 'GPENCIL' and context.gpencil_data: + gpd = context.gpencil_data - # XXX: icon - layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH') + if gpd.is_stroke_paint_mode: + row = layout.row(align=True) + row.popover( + panel="VIEW3D_PT_tools_grease_pencil_shapes", + text="Shapes" + ) - row = layout.row(align=True) - row.prop(tool_settings.gpencil_sculpt, "use_select_mask") - row.prop(tool_settings.gpencil_sculpt, "selection_alpha", slider=True) + if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode: + row = layout.row(align=True) + row.prop(gpd, "use_multiedit", text="", icon="FORCE_HARMONIC") + + sub = row.row(align=True) + sub.active = gpd.use_multiedit + sub.popover( + panel="VIEW3D_PT_gpencil_multi_frame", + text="Multiframe" + ) + + if gpd.use_stroke_edit_mode: + row = layout.row(align=True) + row.operator("gpencil.copy", text="", icon='COPYDOWN') + row.operator("gpencil.paste", text="", icon='PASTEDOWN') + + row = layout.row(align=True) + row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="") + + row.popover( + panel="VIEW3D_PT_tools_grease_pencil_interpolate", + text="Interpolate" + ) VIEW3D_MT_editor_menus.draw_collapsible(context, layout) @@ -101,7 +120,7 @@ class VIEW3D_HT_header(Header): scene = context.scene # Orientation - if object_mode in {'OBJECT', 'EDIT', 'POSE'}: + if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT'}: orientation = scene.transform_orientation current_orientation = scene.current_orientation @@ -126,7 +145,8 @@ class VIEW3D_HT_header(Header): if obj is None: show_snap = True else: - if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}: + if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT', + 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}: show_snap = True else: @@ -160,13 +180,15 @@ class VIEW3D_HT_header(Header): # Proportional editing if obj: - if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode: - row = layout.row(align=True) - row.prop(tool_settings, "proportional_edit", icon_only=True) + gpd = context.gpencil_data + if gpd is not None and obj.type == 'GPENCIL': + if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode: + row = layout.row(align=True) + row.prop(tool_settings, "proportional_edit", icon_only=True) - sub = row.row(align=True) - sub.active = tool_settings.proportional_edit != 'DISABLED' - sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) + sub = row.row(align=True) + sub.active = tool_settings.proportional_edit != 'DISABLED' + sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) elif object_mode in {'EDIT', 'PARTICLE_EDIT'}: row = layout.row(align=True) @@ -190,7 +212,7 @@ class VIEW3D_HT_header(Header): sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) # Pivot - if object_mode in {'OBJECT', 'EDIT', 'POSE'}: + if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT', 'GPENCIL_SCULPT'}: pivot_point = tool_settings.transform_pivot_point act_pivot_point = bpy.types.ToolSettings.bl_rna.properties["transform_pivot_point"].enum_items[pivot_point] row = layout.row(align=True) @@ -234,13 +256,14 @@ class VIEW3D_MT_editor_menus(Menu): obj = context.active_object mode_string = context.mode edit_object = context.edit_object - gp_edit = context.gpencil_data and context.gpencil_data.use_stroke_edit_mode + gp_edit = obj and obj.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'} layout.menu("VIEW3D_MT_view") # Select Menu if gp_edit: - layout.menu("VIEW3D_MT_select_gpencil") + if mode_string not in {'GPENCIL_PAINT', 'GPENCIL_WEIGHT'}: + layout.menu("VIEW3D_MT_select_gpencil") elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}: mesh = obj.data if mesh.use_paint_mask: @@ -266,7 +289,15 @@ class VIEW3D_MT_editor_menus(Menu): layout.menu("INFO_MT_edit_armature_add", text="Add") if gp_edit: - layout.menu("VIEW3D_MT_edit_gpencil") + if obj and obj.mode == 'GPENCIL_PAINT': + layout.menu("VIEW3D_MT_paint_gpencil") + elif obj and obj.mode == 'GPENCIL_EDIT': + layout.menu("VIEW3D_MT_edit_gpencil") + elif obj and obj.mode == 'GPENCIL_SCULPT': + layout.menu("VIEW3D_MT_sculpt_gpencil") + elif obj and obj.mode == 'GPENCIL_WEIGHT': + layout.menu("VIEW3D_MT_weight_gpencil") + elif edit_object: layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower()) @@ -453,7 +484,7 @@ class VIEW3D_MT_snap(Menu): layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid") layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False - layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True layout.operator("view3d.snap_selected_to_active", text="Selection to Active") layout.separator() @@ -1194,6 +1225,7 @@ class VIEW3D_MT_select_gpencil(Menu): layout.separator() layout.operator("gpencil.select_linked", text="Linked") + layout.operator("gpencil.select_alternate") layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped") layout.separator() @@ -1454,6 +1486,7 @@ class INFO_MT_add(Menu): layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE') layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE' layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY') + layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL') layout.separator() layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') @@ -3134,12 +3167,17 @@ class VIEW3D_MT_edit_gpencil_delete(Menu): layout.separator() - layout.operator("gpencil.dissolve") + layout.operator_enum("gpencil.dissolve", "type") layout.separator() layout.operator("gpencil.active_frames_delete_all") + layout.separator() + + layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes").mode = 'ACTIVE' + layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes all Frames").mode = 'ALL' + # Edit Curve # draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface @@ -3500,11 +3538,34 @@ class VIEW3D_MT_edit_armature_delete(Menu): layout.operator("armature.dissolve", text="Dissolve") -# ********** GPencil Stroke Edit menu ********** +# ********** Grease Pencil Stroke menus ********** +class VIEW3D_MT_gpencil_simplify(Menu): + bl_label = "Simplify" + + def draw(self, context): + layout = self.layout + layout.operator("gpencil.stroke_simplify_fixed", text="Fixed") + layout.operator("gpencil.stroke_simplify", text="Adaptative") + + +class VIEW3D_MT_paint_gpencil(Menu): + bl_label = "Strokes" + + def draw(self, context): + + layout = self.layout + + layout.menu("VIEW3D_MT_gpencil_animation") + layout.menu("VIEW3D_MT_edit_gpencil_interpolate") + + layout.separator() + + layout.operator("gpencil.delete", text="Delete Frame").type = 'FRAME' + layout.operator("gpencil.active_frames_delete_all") class VIEW3D_MT_edit_gpencil(Menu): - bl_label = "GPencil" + bl_label = "Strokes" def draw(self, context): tool_settings = context.tool_settings @@ -3512,53 +3573,126 @@ class VIEW3D_MT_edit_gpencil(Menu): layout = self.layout layout.menu("VIEW3D_MT_edit_gpencil_transform") - layout.operator("transform.mirror", text="Mirror") + + layout.separator() layout.menu("GPENCIL_MT_snap") layout.separator() - layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True - layout.prop_menu_enum(tool_settings.gpencil_sculpt, "tool", text="Sculpt Brush") + layout.menu("VIEW3D_MT_gpencil_animation") layout.separator() - layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access... layout.menu("VIEW3D_MT_edit_gpencil_interpolate") layout.separator() layout.operator("gpencil.duplicate_move", text="Duplicate") layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.menu("VIEW3D_MT_gpencil_simplify") layout.separator() + layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...") + layout.operator("gpencil.stroke_split", text="Split") layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...") layout.operator("gpencil.stroke_flip", text="Flip Direction") layout.separator() layout.operator("gpencil.copy", text="Copy") - layout.operator("gpencil.paste", text="Paste") + layout.operator("gpencil.paste", text="Paste").type = 'COPY' + layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE' layout.separator() - layout.operator("gpencil.reveal") - layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True - layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False + layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer") + layout.operator("gpencil.stroke_change_color", text="Assign Material") + layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...") + + layout.separator() + + layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...") + + layout.separator() + + layout.menu("VIEW3D_MT_edit_gpencil_delete") + layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE' + + layout.separator() + + layout.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode") + + +class VIEW3D_MT_sculpt_gpencil(Menu): + bl_label = "Strokes" + + def draw(self, context): + layout = self.layout + + layout.menu("VIEW3D_MT_edit_gpencil_transform") + + layout.separator() + layout.menu("GPENCIL_MT_snap") + + layout.separator() + + layout.operator("gpencil.duplicate_move", text="Duplicate") + layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.menu("VIEW3D_MT_gpencil_simplify") + + layout.separator() + + layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...") + layout.operator("gpencil.stroke_split", text="Split") + layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...") + layout.operator("gpencil.stroke_flip", text="Flip Direction") + + layout.separator() + + layout.operator("gpencil.copy", text="Copy") + layout.operator("gpencil.paste", text="Paste").type = 'COPY' + layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE' layout.separator() layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer") - layout.operator("gpencil.stroke_change_color", text="Move to Color") + layout.operator("gpencil.stroke_change_color", text="Assign Material") layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...") layout.separator() layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...") - layout.separator() - layout.menu("VIEW3D_MT_edit_gpencil_delete") +class VIEW3D_MT_weight_gpencil(Menu): + bl_label = "Weights" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.vertex_group_invert", text="Invert") + layout.operator("gpencil.vertex_group_smooth", text="Smooth") + + +class VIEW3D_MT_gpencil_animation(Menu): + bl_label = "Animation" + + @classmethod + def poll(cls, context): + ob = context.active_object + return ob and ob.type == 'GPENCIL' and ob.mode != 'OBJECT' + + @staticmethod + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.blank_frame_add") + layout.operator("gpencil.active_frames_delete_all", text="Delete Frame(s)") + + layout.separator() + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers").mode = 'ALL' class VIEW3D_MT_edit_gpencil_transform(Menu): @@ -3619,20 +3753,6 @@ class VIEW3D_MT_view_pie(Menu): # ********** Panel ********** -class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - - -class VIEW3D_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - - class VIEW3D_PT_view3d_properties(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -3744,6 +3864,7 @@ class VIEW3D_PT_object_type_visibility(Panel): "armature", "lattice", "empty", + "grease_pencil", "camera", "light", "light_probe", @@ -3805,10 +3926,10 @@ class VIEW3D_PT_shading_lighting(Panel): split = layout.split(0.9) col = split.column() sub = col.row() - sub.scale_y = 0.6 # smaller matcap/hdri preview + sub.scale_y = 0.6 # smaller matcap/hdri preview if shading.light == 'STUDIO': - sub.template_icon_view(shading, "studio_light", show_labels=True, scale=3) + sub.template_icon_view(shading, "studio_light", scale=3) if shading.selected_studio_light.orientation == 'WORLD': col.prop(shading, "studiolight_rotate_z", text="Rotation") @@ -3817,7 +3938,7 @@ class VIEW3D_PT_shading_lighting(Panel): col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') elif shading.light == 'MATCAP': - sub.template_icon_view(shading, "studio_light", show_labels=True, scale=3) + sub.template_icon_view(shading, "studio_light", scale=3) col = split.column() col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') @@ -3834,7 +3955,7 @@ class VIEW3D_PT_shading_lighting(Panel): col = split.column() sub = col.row() sub.scale_y = 0.6 - sub.template_icon_view(shading, "studio_light", show_labels=True, scale=3) + sub.template_icon_view(shading, "studio_light", scale=3) col = split.column() col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') @@ -3844,7 +3965,7 @@ class VIEW3D_PT_shading_lighting(Panel): col = split.column() col.prop(shading, "studiolight_rotate_z", text="Rotation") col.prop(shading, "studiolight_background_alpha") - col = split.column() # to align properly with above + col = split.column() # to align properly with above class VIEW3D_PT_shading_color(Panel): @@ -3863,10 +3984,14 @@ class VIEW3D_PT_shading_color(Panel): shading = VIEW3D_PT_shading.get_shading(context) - layout.row().prop(shading, "color_type", expand=True) - + layout.row().prop(shading, 'color_type', expand=True) if shading.color_type == 'SINGLE': - layout.row().prop(shading, "single_color", text="") + layout.row().prop(shading, 'single_color', text="") + + layout.row().label("Background") + layout.row().prop(shading, 'background_type', expand=True) + if shading.background_type == 'VIEWPORT': + layout.row().prop(shading, "background_color", text="") class VIEW3D_PT_shading_options(Panel): @@ -3936,10 +4061,6 @@ class VIEW3D_PT_shading_options(Panel): if not shading.light == 'MATCAP': col.prop(shading, "show_specular_highlight") - view = context.space_data - if view.type == 'VIEW_3D': - col.prop(view, "show_world") - class VIEW3D_PT_shading_options_shadow(Panel): bl_label = "Shadow Settings" @@ -4064,6 +4185,8 @@ class VIEW3D_PT_overlay_guides(Panel): if shading.type == 'MATERIAL': col.prop(overlay, "show_look_dev") + col.prop(overlay, "show_annotation", text="Annotations") + class VIEW3D_PT_overlay_object(Panel): bl_space_type = 'VIEW_3D' @@ -4384,7 +4507,7 @@ class VIEW3D_PT_overlay_edit_curve(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' bl_parent_id = 'VIEW3D_PT_overlay' - bl_label = "Edit Curve" + bl_label = "Curve Edit Mode" @classmethod def poll(cls, context): @@ -4459,7 +4582,7 @@ class VIEW3D_PT_overlay_edit_armature(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' bl_parent_id = 'VIEW3D_PT_overlay' - bl_label = "Edit Armature" + bl_label = "Armature Edit Mode" @classmethod def poll(cls, context): @@ -4602,6 +4725,60 @@ class VIEW3D_PT_transform_orientations(Panel): row.operator("transform.delete_orientation", text="", icon='X', emboss=False) +class VIEW3D_PT_overlay_gpencil_options(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "" + + @classmethod + def poll(cls, context): + return context.object and context.object.type == 'GPENCIL' + + def draw_header(self, context): + layout = self.layout + layout.label(text={ + 'GPENCIL_PAINT': "Draw Grease Pencil", + 'GPENCIL_EDIT': "Edit Grease Pencil", + 'GPENCIL_SCULPT': "Sculpt Grease Pencil", + 'GPENCIL_WEIGHT': "Weight Grease Pencil", + 'OBJECT': "Grease Pencil", + }[context.mode]) + + def draw(self, context): + layout = self.layout + view = context.space_data + overlay = view.overlay + + layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin") + + col = layout.column() + row = col.row() + row.prop(overlay, "use_gpencil_paper", text="") + sub = row.row() + sub.active = overlay.use_gpencil_paper + sub.prop(overlay, "gpencil_paper_opacity", text="Fade 3D Objects", slider=True) + + col = layout.column() + row = col.row() + row.prop(overlay, "use_gpencil_grid", text="") + sub = row.row() + sub.active = overlay.use_gpencil_grid + sub.prop(overlay, "gpencil_grid_opacity", text="Canvas Grid", slider=True) + + if overlay.use_gpencil_grid: + row = layout.row(align=True) + row.prop(overlay, "gpencil_grid_scale") + col = row.column() + col.prop(overlay, "gpencil_grid_lines", text="Subdivisions") + col.prop(overlay, "gpencil_grid_axis") + + if context.object.mode in {'GPENCIL_EDIT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}: + layout.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines") + layout.prop(overlay, "use_gpencil_multiedit_line_only", text="Show Edit Lines only in multiframe") + layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True) + + class VIEW3D_PT_quad_view(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -4629,6 +4806,14 @@ class VIEW3D_PT_quad_view(Panel): row.prop(region, "use_box_clip") +# Annotation properties +class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + + # NOTE: this is just a wrapper around the generic GP Panel + + class VIEW3D_PT_view3d_stereo(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -4708,6 +4893,26 @@ class VIEW3D_PT_context_properties(Panel): rna_prop_ui.draw(self.layout, context, member, object, False) +# Grease Pencil Object - Multiframe falloff tools +class VIEW3D_PT_gpencil_multi_frame(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Multi Frame" + + @staticmethod + def draw(self, context): + gpd = context.gpencil_data + settings = context.tool_settings.gpencil_sculpt + + layout = self.layout + col = layout.column(align=True) + col.prop(settings, "use_multiframe_falloff") + + # Falloff curve + if gpd.use_multiedit and settings.use_multiframe_falloff: + layout.template_curve_mapping(settings, "multiframe_falloff_curve", brush=True) + + classes = ( VIEW3D_HT_header, VIEW3D_MT_editor_menus, @@ -4815,8 +5020,13 @@ classes = ( VIEW3D_MT_edit_mesh_clean, VIEW3D_MT_edit_mesh_delete, VIEW3D_MT_edit_mesh_showhide, + VIEW3D_MT_paint_gpencil, VIEW3D_MT_edit_gpencil, VIEW3D_MT_edit_gpencil_delete, + VIEW3D_MT_sculpt_gpencil, + VIEW3D_MT_weight_gpencil, + VIEW3D_MT_gpencil_animation, + VIEW3D_MT_gpencil_simplify, VIEW3D_MT_edit_curve, VIEW3D_MT_edit_curve_ctrlpoints, VIEW3D_MT_edit_curve_segments, @@ -4839,12 +5049,12 @@ classes = ( VIEW3D_MT_edit_gpencil_interpolate, VIEW3D_MT_object_mode_pie, VIEW3D_MT_view_pie, - VIEW3D_PT_grease_pencil, - VIEW3D_PT_grease_pencil_palettecolor, VIEW3D_PT_view3d_properties, VIEW3D_PT_view3d_camera_lock, VIEW3D_PT_view3d_cursor, VIEW3D_PT_object_type_visibility, + VIEW3D_PT_grease_pencil, + VIEW3D_PT_gpencil_multi_frame, VIEW3D_PT_quad_view, VIEW3D_PT_view3d_stereo, VIEW3D_PT_shading, @@ -4873,6 +5083,7 @@ classes = ( VIEW3D_PT_pivot_point, VIEW3D_PT_snapping, VIEW3D_PT_transform_orientations, + VIEW3D_PT_overlay_gpencil_options, VIEW3D_PT_context_properties, ) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 3b68057c26d..6110d0fca61 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -20,12 +20,9 @@ import bpy from bpy.types import Menu, Panel, UIList from .properties_grease_pencil_common import ( - GreasePencilDrawingToolsPanel, GreasePencilStrokeEditPanel, - GreasePencilInterpolatePanel, GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel + GreasePencilAppearancePanel, ) from .properties_paint_common import ( UnifiedPaintPanel, @@ -33,6 +30,7 @@ from .properties_paint_common import ( brush_texpaint_common, brush_mask_texture_settings, ) +from bl_operators.presets import PresetMenu class View3DPanel: @@ -70,6 +68,16 @@ def draw_vpaint_symmetry(layout, vpaint): col.use_property_split = True col.prop(vpaint, "radial_symmetry", text="Radial") +# Most of these panels should not be visible in GP edit modes + + +def is_not_gpencil_edit_mode(context): + is_gpmode = ( + context.active_object and + context.active_object.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'} + ) + return not is_gpmode + # ********** default tools for editmode_mesh **************** @@ -1361,9 +1369,273 @@ class VIEW3D_PT_tools_normal(View3DPanel, Panel): col = layout.column(align=True) -# Grease Pencil drawing tools -class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): +# ********** grease pencil object tool panels **************** + +# Grease Pencil drawing brushes +class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Brush" + + @classmethod + def poll(cls, context): + is_3d_view = context.space_data.type == 'VIEW_3D' + if is_3d_view: + if context.gpencil_data is None: + return False + + gpd = context.gpencil_data + return bool(gpd.is_stroke_paint_mode) + else: + return True + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + ts = context.scene.tool_settings + settings = ts.gpencil_paint + + row = layout.row() + col = row.column() + col.template_ID_preview(settings, "brush", new="brush.add_gpencil", rows=3, cols=8) + + col = row.column() + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + sub = col.column(align=True) + sub.operator("gpencil.brush_presets_create", icon='HELP', text="") + + if brush is not None: + # XXX: Items in "sub" currently show up beside the brush selector in a separate column + if gp_settings.gpencil_brush_type == 'ERASE': + sub.prop(gp_settings, "default_eraser", text="") + + # Brush details + if gp_settings.gpencil_brush_type == 'ERASE': + col = layout.column(align=True) + col.prop(brush, "size", text="Radius") + + col.separator() + row = col.row() + row.prop(gp_settings, "eraser_mode", expand=True) + elif gp_settings.gpencil_brush_type == 'FILL': + col = layout.column(align=True) + col.prop(gp_settings, "gpencil_fill_leak", text="Leak Size") + col.prop(brush, "size", text="Thickness") + col.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify") + + col = layout.row(align=True) + col.template_ID(gp_settings, "material") + + row = layout.row(align=True) + row.prop(gp_settings, "gpencil_fill_draw_mode", text="Boundary Draw Mode") + row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID') + + col = layout.column(align=True) + col.enabled = gp_settings.gpencil_fill_draw_mode != "STROKE" + col.prop(gp_settings, "gpencil_fill_hide", text="Hide Transparent Lines") + sub = col.row(align=True) + sub.enabled = gp_settings.gpencil_fill_hide + sub.prop(gp_settings, "gpencil_fill_threshold", text="Threshold") + else: # bgpsettings.gpencil_brush_type == 'DRAW': + row = layout.row(align=True) + row.prop(brush, "size", text="Radius") + row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE') + row = layout.row(align=True) + row.prop(gp_settings, "pen_strength", slider=True) + row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') + + row = layout.row(align=True) + row.template_ID(gp_settings, "material") + + +# Grease Pencil drawing brushes options +class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Options" + bl_options = {'DEFAULT_CLOSED'} + + def draw_header_preset(self, context): + VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout) + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + if brush is not None: + col = layout.column(align=True) + col.prop(gp_settings, "input_samples") + col.separator() + + col.prop(gp_settings, "active_smooth_factor") + col.separator() + + col.prop(gp_settings, "angle", slider=True) + col.prop(gp_settings, "angle_factor", text="Factor", slider=True) + col.separator() + + +class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option' + bl_label = "Stabilizer" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + return brush is not None and gp_settings.gpencil_brush_type == 'DRAW' + + def draw_header(self, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + self.layout.prop(gp_settings, "use_stabilizer", text="") + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.active = gp_settings.use_stabilizer + + layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True) + layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True) + + +class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option' + bl_label = "Post-processing Settings" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + brush = context.active_gpencil_brush + + return brush is not None + + def draw_header(self, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + self.layout.prop(gp_settings, "enable_settings", text="") + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.active = gp_settings.enable_settings + + layout.prop(gp_settings, "pen_smooth_factor") + layout.prop(gp_settings, "pen_smooth_steps") + + layout.prop(gp_settings, "pen_thick_smooth_factor") + layout.prop(gp_settings, "pen_thick_smooth_steps") + + layout.prop(gp_settings, "pen_subdivision_steps") + layout.prop(gp_settings, "random_subdiv", text="Randomness", slider=True) + + +class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option' + bl_label = "Random Settings" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + brush = context.active_gpencil_brush + + return brush is not None + + def draw_header(self, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + self.layout.prop(gp_settings, "enable_random", text="") + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.active = gp_settings.enable_random + + layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True) + layout.prop(gp_settings, "random_strength", text="Strength", slider=True) + layout.prop(gp_settings, "uv_random", text="UV", slider=True) + + row = layout.row(align=True) + row.prop(gp_settings, "pen_jitter", slider=True) + row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE') + + +# Grease Pencil drawingcurves +class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Curves" + bl_options = {'DEFAULT_CLOSED'} + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + # Brush + layout.label("Sensitivity") + layout.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True) + + layout.label("Strength") + layout.template_curve_mapping(gp_settings, "curve_strength", brush=True) + + layout.label("Jitter") + layout.template_curve_mapping(gp_settings, "curve_jitter", brush=True) + + +# Grease Pencil create shapes +class VIEW3D_PT_tools_grease_pencil_shapes(View3DPanel, Panel): +>>>>>>> blender2.8 bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Shapes" + + @classmethod + def poll(cls, context): + ob = context.active_object + return ob and ob.type == 'GPENCIL' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + col = layout.column(align=True) + col.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE' + col.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX' + col.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE' + + layout.operator("object.gpencil_add", text="Monkey", icon='MONKEY').type = 'MONKEY' # Grease Pencil stroke editing tools @@ -1372,24 +1644,109 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): # Grease Pencil stroke interpolation tools -class VIEW3D_PT_tools_grease_pencil_interpolate(GreasePencilInterpolatePanel, Panel): +class VIEW3D_PT_tools_grease_pencil_interpolate(Panel): bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Interpolate" + + @classmethod + def poll(cls, context): + if context.gpencil_data is None: + return False + + gpd = context.gpencil_data + return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) + + @staticmethod + def draw(self, context): + layout = self.layout + settings = context.tool_settings.gpencil_interpolate + + col = layout.column(align=True) + col.label("Interpolate Strokes") + col.operator("gpencil.interpolate", text="Interpolate") + col.operator("gpencil.interpolate_sequence", text="Sequence") + col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns") + + col = layout.column(align=True) + col.label(text="Options:") + col.prop(settings, "interpolate_all_layers") + col.prop(settings, "interpolate_selected_only") + + col = layout.column(align=True) + col.label(text="Sequence Options:") + col.prop(settings, "type") + if settings.type == 'CUSTOM': + # TODO: Options for loading/saving curve presets? + col.template_curve_mapping(settings, "interpolation_curve", brush=True) + elif settings.type != 'LINEAR': + col.prop(settings, "easing") + + if settings.type == 'BACK': + layout.prop(settings, "back") + elif setting.type == 'ELASTIC': + sub = layout.column(align=True) + sub.prop(settings, "amplitude") + sub.prop(settings, "period") # Grease Pencil stroke sculpting tools -class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'VIEW_3D' +class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel): + bl_context = ".greasepencil_sculpt" + bl_category = "Tools" + bl_label = "Sculpt Strokes" -# Grease Pencil drawing brushes -class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'VIEW_3D' +# Grease Pencil weight painting tools +class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel): + bl_context = ".greasepencil_weight" + bl_category = "Tools" + bl_label = "Weight Paint" -# Grease Pencil drawingcurves + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + gpd = context.gpencil_data + settings = context.tool_settings.gpencil_sculpt + tool = settings.tool + brush = settings.brush -class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): - bl_space_type = 'VIEW_3D' + layout.template_icon_view(settings, "weight_tool", show_labels=True) + + col = layout.column() + col.prop(brush, "size", slider=True) + row = col.row(align=True) + row.prop(brush, "strength", slider=True) + row.prop(brush, "use_pressure_strength", text="") + + col.prop(brush, "use_falloff") + + +# Grease Pencil Brush Appeareance (one for each mode) +class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Appearance" + + +class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel): + bl_context = ".greasepencil_sculpt" + bl_label = "Appearance" + + +class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel): + bl_context = ".greasepencil_weight" + bl_label = "Appearance" + + +class VIEW3D_PT_gpencil_brush_presets(PresetMenu): + """Brush settings""" + bl_label = "Brush Presets" + preset_subdir = "gpencil_brush" + preset_operator = "script.execute_preset" + preset_add_operator = "scene.gpencil_brush_preset_add" classes = ( @@ -1421,12 +1778,21 @@ classes = ( VIEW3D_PT_tools_projectpaint, VIEW3D_MT_tools_projectpaint_stencil, VIEW3D_PT_tools_particlemode, - VIEW3D_PT_tools_grease_pencil_draw, - VIEW3D_PT_tools_grease_pencil_edit, - VIEW3D_PT_tools_grease_pencil_interpolate, - VIEW3D_PT_tools_grease_pencil_sculpt, + + VIEW3D_PT_gpencil_brush_presets, VIEW3D_PT_tools_grease_pencil_brush, + VIEW3D_PT_tools_grease_pencil_brush_option, + VIEW3D_PT_tools_grease_pencil_brush_settings, + VIEW3D_PT_tools_grease_pencil_brush_stabilizer, + VIEW3D_PT_tools_grease_pencil_brush_random, VIEW3D_PT_tools_grease_pencil_brushcurves, + VIEW3D_PT_tools_grease_pencil_shapes, + VIEW3D_PT_tools_grease_pencil_sculpt, + VIEW3D_PT_tools_grease_pencil_weight_paint, + VIEW3D_PT_tools_grease_pencil_paint_appearance, + VIEW3D_PT_tools_grease_pencil_sculpt_appearance, + VIEW3D_PT_tools_grease_pencil_weight_appearance, + VIEW3D_PT_tools_grease_pencil_interpolate, VIEW3D_PT_tools_normal, ) diff --git a/release/scripts/templates_py/batch_export.py b/release/scripts/templates_py/batch_export.py index 1463915886a..a07491742ec 100644 --- a/release/scripts/templates_py/batch_export.py +++ b/release/scripts/templates_py/batch_export.py @@ -9,9 +9,9 @@ basedir = os.path.dirname(bpy.data.filepath) if not basedir: raise Exception("Blend file is not saved") -scene = bpy.context.scene +view_layer = bpy.context.view_layer -obj_active = scene.objects.active +obj_active = view_layer.objects.active selection = bpy.context.selected_objects bpy.ops.object.select_all(action='DESELECT') @@ -21,7 +21,7 @@ for obj in selection: obj.select_set(action='SELECT') # some exporters only use the active object - scene.objects.active = obj + view_layer.objects.active = obj name = bpy.path.clean_name(obj.name) fn = os.path.join(basedir, name) @@ -36,7 +36,7 @@ for obj in selection: print("written:", fn) -scene.objects.active = obj_active +view_layer.objects.active = obj_active for obj in selection: obj.select_set(action='SELECT') diff --git a/release/scripts/templates_py/operator_modal_view3d_raycast.py b/release/scripts/templates_py/operator_modal_view3d_raycast.py index e3b63813fc4..613501143f7 100644 --- a/release/scripts/templates_py/operator_modal_view3d_raycast.py +++ b/release/scripts/templates_py/operator_modal_view3d_raycast.py @@ -68,7 +68,7 @@ def main(context, event): # we could do lots of stuff but for the example just select. if best_obj is not None: best_obj.select_set(action='SELECT') - context.scene.objects.active = best_obj + context.view_layer.objects.active = best_obj class ViewOperatorRayCast(bpy.types.Operator): |