Files
blender/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
Antonioya ac7ff55f11 GPencil: New subdivide stroke operator
In some situations the artist needs to subdivide a stroke created with
few points before, specially for sculpting.

The subdivision is done for any pair of continuous selected points in
the same stroke.

The operator can be activated in edit mode with W key and has a
parameter for number of cuts.
2016-09-16 10:32:39 +02:00

1066 lines
39 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>
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"
elif context.space_data.type == 'SEQUENCE_EDITOR':
propname = "gpencil_stroke_placement_sequencer_preview"
elif context.space_data.type == 'IMAGE_EDITOR':
propname = "gpencil_stroke_placement_image_editor"
else:
propname = "gpencil_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':
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")
def gpencil_active_brush_settings_simple(context, layout):
brush = context.active_gpencil_brush
col = layout.column()
col.label("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, "line_width", 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)
class GreasePencilDrawingToolsPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Grease Pencil"
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
@staticmethod
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.draw", icon='GREASEPENCIL', text="Draw").mode = 'DRAW'
row.operator("gpencil.draw", 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'
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'}:
col.separator()
col.label("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)
gpd = context.gpencil_data
if gpd and not is_3d_view:
layout.separator()
layout.separator()
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_region_type = 'TOOLS'
bl_options = {'DEFAULT_CLOSED'}
@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
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_border")
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.palettecolor_select")
layout.label(text="Edit:")
row = layout.row(align=True)
row.operator("gpencil.copy", text="Copy")
row.operator("gpencil.paste", text="Paste").type = 'COPY'
row.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
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'
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()
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 = layout.column(align=True)
col.operator("gpencil.interpolate", text="Interpolate")
col.operator("gpencil.interpolate_sequence", text="Sequence")
settings = context.tool_settings.gpencil_sculpt
col.prop(settings, "interpolate_all_layers")
col.prop(settings, "interpolate_selected_only")
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("gpencil.reproject")
class GreasePencilBrushPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Drawing Brushes"
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
@staticmethod
def draw(self, context):
layout = self.layout
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)
col = row.column()
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'
# 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)
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)
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):
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_sculpt
tool = settings.tool
brush = settings.brush
layout.column().prop(settings, "tool")
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")
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()
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")
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")
class GreasePencilBrushCurvesPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Brush Curves"
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
if context.active_gpencil_brush is None:
return False
brush = context.active_gpencil_brush
return bool(brush)
@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.label("Strength")
box = layout.box()
box.template_curve_mapping(brush, "curve_strength", brush=True)
layout.label("Jitter")
box = layout.box()
box.template_curve_mapping(brush, "curve_jitter", brush=True)
###############################
class GPENCIL_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_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("Proportional Edit:")
row.prop(context.tool_settings, "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_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')
# 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_PIE_tools_more"
else:
# Toggle Edit Mode
pie.operator("gpencil.editmode_toggle", text="Enable Stroke Editing", icon='EDIT')
class GPENCIL_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 = context.active_gpencil_palettecolor
brush = context.active_gpencil_brush
# W - Stroke draw settings
col = pie.column(align=True)
if palcolor is not None:
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.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("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 - Move stroke Down
col = pie.column(align=True)
col.label("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("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("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")
gpd = context.gpencil_data
if gpd:
col.prop(gpd, "show_stroke_direction", text="Show drawing direction")
class GPENCIL_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", icon='COPYDOWN', text="Copy")
col.operator("gpencil.paste", icon='PASTEDOWN', text="Paste")
col = pie.column(align=True)
col.operator("gpencil.select_more", icon='ZOOMIN')
col.operator("gpencil.select_less", icon='ZOOMOUT')
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_PIE_tool_palette"
class GPENCIL_PIE_sculpt(Menu):
"""A pie menu for accessing Grease Pencil stroke sculpting 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("Tool:")
col.prop(settings, "tool", text="")
col.operator("gpencil.brush_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.tool in {'SMOOTH', 'RANDOMIZE'}:
row = col.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)
# 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 (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 Center")
layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
###############################
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.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_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)
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)
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 GPENCIL_MT_brush_specials(Menu):
bl_label = "Layer"
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")
class GPENCIL_MT_palettecolor_specials(Menu):
bl_label = "Layer"
def draw(self, context):
layout = self.layout
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()
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")
layout.separator()
layout.operator("gpencil.palettecolor_select", icon='COLOR', text="Select Strokes")
layout.operator("gpencil.stroke_change_color", icon='MAN_TRANS', text="Move to Color")
class GreasePencilDataPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Grease Pencil Layers"
bl_region_type = 'UI'
@staticmethod
def draw_header(self, context):
self.layout.prop(context.space_data, "show_grease_pencil", text="")
@staticmethod
def draw(self, context):
layout = self.layout
# owner of Grease Pencil data
gpd_owner = context.gpencil_data_owner
gpd = context.gpencil_data
# Owner Selector
if context.space_data.type == 'VIEW_3D':
layout.prop(context.tool_settings, "grease_pencil_source", expand=True)
elif context.space_data.type == 'CLIP_EDITOR':
layout.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:
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
if gpl:
self.draw_layer(context, layout, gpl)
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.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
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')
layout.separator()
# Onion skinning
col = layout.column(align=True)
col.active = not gpl.lock
row = col.row()
row.prop(gpl, "use_onion_skinning")
row.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'
@classmethod
def poll(cls, context):
if context.gpencil_data is None:
return False
gpd = context.gpencil_data
return bool(gpd.layers.active)
@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)
col = row.column()
sub = col.column(align=True)
sub.operator("gpencil.palettecolor_add", icon='ZOOMIN', text="")
sub.operator("gpencil.palettecolor_remove", icon='ZOOMOUT', text="")
palcol = context.active_gpencil_palettecolor
if palcol:
sub.menu("GPENCIL_MT_palettecolor_specials", icon='DOWNARROW_HLT', text="")
if len(palette.colors) > 1:
col.separator()
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.active = 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.active = 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")
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'
@classmethod
def poll(cls, context):
return (context.gpencil_data is not None)
@staticmethod
def draw(self, context):
layout = self.layout
# gpd_owner = context.gpencil_data_owner
gpd = context.gpencil_data
layout.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
layout.separator()
layout.label("Proportional Edit:")
row = layout.row()
row.prop(context.tool_settings, "proportional_edit", text="")
row.prop(context.tool_settings, "proportional_edit_falloff", text="")
layout.separator()
layout.separator()
gpencil_active_brush_settings_simple(context, layout)
layout.separator()
gpencil_stroke_placement_settings(context, layout)