forked from bartvdbraak/blender
5f6b958e96
As reported by zeffi, the "show_points" option was not working in master. It probably broke recently, after some changes meant that the point sizes weren't geting set prior to drawing these points anymore. Since this was originally added as a debugging tool (though it is now somewhat redundant due to the stroke editing functionality, which uses/exposes the same points), this option wasn't really that important. I have decided to add back a toggle for this to the UI though, since it can be used for some interesting effects...
492 lines
17 KiB
Python
492 lines
17 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
|
|
|
|
|
|
def gpencil_stroke_placement_settings(context, layout, gpd):
|
|
col = layout.column(align=True)
|
|
|
|
col.label(text="Stroke Placement:")
|
|
|
|
row = col.row(align=True)
|
|
row.prop_enum(gpd, "draw_mode", 'VIEW')
|
|
row.prop_enum(gpd, "draw_mode", 'CURSOR')
|
|
|
|
if context.space_data.type == 'VIEW_3D':
|
|
row = col.row(align=True)
|
|
row.prop_enum(gpd, "draw_mode", 'SURFACE')
|
|
row.prop_enum(gpd, "draw_mode", 'STROKE')
|
|
|
|
row = col.row(align=False)
|
|
row.active = gpd.draw_mode in {'SURFACE', 'STROKE'}
|
|
row.prop(gpd, "use_stroke_endpoints")
|
|
|
|
|
|
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
|
|
|
|
col = layout.column(align=True)
|
|
|
|
col.label(text="Draw:")
|
|
row = col.row(align=True)
|
|
row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
|
|
row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
|
|
|
|
row = col.row(align=True)
|
|
row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
|
|
row.operator("gpencil.draw", text="Poly").mode = 'DRAW_POLY'
|
|
|
|
row = col.row(align=True)
|
|
row.prop(context.tool_settings, "use_grease_pencil_sessions", text="Continuous Drawing")
|
|
|
|
if context.space_data.type in {'VIEW_3D', 'CLIP_EDITOR'}:
|
|
col.separator()
|
|
col.label("Data Source:")
|
|
row = col.row(align=True)
|
|
if context.space_data.type == 'VIEW_3D':
|
|
row.prop(context.tool_settings, "grease_pencil_source", expand=True)
|
|
elif context.space_data.type == 'CLIP_EDITOR':
|
|
row.prop(context.space_data, "grease_pencil_source", expand=True)
|
|
|
|
gpd = context.gpencil_data
|
|
if gpd:
|
|
col.separator()
|
|
gpencil_stroke_placement_settings(context, col, gpd)
|
|
|
|
if context.space_data.type == 'VIEW_3D':
|
|
col.separator()
|
|
col.separator()
|
|
|
|
col.label(text="Tools:")
|
|
col.operator("gpencil.convert", text="Convert...")
|
|
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'
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return (context.gpencil_data is not None)
|
|
|
|
@staticmethod
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
gpd = context.gpencil_data
|
|
edit_ok = bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
|
|
|
|
col.separator()
|
|
|
|
col.label(text="Select:")
|
|
subcol = col.column(align=True)
|
|
subcol.active = edit_ok
|
|
subcol.operator("gpencil.select_all", text="Select All")
|
|
subcol.operator("gpencil.select_border")
|
|
subcol.operator("gpencil.select_circle")
|
|
|
|
col.separator()
|
|
|
|
subcol = col.column(align=True)
|
|
subcol.active = edit_ok
|
|
subcol.operator("gpencil.select_linked")
|
|
subcol.operator("gpencil.select_more")
|
|
subcol.operator("gpencil.select_less")
|
|
|
|
col.separator()
|
|
|
|
col.label(text="Edit:")
|
|
row = col.row(align=True)
|
|
row.active = edit_ok
|
|
row.operator("gpencil.copy", text="Copy")
|
|
row.operator("gpencil.paste", text="Paste")
|
|
|
|
subcol = col.column(align=True)
|
|
subcol.active = edit_ok
|
|
subcol.operator("gpencil.delete", text="Delete")
|
|
subcol.operator("gpencil.duplicate_move", text="Duplicate")
|
|
subcol.operator("transform.mirror", text="Mirror").gpencil_strokes = True
|
|
|
|
col.separator()
|
|
|
|
subcol = col.column(align=True)
|
|
subcol.active = edit_ok
|
|
subcol.operator("transform.translate").gpencil_strokes = True # icon='MAN_TRANS'
|
|
subcol.operator("transform.rotate").gpencil_strokes = True # icon='MAN_ROT'
|
|
subcol.operator("transform.resize", text="Scale").gpencil_strokes = True # icon='MAN_SCALE'
|
|
|
|
col.separator()
|
|
|
|
subcol = col.column(align=True)
|
|
subcol.active = edit_ok
|
|
subcol.operator("transform.bend", text="Bend").gpencil_strokes = True
|
|
subcol.operator("transform.shear", text="Shear").gpencil_strokes = True
|
|
subcol.operator("transform.tosphere", text="To Sphere").gpencil_strokes = 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.prop(gpd, "use_stroke_edit_mode", text="Exit Edit Mode", icon='EDIT')
|
|
|
|
# N - Transforms
|
|
col = pie.column()
|
|
row = col.row(align=True)
|
|
row.operator("transform.translate", icon='MAN_TRANS').gpencil_strokes = True
|
|
row.operator("transform.rotate", icon='MAN_ROT').gpencil_strokes = True
|
|
row.operator("transform.resize", text="Scale", icon='MAN_SCALE').gpencil_strokes = True
|
|
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')
|
|
|
|
# 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.prop(gpd, "use_stroke_edit_mode", 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
|
|
|
|
# W - Stroke draw settings
|
|
col = pie.column(align=True)
|
|
col.label(text="Stroke")
|
|
col.prop(gpl, "color", text="")
|
|
col.prop(gpl, "alpha", text="", slider=True)
|
|
|
|
# E - Fill draw settings
|
|
col = pie.column(align=True)
|
|
col.label(text="Fill")
|
|
col.prop(gpl, "fill_color", text="")
|
|
col.prop(gpl, "fill_alpha", text="", slider=True)
|
|
|
|
# S - Layer settings
|
|
col = pie.column()
|
|
col.prop(gpl, "line_width", slider=True)
|
|
# col.prop(gpl, "use_volumetric_strokes")
|
|
col.prop(gpl, "use_onion_skinning")
|
|
|
|
# N - Active Layer
|
|
# XXX: this should show an operator to change the active layer instead
|
|
col = pie.column()
|
|
col.label("Active Layer: ")
|
|
col.prop(gpl, "info", text="")
|
|
# col.prop(gpd, "layers")
|
|
row = col.row()
|
|
row.prop(gpl, "lock")
|
|
row.prop(gpl, "hide")
|
|
|
|
|
|
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').gpencil_strokes = True
|
|
pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM').gpencil_strokes = True
|
|
pie.operator("transform.shear", icon='MOD_TRIANGULATE').gpencil_strokes = True
|
|
pie.operator("transform.tosphere", icon='MOD_MULTIRES').gpencil_strokes = True
|
|
|
|
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_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
|
|
|
|
split = layout.split(percentage=0.25)
|
|
row = split.row(align=True)
|
|
row.prop(gpl, "color", text="", emboss=gpl.is_stroke_visible)
|
|
row.prop(gpl, "fill_color", text="", emboss=gpl.is_fill_visible)
|
|
split.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)
|
|
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"
|
|
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:
|
|
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.operator("gpencil.layer_duplicate", icon='COPY_ID', text="") # XXX: needs a dedicated icon
|
|
|
|
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'
|
|
|
|
if gpl:
|
|
self.draw_layer(layout, gpl)
|
|
|
|
def draw_layer(self, layout, gpl):
|
|
# layer settings
|
|
split = layout.split(percentage=0.5)
|
|
split.active = not gpl.lock
|
|
|
|
# Column 1 - Stroke
|
|
col = split.column(align=True)
|
|
col.label(text="Stroke:")
|
|
col.prop(gpl, "color", text="")
|
|
col.prop(gpl, "alpha", slider=True)
|
|
|
|
# Column 2 - Fill
|
|
col = split.column(align=True)
|
|
col.label(text="Fill:")
|
|
col.prop(gpl, "fill_color", text="")
|
|
col.prop(gpl, "fill_alpha", text="Opacity", slider=True)
|
|
|
|
# Options
|
|
split = layout.split(percentage=0.5)
|
|
split.active = not gpl.lock
|
|
|
|
col = split.column(align=True)
|
|
col.prop(gpl, "line_width", slider=True)
|
|
col.prop(gpl, "use_volumetric_strokes")
|
|
|
|
col = split.column(align=True)
|
|
col.prop(gpl, "show_x_ray")
|
|
col.prop(gpl, "show_points", text="Points")
|
|
|
|
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 = "Locked" if gpl.lock_frame else "Unlocked"
|
|
lock_label = "Frame: %d (%s)" % (gpl.active_frame.frame_number, lock_status)
|
|
else:
|
|
lock_label = "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 GreasePencilToolsPanel:
|
|
# 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_stroke_placement_settings(context, layout, gpd)
|