blender/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
Joshua Leung d92d8c3768 GPencil: Some tweaks to make GPencil UI more compact when there are 0 or 1 layer(s) only
As brought up in T43595, the Grease Pencil layers list could sometimes end up
taking up too much space when there are no layers. Another issue raised there
was that the up/down buttons are redundant when there is only a single layer.
This commit makes some changes to get these a bit more compact for the case where
you have an empty GPencil datablock left over from previous work.
2015-02-13 02:48:49 +13:00

494 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 in {'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")
# if debug:
# layout.prop(gpl, "show_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)