blender/scripts/startup/bl_ui/space_dopesheet.py

879 lines
29 KiB
Python

# SPDX-FileCopyrightText: 2009-2023 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import (
Header,
Menu,
Panel,
)
from bl_ui.properties_grease_pencil_common import (
GreasePencilLayerMasksPanel,
GreasePencilLayerTransformPanel,
GreasePencilLayerAdjustmentsPanel,
GreasePencilLayerRelationsPanel,
GreasePencilLayerDisplayPanel,
)
from rna_prop_ui import PropertyPanel
#######################################
# DopeSheet Filtering - Header Buttons
# used for DopeSheet, NLA, and Graph Editors
def dopesheet_filter(layout, context):
dopesheet = context.space_data.dopesheet
is_nla = context.area.type == 'NLA_EDITOR'
row = layout.row(align=True)
row.prop(dopesheet, "show_only_selected", text="")
row.prop(dopesheet, "show_hidden", text="")
if is_nla:
row.prop(dopesheet, "show_missing_nla", text="")
else: # graph and dopesheet editors - F-Curves and drivers only
row.prop(dopesheet, "show_only_errors", text="")
#######################################
# Dopesheet Filtering Popovers
# Generic Layout - Used as base for filtering popovers used in all animation editors
# Used for DopeSheet, NLA, and Graph Editors
class DopesheetFilterPopoverBase:
bl_region_type = 'HEADER'
bl_label = "Filters"
# Generic = Affects all datatypes
# XXX: Perhaps we want these to stay in the header instead, for easy/fast access
@classmethod
def draw_generic_filters(cls, context, layout):
dopesheet = context.space_data.dopesheet
is_nla = context.area.type == 'NLA_EDITOR'
col = layout.column(align=True)
col.prop(dopesheet, "show_only_selected", icon='NONE')
col.prop(dopesheet, "show_hidden", icon='NONE')
if is_nla:
col.prop(dopesheet, "show_missing_nla", icon='NONE')
else: # graph and dopesheet editors - F-Curves and drivers only
col.prop(dopesheet, "show_only_errors", icon='NONE')
# Name/Membership Filters
# XXX: Perhaps these should just stay in the headers (exclusively)?
@classmethod
def draw_search_filters(cls, context, layout, generic_filters_only=False):
dopesheet = context.space_data.dopesheet
is_nla = context.area.type == 'NLA_EDITOR'
col = layout.column(align=True)
if not is_nla:
row = col.row(align=True)
row.prop(dopesheet, "filter_fcurve_name", text="")
else:
row = col.row(align=True)
row.prop(dopesheet, "filter_text", text="")
if (not generic_filters_only) and bpy.data.collections:
col = layout.column(align=True)
col.prop(dopesheet, "filter_collection", text="")
# Standard = Present in all panels
@classmethod
def draw_standard_filters(cls, context, layout):
dopesheet = context.space_data.dopesheet
# datablock filters
layout.label(text="Filter by Type:")
flow = layout.grid_flow(row_major=True, columns=2, even_rows=False, align=False)
flow.prop(dopesheet, "show_scenes", text="Scenes")
flow.prop(dopesheet, "show_nodes", text="Node Trees")
# object types
if bpy.data.armatures:
flow.prop(dopesheet, "show_armatures", text="Armatures")
if bpy.data.cameras:
flow.prop(dopesheet, "show_cameras", text="Cameras")
if bpy.data.grease_pencils:
flow.prop(dopesheet, "show_gpencil", text="Grease Pencil Objects")
if bpy.data.lights:
flow.prop(dopesheet, "show_lights", text="Lights")
if bpy.data.meshes:
flow.prop(dopesheet, "show_meshes", text="Meshes")
if bpy.data.curves:
flow.prop(dopesheet, "show_curves", text="Curves")
if bpy.data.lattices:
flow.prop(dopesheet, "show_lattices", text="Lattices")
if bpy.data.metaballs:
flow.prop(dopesheet, "show_metaballs", text="Metaballs")
if hasattr(bpy.data, "hair_curves") and bpy.data.hair_curves:
flow.prop(dopesheet, "show_hair_curves", text="Hair Curves")
if hasattr(bpy.data, "pointclouds") and bpy.data.pointclouds:
flow.prop(dopesheet, "show_pointclouds", text="Point Clouds")
if bpy.data.volumes:
flow.prop(dopesheet, "show_volumes", text="Volumes")
# data types
flow.prop(dopesheet, "show_worlds", text="Worlds")
if bpy.data.particles:
flow.prop(dopesheet, "show_particles", text="Particles")
if bpy.data.linestyles:
flow.prop(dopesheet, "show_linestyles", text="Line Styles")
if bpy.data.speakers:
flow.prop(dopesheet, "show_speakers", text="Speakers")
if bpy.data.materials:
flow.prop(dopesheet, "show_materials", text="Materials")
if bpy.data.textures:
flow.prop(dopesheet, "show_textures", text="Textures")
if bpy.data.shape_keys:
flow.prop(dopesheet, "show_shapekeys", text="Shape Keys")
if bpy.data.cache_files:
flow.prop(dopesheet, "show_cache_files", text="Cache Files")
if bpy.data.movieclips:
flow.prop(dopesheet, "show_movieclips", text="Movie Clips")
layout.separator()
# Object Data Filters
# TODO: Add per-channel/axis convenience toggles?
split = layout.split()
col = split.column()
col.prop(dopesheet, "show_transforms", text="Transforms")
col = split.column()
col.prop(dopesheet, "show_modifiers", text="Modifiers")
layout.separator()
# performance-related options (users will mostly have these enabled)
col = layout.column(align=True)
col.label(text="Options:")
col.prop(dopesheet, "use_datablock_sort", icon='NONE')
# Popover for Dopesheet Editor(s) - Dopesheet, Action, Shapekey, GPencil, Mask, etc.
class DOPESHEET_PT_filters(DopesheetFilterPopoverBase, Panel):
bl_space_type = 'DOPESHEET_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Filters"
def draw(self, context):
layout = self.layout
dopesheet = context.space_data.dopesheet
ds_mode = context.space_data.mode
layout.prop(dopesheet, "show_summary", text="Summary")
DopesheetFilterPopoverBase.draw_generic_filters(context, layout)
if ds_mode in {'DOPESHEET', 'ACTION', 'GPENCIL'}:
layout.separator()
generic_filters_only = ds_mode != 'DOPESHEET'
DopesheetFilterPopoverBase.draw_search_filters(context, layout,
generic_filters_only=generic_filters_only)
if ds_mode == 'DOPESHEET':
layout.separator()
DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
#######################################
# DopeSheet Editor - General/Standard UI
class DOPESHEET_HT_header(Header):
bl_space_type = 'DOPESHEET_EDITOR'
def draw(self, context):
layout = self.layout
st = context.space_data
layout.template_header()
if st.mode == 'TIMELINE':
from bl_ui.space_time import (
TIME_MT_editor_menus,
TIME_HT_editor_buttons,
)
TIME_MT_editor_menus.draw_collapsible(context, layout)
TIME_HT_editor_buttons.draw_header(context, layout)
else:
layout.prop(st, "ui_mode", text="")
DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
DOPESHEET_HT_editor_buttons.draw_header(context, layout)
# Header for "normal" dopesheet editor modes (e.g. Dope Sheet, Action, Shape Keys, etc.)
class DOPESHEET_HT_editor_buttons:
@staticmethod
def draw_header(context, layout):
st = context.space_data
tool_settings = context.tool_settings
if st.mode in {'ACTION', 'SHAPEKEY'}:
# TODO: These buttons need some tidying up -
# Probably by using a popover, and bypassing the template_id() here
row = layout.row(align=True)
row.operator("action.layer_prev", text="", icon='TRIA_DOWN')
row.operator("action.layer_next", text="", icon='TRIA_UP')
row = layout.row(align=True)
row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
row.operator("action.stash", text="Stash", icon='FREEZE')
layout.separator_spacer()
layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
# Layer management
if st.mode == 'GPENCIL':
ob = context.active_object
enable_but = ob is not None and ob.type == 'GPENCIL'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_add", icon='ADD', text="")
row.operator("gpencil.layer_remove", icon='REMOVE', text="")
row.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
row.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
row = layout.row(align=True)
row.enabled = enable_but
row.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
row.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
layout.separator_spacer()
if st.mode == 'DOPESHEET':
dopesheet_filter(layout, context)
elif st.mode == 'ACTION':
dopesheet_filter(layout, context)
elif st.mode == 'GPENCIL':
row = layout.row(align=True)
row.prop(st.dopesheet, "show_only_selected", text="")
row.prop(st.dopesheet, "show_hidden", text="")
layout.popover(
panel="DOPESHEET_PT_filters",
text="",
icon='FILTER',
)
# Grease Pencil mode doesn't need snapping, as it's frame-aligned only
if st.mode != 'GPENCIL':
layout.prop(st, "auto_snap", text="")
row = layout.row(align=True)
row.prop(tool_settings, "use_proportional_action", text="", icon_only=True)
sub = row.row(align=True)
sub.active = tool_settings.use_proportional_action
sub.prop_with_popover(
tool_settings,
"proportional_edit_falloff",
text="",
icon_only=True,
panel="DOPESHEET_PT_proportional_edit",
)
class DOPESHEET_PT_proportional_edit(Panel):
bl_space_type = 'DOPESHEET_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Proportional Editing"
bl_ui_units_x = 8
def draw(self, context):
layout = self.layout
tool_settings = context.tool_settings
col = layout.column()
col.active = tool_settings.use_proportional_action
col.prop(tool_settings, "proportional_edit_falloff", expand=True)
col.prop(tool_settings, "proportional_size")
class DOPESHEET_MT_editor_menus(Menu):
bl_idname = "DOPESHEET_MT_editor_menus"
bl_label = ""
def draw(self, context):
layout = self.layout
st = context.space_data
layout.menu("DOPESHEET_MT_view")
layout.menu("DOPESHEET_MT_select")
if st.show_markers:
layout.menu("DOPESHEET_MT_marker")
if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action is not None):
layout.menu("DOPESHEET_MT_channel")
elif st.mode == 'GPENCIL':
layout.menu("DOPESHEET_MT_gpencil_channel")
if st.mode != 'GPENCIL':
layout.menu("DOPESHEET_MT_key")
else:
layout.menu("DOPESHEET_MT_gpencil_key")
class DOPESHEET_MT_view(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
st = context.space_data
layout.prop(st, "show_region_ui")
layout.prop(st, "show_region_hud")
layout.separator()
layout.prop(st.dopesheet, "use_multi_word_filter", text="Multi-Word Match Search")
layout.separator()
layout.prop(st, "use_realtime_update")
# Sliders are always shown in the Shape Key Editor regardless of this setting.
col = layout.column()
col.active = context.space_data.mode != 'SHAPEKEY'
col.prop(st, "show_sliders")
layout.prop(st, "show_interpolation")
layout.prop(st, "show_extremes")
layout.prop(st, "use_auto_merge_keyframes")
layout.separator()
layout.prop(st, "show_markers")
layout.separator()
layout.prop(st, "show_seconds")
layout.prop(st, "show_locked_time")
layout.separator()
layout.operator("anim.previewrange_set")
layout.operator("anim.previewrange_clear")
layout.operator("action.previewrange_set")
layout.separator()
layout.operator("action.view_all")
layout.operator("action.view_selected")
layout.operator("action.view_frame")
# Add this to show key-binding (reverse action in dope-sheet).
layout.separator()
props = layout.operator("wm.context_set_enum", text="Toggle Graph Editor", icon='GRAPH')
props.data_path = "area.type"
props.value = 'GRAPH_EDITOR'
layout.separator()
layout.menu("INFO_MT_area")
class DOPESHEET_MT_view_pie(Menu):
bl_label = "View"
def draw(self, _context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("action.view_all")
pie.operator("action.view_selected", icon='ZOOM_SELECTED')
pie.operator("action.view_frame")
class DOPESHEET_MT_select(Menu):
bl_label = "Select"
def draw(self, context):
layout = self.layout
layout.operator("action.select_all", text="All").action = 'SELECT'
layout.operator("action.select_all", text="None").action = 'DESELECT'
layout.operator("action.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("action.select_box").axis_range = False
layout.operator("action.select_box", text="Box Select (Axis Range)").axis_range = True
layout.operator("action.select_circle")
layout.operator_menu_enum("action.select_lasso", "mode")
layout.separator()
layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS'
layout.operator("action.select_column", text="Column on Current Frame").mode = 'CFRA'
layout.operator("action.select_column", text="Columns on Selected Markers").mode = 'MARKERS_COLUMN'
layout.operator("action.select_column", text="Between Selected Markers").mode = 'MARKERS_BETWEEN'
layout.separator()
props = layout.operator("action.select_leftright", text="Before Current Frame")
props.extend = False
props.mode = 'LEFT'
props = layout.operator("action.select_leftright", text="After Current Frame")
props.extend = False
props.mode = 'RIGHT'
# FIXME: grease pencil mode isn't supported for these yet, so skip for that mode only
if context.space_data.mode != 'GPENCIL':
layout.separator()
layout.operator("action.select_more")
layout.operator("action.select_less")
layout.separator()
layout.operator("action.select_linked")
class DOPESHEET_MT_marker(Menu):
bl_label = "Marker"
def draw(self, context):
layout = self.layout
from bl_ui.space_time import marker_menu_generic
marker_menu_generic(layout, context)
st = context.space_data
if st.mode in {'ACTION', 'SHAPEKEY'} and st.action:
layout.separator()
layout.prop(st, "show_pose_markers")
if st.show_pose_markers is False:
layout.operator("action.markers_make_local")
layout.prop(st, "use_marker_sync")
#######################################
# Keyframe Editing
class DOPESHEET_MT_channel(Menu):
bl_label = "Channel"
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_CHANNELS'
layout.operator("anim.channels_delete")
layout.separator()
layout.operator("anim.channels_group")
layout.operator("anim.channels_ungroup")
layout.separator()
layout.operator_menu_enum("anim.channels_setting_toggle", "type")
layout.operator_menu_enum("anim.channels_setting_enable", "type")
layout.operator_menu_enum("anim.channels_setting_disable", "type")
layout.separator()
layout.operator("anim.channels_editable_toggle")
layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode")
layout.separator()
layout.operator("anim.channels_expand")
layout.operator("anim.channels_collapse")
layout.separator()
layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
layout.separator()
layout.operator("anim.channels_fcurves_enable")
layout.separator()
layout.operator("anim.channels_view_selected")
class DOPESHEET_MT_key(Menu):
bl_label = "Key"
def draw(self, _context):
layout = self.layout
layout.menu("DOPESHEET_MT_key_transform", text="Transform")
layout.operator_menu_enum("action.snap", "type", text="Snap")
layout.operator_menu_enum("action.mirror", "type", text="Mirror")
layout.separator()
layout.operator("action.keyframe_insert")
layout.separator()
layout.operator("action.frame_jump")
layout.separator()
layout.operator("action.copy")
layout.operator("action.paste")
layout.operator("action.paste", text="Paste Flipped").flipped = True
layout.operator("action.duplicate_move")
layout.operator("action.delete")
layout.separator()
layout.operator_menu_enum("action.keyframe_type", "type", text="Keyframe Type")
layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
layout.operator_menu_enum("action.easing_type", "type", text="Easing Mode")
layout.separator()
layout.operator("action.clean").channels = False
layout.operator("action.clean", text="Clean Channels").channels = True
layout.operator("action.sample")
layout.separator()
layout.operator("graph.euler_filter", text="Discontinuity (Euler) Filter")
class DOPESHEET_MT_key_transform(Menu):
bl_label = "Transform"
def draw(self, _context):
layout = self.layout
layout.operator("transform.transform", text="Move").mode = 'TIME_TRANSLATE'
layout.operator("transform.transform", text="Extend").mode = 'TIME_EXTEND'
layout.operator("transform.transform", text="Slide").mode = 'TIME_SLIDE'
layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE'
class DopesheetActionPanelBase:
bl_region_type = 'UI'
bl_label = "Action"
@classmethod
def draw_generic_panel(cls, _context, layout, action):
layout.label(text=action.name, icon='ACTION')
layout.prop(action, "use_frame_range")
col = layout.column()
col.active = action.use_frame_range
row = col.row(align=True)
row.prop(action, "frame_start", text="Start")
row.prop(action, "frame_end", text="End")
col.prop(action, "use_cyclic")
class DOPESHEET_PT_custom_props_action(PropertyPanel, Panel):
bl_space_type = 'DOPESHEET_EDITOR'
bl_category = "Action"
bl_region_type = 'UI'
bl_context = "data"
_context_path = "active_action"
_property_type = bpy.types.Action
@classmethod
def poll(cls, context):
return bool(context.active_action)
class DOPESHEET_PT_action(DopesheetActionPanelBase, Panel):
bl_space_type = 'DOPESHEET_EDITOR'
bl_category = "Action"
@classmethod
def poll(cls, context):
return bool(context.active_action)
def draw(self, context):
action = context.active_action
self.draw_generic_panel(context, self.layout, action)
#######################################
# Grease Pencil Editing
class DOPESHEET_MT_gpencil_channel(Menu):
bl_label = "Channel"
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_CHANNELS'
layout.operator("anim.channels_delete")
layout.separator()
layout.operator("anim.channels_setting_toggle")
layout.operator("anim.channels_setting_enable")
layout.operator("anim.channels_setting_disable")
layout.separator()
layout.operator("anim.channels_editable_toggle")
# XXX: to be enabled when these are ready for use!
# layout.separator()
# layout.operator("anim.channels_expand")
# layout.operator("anim.channels_collapse")
layout.separator()
layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
layout.separator()
layout.operator("anim.channels_view_selected")
class DOPESHEET_MT_gpencil_key(Menu):
bl_label = "Key"
def draw(self, _context):
layout = self.layout
layout.menu("DOPESHEET_MT_key_transform", text="Transform")
layout.operator_menu_enum("action.snap", "type", text="Snap")
layout.operator_menu_enum("action.mirror", "type", text="Mirror")
layout.separator()
layout.operator("action.keyframe_insert")
layout.separator()
layout.operator("action.delete")
layout.operator("gpencil.interpolate_reverse")
layout.separator()
layout.operator("action.keyframe_type", text="Keyframe Type")
class DOPESHEET_MT_delete(Menu):
bl_label = "Delete"
def draw(self, _context):
layout = self.layout
layout.operator("action.delete")
layout.separator()
layout.operator("action.clean").channels = False
layout.operator("action.clean", text="Clean Channels").channels = True
class DOPESHEET_MT_context_menu(Menu):
bl_label = "Dope Sheet Context Menu"
def draw(self, context):
layout = self.layout
st = context.space_data
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("action.copy", text="Copy", icon='COPYDOWN')
layout.operator("action.paste", text="Paste", icon='PASTEDOWN')
layout.operator("action.paste", text="Paste Flipped", icon='PASTEFLIPDOWN').flipped = True
layout.separator()
layout.operator_menu_enum("action.keyframe_type", "type", text="Keyframe Type")
if st.mode != 'GPENCIL':
layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
layout.operator_menu_enum("action.easing_type", "type", text="Easing Mode")
layout.separator()
layout.operator("action.keyframe_insert").type = 'SEL'
layout.operator("action.duplicate_move")
if st.mode == 'GPENCIL':
layout.separator()
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("action.delete")
if st.mode == 'GPENCIL':
layout.operator("gpencil.interpolate_reverse")
layout.operator("gpencil.frame_clean_duplicate", text="Delete Duplicate Frames")
layout.separator()
layout.operator_menu_enum("action.mirror", "type", text="Mirror")
layout.operator_menu_enum("action.snap", "type", text="Snap")
class DOPESHEET_MT_channel_context_menu(Menu):
bl_label = "Dope Sheet Channel Context Menu"
def draw(self, context):
layout = self.layout
# This menu is used from the graph editor too.
is_graph_editor = context.area.type == 'GRAPH_EDITOR'
layout.separator()
layout.operator("anim.channels_view_selected")
layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
layout.separator()
layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT'
layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT'
layout.separator()
layout.operator("anim.channels_group")
layout.operator("anim.channels_ungroup")
layout.separator()
layout.operator("anim.channels_editable_toggle")
if is_graph_editor:
operator = "graph.extrapolation_type"
else:
operator = "action.extrapolation_type"
layout.operator_menu_enum(operator, "type", text="Extrapolation Mode")
if is_graph_editor:
layout.operator_menu_enum("graph.fmodifier_add", "type", text="Add F-Curve Modifier").only_active = False
layout.separator()
layout.operator("anim.channels_expand")
layout.operator("anim.channels_collapse")
layout.separator()
layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
layout.separator()
layout.operator("anim.channels_delete")
class DOPESHEET_MT_snap_pie(Menu):
bl_label = "Snap"
def draw(self, _context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("action.snap", text="Selection to Current Frame").type = 'CFRA'
pie.operator("action.snap", text="Selection to Nearest Frame").type = 'NEAREST_FRAME'
pie.operator("action.snap", text="Selection to Nearest Second").type = 'NEAREST_SECOND'
pie.operator("action.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER'
class LayersDopeSheetPanel:
bl_space_type = 'DOPESHEET_EDITOR'
bl_region_type = 'UI'
bl_category = "View"
@classmethod
def poll(cls, context):
st = context.space_data
ob = context.object
if st.mode != 'GPENCIL' or ob is None or ob.type != 'GPENCIL':
return False
gpd = ob.data
gpl = gpd.layers.active
if gpl:
return True
return False
class DOPESHEET_PT_gpencil_mode(LayersDopeSheetPanel, Panel):
# bl_space_type = 'DOPESHEET_EDITOR'
# bl_region_type = 'UI'
# bl_category = "View"
bl_label = "Layer"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
ob = context.object
gpd = ob.data
gpl = gpd.layers.active
if gpl:
row = layout.row(align=True)
row.prop(gpl, "blend_mode", text="Blend")
row = layout.row(align=True)
row.prop(gpl, "opacity", text="Opacity", slider=True)
row = layout.row(align=True)
row.prop(gpl, "use_lights")
class DOPESHEET_PT_gpencil_layer_masks(LayersDopeSheetPanel, GreasePencilLayerMasksPanel, Panel):
bl_label = "Masks"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
bl_options = {'DEFAULT_CLOSED'}
class DOPESHEET_PT_gpencil_layer_transform(LayersDopeSheetPanel, GreasePencilLayerTransformPanel, Panel):
bl_label = "Transform"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
bl_options = {'DEFAULT_CLOSED'}
class DOPESHEET_PT_gpencil_layer_adjustments(LayersDopeSheetPanel, GreasePencilLayerAdjustmentsPanel, Panel):
bl_label = "Adjustments"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
bl_options = {'DEFAULT_CLOSED'}
class DOPESHEET_PT_gpencil_layer_relations(LayersDopeSheetPanel, GreasePencilLayerRelationsPanel, Panel):
bl_label = "Relations"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
bl_options = {'DEFAULT_CLOSED'}
class DOPESHEET_PT_gpencil_layer_display(LayersDopeSheetPanel, GreasePencilLayerDisplayPanel, Panel):
bl_label = "Display"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
bl_options = {'DEFAULT_CLOSED'}
classes = (
DOPESHEET_HT_header,
DOPESHEET_PT_proportional_edit,
DOPESHEET_MT_editor_menus,
DOPESHEET_MT_view,
DOPESHEET_MT_select,
DOPESHEET_MT_marker,
DOPESHEET_MT_channel,
DOPESHEET_MT_key,
DOPESHEET_MT_key_transform,
DOPESHEET_MT_gpencil_channel,
DOPESHEET_MT_gpencil_key,
DOPESHEET_MT_delete,
DOPESHEET_MT_context_menu,
DOPESHEET_MT_channel_context_menu,
DOPESHEET_MT_snap_pie,
DOPESHEET_MT_view_pie,
DOPESHEET_PT_filters,
DOPESHEET_PT_action,
DOPESHEET_PT_gpencil_mode,
DOPESHEET_PT_gpencil_layer_masks,
DOPESHEET_PT_gpencil_layer_transform,
DOPESHEET_PT_gpencil_layer_adjustments,
DOPESHEET_PT_gpencil_layer_relations,
DOPESHEET_PT_gpencil_layer_display,
DOPESHEET_PT_custom_props_action,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)