Files
blender/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
Matias Mendiola a7ac8a22f8 GPencil: Animation menu updates
Animation menu updates for Edit Mode and Draw Mode (header and context menu):

- Rename menu items for a better understanding of what the operators really do.
- Change shortcuts (legacy from the old Grease pencil)

{F7708018}

Reviewers: antoniov, pepeland, billreynish

Tags: #bf_blender, #grease_pencil

Differential Revision: https://developer.blender.org/D5617
2019-08-28 22:33:44 +02:00

948 lines
34 KiB
Python

# ##### 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, 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 = "annotation_stroke_placement_view3d"
elif context.space_data.type == 'SEQUENCE_EDITOR':
propname = "annotation_stroke_placement_sequencer_preview"
elif context.space_data.type == 'IMAGE_EDITOR':
propname = "annotation_stroke_placement_image_editor"
else:
propname = "annotation_stroke_placement_view2d"
tool_settings = context.tool_settings
col = layout.column(align=True)
if context.space_data.type != 'VIEW_3D':
col.label(text="Stroke Placement:")
row = col.row(align=True)
row.prop_enum(tool_settings, propname, 'VIEW')
row.prop_enum(tool_settings, propname, 'CURSOR', text="Cursor")
def gpencil_active_brush_settings_simple(context, layout):
tool_settings = context.tool_settings
brush = tool_settings.gpencil_paint.brush
if brush is None:
layout.label(text="No Active Brush")
return
col = layout.column()
col.label(text="Active Brush: ")
row = col.row(align=True)
row.operator_context = 'EXEC_REGION_WIN'
row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
row.prop(brush, "name", text="")
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)
row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE')
row = col.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 = col.row(align=True)
row.prop(brush, "jitter", slider=True)
row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
row = col.row()
row.prop(brush, "angle", slider=True)
row.prop(brush, "angle_factor", text="Factor", slider=True)
# XXX: To be replaced with active tools
class AnnotationDrawingToolsPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Annotation"
bl_category = "Annotation"
bl_region_type = 'TOOLS'
def draw(self, context):
layout = self.layout
is_3d_view = context.space_data.type == 'VIEW_3D'
is_clip_editor = context.space_data.type == 'CLIP_EDITOR'
col = layout.column(align=True)
col.label(text="Draw:")
row = col.row(align=True)
row.operator("gpencil.annotate", icon='GREASEPENCIL', text="Draw").mode = 'DRAW'
# XXX: Needs a dedicated icon
row.operator("gpencil.annotate", icon='FORCE_CURVE', text="Erase").mode = 'ERASER'
row = col.row(align=True)
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()
sub = col.column(align=True)
sub.operator("gpencil.blank_frame_add", icon='FILE_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_draw_additive", 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 == 'CLIP_EDITOR':
col.separator()
col.label(text="Data Source:")
row = col.row(align=True)
if is_3d_view:
row.prop(context.tool_settings, "grease_pencil_source", expand=True)
elif is_clip_editor:
row.prop(context.space_data, "grease_pencil_source", expand=True)
# col.separator()
# col.separator()
gpencil_stroke_placement_settings(context, col)
class GreasePencilStrokeEditPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Edit Strokes"
bl_category = "Tools"
bl_region_type = 'TOOLS'
@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)
def draw(self, context):
layout = self.layout
is_3d_view = context.space_data.type == 'VIEW_3D'
if not is_3d_view:
layout.label(text="Select:")
col = layout.column(align=True)
col.operator("gpencil.select_all", text="Select All")
col.operator("gpencil.select_box")
col.operator("gpencil.select_circle")
layout.separator()
col = layout.column(align=True)
col.operator("gpencil.select_linked")
col.operator("gpencil.select_more")
col.operator("gpencil.select_less")
col.operator("gpencil.select_alternate")
layout.label(text="Edit:")
row = layout.row(align=True)
row.operator("gpencil.copy", text="Copy")
row.operator("gpencil.paste", text="Paste").type = 'ACTIVE'
row.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col = layout.column(align=True)
col.operator("gpencil.delete")
col.operator("gpencil.duplicate_move", text="Duplicate")
if is_3d_view:
col.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
col.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps...", property="type")
layout.separator()
if not is_3d_view:
col = layout.column(align=True)
col.operator("transform.translate") # icon='MAN_TRANS'
col.operator("transform.rotate") # icon='MAN_ROT'
col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
layout.separator()
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="Assign Material")
layout.separator()
col = layout.column(align=True)
col.operator("gpencil.stroke_subdivide", text="Subdivide")
row = col.row(align=True)
row.operator("gpencil.stroke_simplify_fixed", text="Simplify")
row.operator("gpencil.stroke_simplify", text="Adaptive")
row.operator("gpencil.stroke_trim", text="Trim")
col.separator()
row = col.row(align=True)
row.operator("gpencil.stroke_merge", text="Merge")
row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
row.operator("gpencil.stroke_join", text="& Copy").type = 'JOINCOPY'
col.operator("gpencil.stroke_flip", text="Flip Direction")
if is_3d_view:
layout.separator()
col = layout.column(align=True)
col.operator_menu_enum("gpencil.stroke_separate", text="Separate...", property="mode")
col.operator("gpencil.stroke_split", text="Split")
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 = "Tools"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
brush = settings.brush
layout.template_icon_view(settings, "sculpt_tool", show_labels=True)
if not self.is_popover:
from bl_ui.properties_paint_common import (
brush_basic_gpencil_sculpt_settings,
)
brush_basic_gpencil_sculpt_settings(layout, context, brush)
class GreasePencilSculptOptionsPanel:
bl_label = "Sculpt Strokes"
@classmethod
def poll(cls, context):
settings = context.tool_settings.gpencil_sculpt
tool = settings.sculpt_tool
return bool(tool in {'SMOOTH', 'RANDOMIZE', 'SMOOTH'})
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.sculpt_tool
brush = settings.brush
if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.prop(settings, "use_edit_position", text="Affect Position")
layout.prop(settings, "use_edit_strength", text="Affect Strength")
layout.prop(settings, "use_edit_thickness", text="Affect Thickness")
if tool == 'SMOOTH':
layout.prop(brush, "use_edit_pressure")
layout.prop(settings, "use_edit_uv", text="Affect UV")
# GP Object Tool Settings
class GreasePencilAppearancePanel:
bl_label = "Brush Appearance"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.active_object
return ob and ob.type == 'GPENCIL'
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
tool_settings = context.tool_settings
ob = context.active_object
if ob.mode == 'PAINT_GPENCIL':
brush = tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
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 brush.gpencil_tool == 'DRAW':
layout.prop(gp_settings, "show_lasso", text="Show fill color while drawing")
if brush.gpencil_tool == 'FILL':
layout.prop(brush, "cursor_color_add", text="Color")
elif ob.mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
settings = tool_settings.gpencil_sculpt
brush = settings.brush
tool = settings.sculpt_tool
col = layout.column(align=True)
col.prop(brush, "use_cursor", text="Show Brush")
if tool in {'THICKNESS', 'STRENGTH'}:
col.prop(brush, "cursor_color_add", text="Add")
col.prop(brush, "cursor_color_sub", text="Subtract")
elif tool == 'PINCH':
col.prop(brush, "cursor_color_add", text="Pinch")
col.prop(brush, "cursor_color_sub", text="Inflate")
elif tool == 'TWIST':
col.prop(brush, "cursor_color_add", text="CCW")
col.prop(brush, "cursor_color_sub", text="CW")
else:
col.prop(brush, "cursor_color_add", text="")
class GPENCIL_MT_pie_tool_palette(Menu):
"""A pie menu for quick access to Grease Pencil tools"""
bl_label = "Grease Pencil Tools"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
gpd = context.gpencil_data
# W - Drawing Types
col = pie.column()
col.operator("gpencil.draw", text="Draw", icon='GREASEPENCIL').mode = 'DRAW'
col.operator("gpencil.draw", text="Straight Lines", icon='LINE_DATA').mode = 'DRAW_STRAIGHT'
col.operator("gpencil.draw", text="Poly", icon='MESH_DATA').mode = 'DRAW_POLY'
# E - Eraser
# XXX: needs a dedicated icon...
col = pie.column()
col.operator("gpencil.draw", text="Eraser", icon='FORCE_CURVE').mode = 'ERASER'
# E - "Settings" Palette is included here too, since it needs to be in a stable position...
if gpd and gpd.layers.active:
col.separator()
col.operator(
"wm.call_menu_pie",
text="Settings...",
icon='SCRIPTWIN').name = "GPENCIL_MT_pie_settings_palette"
# Editing tools
if gpd:
if gpd.use_stroke_edit_mode and context.editable_gpencil_strokes:
# S - Exit Edit Mode
pie.operator("gpencil.editmode_toggle", text="Exit Edit Mode", icon='EDIT')
# N - Transforms
col = pie.column()
row = col.row(align=True)
row.operator("transform.translate", icon='MAN_TRANS')
row.operator("transform.rotate", icon='MAN_ROT')
row.operator("transform.resize", text="Scale", icon='MAN_SCALE')
row = col.row(align=True)
row.label(text="Proportional Edit:")
row.prop(context.tool_settings, "use_proportional_edit", text="", icon_only=True)
row.prop(context.tool_settings, "proportional_edit_falloff", text="", icon_only=True)
# NW - Select (Non-Modal)
col = pie.column()
col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
col.operator("gpencil.select_all", text="Select Inverse", icon='BLANK1')
col.operator("gpencil.select_linked", text="Select Linked", icon='LINKED')
col.operator("gpencil.palettecolor_select", text="Select Color", icon='COLOR')
# NE - Select (Modal)
col = pie.column()
col.operator("gpencil.select_box", text="Box 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()
col.operator("gpencil.duplicate_move", icon='PARTICLE_PATH', text="Duplicate")
col.operator("gpencil.delete", icon='X', text="Delete...")
# SE - More Tools
pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_MT_pie_tools_more"
else:
# Toggle Edit Mode
pie.operator("gpencil.editmode_toggle", text="Enable Stroke Editing", icon='EDIT')
class GPENCIL_MT_pie_settings_palette(Menu):
"""A pie menu for quick access to Grease Pencil settings"""
bl_label = "Grease Pencil Settings"
@classmethod
def poll(cls, context):
return bool(context.gpencil_data and context.active_gpencil_layer)
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
gpd = context.gpencil_data
gpl = context.active_gpencil_layer
palcolor = None # context.active_gpencil_palettecolor
is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
# W - Stroke draw settings
col = pie.column(align=True)
if palcolor is not None:
col.enabled = not palcolor.lock
col.label(text="Stroke")
col.prop(palcolor, "color", text="")
col.prop(palcolor, "alpha", text="", slider=True)
# E - Fill draw settings
col = pie.column(align=True)
if palcolor is not None:
col.enabled = not palcolor.lock
col.label(text="Fill")
col.prop(palcolor, "fill_color", text="")
col.prop(palcolor, "fill_alpha", text="", slider=True)
# S Brush settings
gpencil_active_brush_settings_simple(context, pie)
# N - Active Layer
col = pie.column()
col.label(text="Active Layer: ")
row = col.row()
row.operator_context = 'EXEC_REGION_WIN'
row.operator_menu_enum("gpencil.layer_change", "layer", text="", icon='GREASEPENCIL')
row.prop(gpl, "info", text="")
row.operator("gpencil.layer_remove", text="", icon='X')
row = col.row()
row.prop(gpl, "lock")
row.prop(gpl, "hide")
col.prop(gpl, "use_onion_skinning")
# NW/NE/SW/SE - These operators are only available in editmode
# as they require strokes to be selected to work
if is_editmode:
# NW - Move stroke Down
col = pie.column(align=True)
col.label(text="Arrange Strokes")
col.operator("gpencil.stroke_arrange", text="Send to Back").direction = 'BOTTOM'
col.operator("gpencil.stroke_arrange", text="Send Backward").direction = 'DOWN'
# NE - Move stroke Up
col = pie.column(align=True)
col.label(text="Arrange Strokes")
col.operator("gpencil.stroke_arrange", text="Bring to Front").direction = 'TOP'
col.operator("gpencil.stroke_arrange", text="Bring Forward").direction = 'UP'
# SW - Move stroke to color
col = pie.column(align=True)
col.operator("gpencil.stroke_change_color", text="Move to Color")
# SE - Join strokes
col = pie.column(align=True)
col.label(text="Join Strokes")
row = col.row()
row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
row.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
col.operator("gpencil.stroke_flip", text="Flip Direction")
col.prop(gpd, "show_stroke_direction", text="Show Drawing Direction")
class GPENCIL_MT_pie_tools_more(Menu):
"""A pie menu for accessing more Grease Pencil tools"""
bl_label = "More Grease Pencil Tools"
@classmethod
def poll(cls, context):
gpd = context.gpencil_data
return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
def draw(self, _context):
layout = self.layout
pie = layout.menu_pie()
# gpd = context.gpencil_data
col = pie.column(align=True)
col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col = pie.column(align=True)
col.operator("gpencil.select_more", icon='ADD')
col.operator("gpencil.select_less", icon='REMOVE')
pie.operator("transform.mirror", icon='MOD_MIRROR')
pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM')
pie.operator("transform.shear", icon='MOD_TRIANGULATE')
pie.operator("transform.tosphere", icon='MOD_MULTIRES')
pie.operator("gpencil.convert", icon='OUTLINER_OB_CURVE', text="Convert...")
pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_MT_pie_tool_palette"
class GPENCIL_MT_pie_sculpt(Menu):
"""A pie menu for accessing Grease Pencil stroke sculpt settings"""
bl_label = "Grease Pencil Sculpt"
@classmethod
def poll(cls, context):
gpd = context.gpencil_data
return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
settings = context.tool_settings.gpencil_sculpt
brush = settings.brush
# W - Launch Sculpt Mode
col = pie.column()
# col.label(text="Tool:")
col.prop(settings, "sculpt_tool", text="")
col.operator("gpencil.sculpt_paint", text="Sculpt", icon='SCULPTMODE_HLT')
# E - Common Settings
col = pie.column(align=True)
col.prop(brush, "size", slider=True)
row = col.row(align=True)
row.prop(brush, "strength", slider=True)
# row.prop(brush, "use_pressure_strength", text="", icon_only=True)
col.prop(brush, "use_falloff")
if settings.sculpt_tool in {'SMOOTH', 'RANDOMIZE'}:
row = col.row(align=True)
row.prop(settings, "use_edit_position", text="Position", icon='MESH_DATA', toggle=True)
row.prop(settings, "use_edit_strength", text="Strength", icon='COLOR', toggle=True)
row.prop(settings, "use_edit_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
# S - Change Brush Type Shortcuts
row = pie.row()
row.prop_enum(settings, "tool", value='GRAB')
row.prop_enum(settings, "tool", value='PUSH')
row.prop_enum(settings, "tool", value='CLONE')
# N - Change Brush Type Shortcuts
row = pie.row()
row.prop_enum(settings, "tool", value='SMOOTH')
row.prop_enum(settings, "tool", value='THICKNESS')
row.prop_enum(settings, "tool", value='STRENGTH')
row.prop_enum(settings, "tool", value='RANDOMIZE')
class GPENCIL_MT_snap(Menu):
bl_label = "Snap"
def draw(self, _context):
layout = self.layout
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 (Keep Offset)").use_offset = True
layout.separator()
layout.operator("gpencil.snap_cursor_to_selected", text="Cursor to Selected")
layout.operator("view3d.snap_cursor_to_center", text="Cursor to World Origin")
layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
class GPENCIL_MT_gpencil_draw_delete(Menu):
bl_label = "Delete"
def draw(self, _context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("gpencil.delete", text="Delete Active Keyframe (Active Layer)").type = 'FRAME'
layout.operator("gpencil.active_frames_delete_all", text="Delete Active Keyframes (All Layers)")
class GPENCIL_MT_cleanup(Menu):
bl_label = "Clean Up"
def draw(self, _context):
ob = _context.active_object
layout = self.layout
layout.operator("gpencil.frame_clean_loose", text="Delete Loose Points")
if ob.mode != 'PAINT_GPENCIL':
layout.operator("gpencil.stroke_merge_by_distance", text="Merge by Distance")
layout.separator()
layout.operator("gpencil.frame_clean_fill", text="Boundary Strokes").mode = 'ACTIVE'
layout.operator("gpencil.frame_clean_fill", text="Boundary Strokes all Frames").mode = 'ALL'
if ob.mode != 'PAINT_GPENCIL':
layout.separator()
layout.operator("gpencil.reproject")
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
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if gpl.lock:
layout.active = False
split = layout.split(factor=0.2)
split.prop(gpl, "color", text="", emboss=True)
split.prop(gpl, "info", text="", emboss=False)
row = layout.row(align=True)
row.prop(gpl, "annotation_hide", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
class AnnotationDataPanel:
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
def draw_header(self, context):
if context.space_data.type not in {'VIEW_3D', 'TOPBAR'}:
self.layout.prop(context.space_data, "show_annotation", text="")
def draw(self, context):
layout = self.layout
layout.use_property_decorate = False
# Grease Pencil owner.
gpd_owner = context.gpencil_data_owner
gpd = context.gpencil_data
# Owner selector.
if context.space_data.type == 'CLIP_EDITOR':
layout.row().prop(context.space_data, "grease_pencil_source", expand=True)
layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink")
# List of layers/notes.
if gpd and gpd.layers:
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 = 3
col.template_list("GPENCIL_UL_annotation_layer", "", gpd, "layers", gpd.layers, "active_index",
rows=layer_rows, sort_reverse=True, sort_lock=True)
col = row.column()
sub = col.column(align=True)
sub.operator("gpencil.layer_add", icon='ADD', text="")
sub.operator("gpencil.layer_remove", icon='REMOVE', text="")
gpl = context.active_gpencil_layer
if gpl:
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'
tool_settings = context.tool_settings
if gpd and gpl:
layout.prop(gpl, "thickness")
else:
layout.prop(tool_settings, "annotation_thickness", text="Thickness")
if gpl:
# 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')
class AnnotationOnionSkin:
bl_label = "Onion Skin"
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:
gpl = context.active_gpencil_layer
if gpl is None:
return False
return True
def draw_header(self, context):
gpl = context.active_gpencil_layer
self.layout.prop(gpl, "use_annotation_onion_skinning", text="")
def draw(self, context):
layout = self.layout
layout.use_property_decorate = False
gpl = context.active_gpencil_layer
col = layout.column()
split = col.split(factor=0.5)
split.active = gpl.use_annotation_onion_skinning
# - Before Frames
sub = split.column(align=True)
row = sub.row(align=True)
row.prop(gpl, "annotation_onion_before_color", text="")
sub.prop(gpl, "annotation_onion_before_range", text="Before")
# - After Frames
sub = split.column(align=True)
row = sub.row(align=True)
row.prop(gpl, "annotation_onion_after_color", text="")
sub.prop(gpl, "annotation_onion_after_range", text="After")
class GreasePencilToolsPanel:
# For use in "2D" Editors without their own toolbar
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Grease Pencil Settings"
bl_region_type = 'UI'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
# XXX - disabled in 2.8 branch.
return False
return (context.gpencil_data is not None)
def draw(self, context):
layout = self.layout
gpencil_active_brush_settings_simple(context, layout)
layout.separator()
gpencil_stroke_placement_settings(context, layout)
class GreasePencilMaterialsPanel:
# Mix-in, use for properties editor and top-bar.
def draw(self, context):
layout = self.layout
show_full_ui = (self.bl_space_type == 'PROPERTIES')
is_view3d = (self.bl_space_type == 'VIEW_3D')
tool_settings = context.scene.tool_settings
gpencil_paint = tool_settings.gpencil_paint
brush = gpencil_paint.brush
ob = context.object
row = layout.row()
if ob:
is_sortable = len(ob.material_slots) > 1
rows = 7
row.template_list("GPENCIL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
# if topbar popover and brush pinned, disable
if is_view3d and brush is not None:
gp_settings = brush.gpencil_settings
if gp_settings.use_material_pin:
row.enabled = False
col = row.column(align=True)
if show_full_ui:
col.operator("object.material_slot_add", icon='ADD', text="")
col.operator("object.material_slot_remove", icon='REMOVE', text="")
col.menu("GPENCIL_MT_color_context_menu", 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_ON', text="").affect_visibility = True
if show_full_ui:
row = layout.row()
row.template_ID(ob, "active_material", new="material.new", live_icon=True)
slot = context.material_slot
if slot:
icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
row.prop(slot, "link", icon=icon_link, icon_only=True)
if ob.data.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.stroke_change_color", text="Assign")
row.operator("gpencil.color_select", text="Select").deselect = False
row.operator("gpencil.color_select", text="Deselect").deselect = True
# stroke color
ma = None
if is_view3d and brush is not None:
gp_settings = brush.gpencil_settings
if gp_settings.use_material_pin is False:
ma = ob.material_slots[ob.active_material_index].material
else:
ma = gp_settings.material
if ma is not None and ma.grease_pencil is not None:
gpcolor = ma.grease_pencil
if (
gpcolor.stroke_style == 'SOLID' or
gpcolor.use_stroke_pattern or
gpcolor.use_stroke_texture_mix
):
row = layout.row()
row.prop(gpcolor, "color", text="Stroke Color")
else:
space = context.space_data
row.template_ID(space, "pin_id")
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
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if gpl.lock:
layout.active = False
row = layout.row(align=True)
row.label(
text="",
icon='BONE_DATA' if gpl.is_parented else 'BLANK1',
)
row.prop(gpl, "info", text="", emboss=False)
row = layout.row(align=True)
row.prop(gpl, "mask_layer", text="",
icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE',
emboss=False)
row.prop(gpl, "lock", text="", emboss=False)
row.prop(gpl, "hide", text="", emboss=False)
subrow = row.row(align=True)
subrow.prop(
gpl,
"use_onion_skinning",
text="",
icon='ONIONSKIN_ON' if gpl.use_onion_skinning else 'ONIONSKIN_OFF',
emboss=False,
)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(
text="",
icon_value=icon,
)
classes = (
GPENCIL_MT_pie_tool_palette,
GPENCIL_MT_pie_settings_palette,
GPENCIL_MT_pie_tools_more,
GPENCIL_MT_pie_sculpt,
GPENCIL_MT_snap,
GPENCIL_MT_cleanup,
GPENCIL_MT_gpencil_draw_delete,
GPENCIL_UL_annotation_layer,
GPENCIL_UL_layer,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)