import bpy
from bpy.types import Panel
from bpy.app.translations import pgettext_iface as iface_
from ... utility import addon
gmods_dic = {
'GP_NOISE': 'MOD_NOISE',
'GP_SMOOTH': 'MOD_SMOOTH',
'GP_SUBDIV': 'MOD_SUBSURF',
'GP_SIMPLIFY': 'MOD_SIMPLIFY',
'GP_THICK': 'MOD_THICKNESS',
'GP_TEXTURE': 'TEXTURE',
'GP_TINT': 'MOD_TINT',
'GP_TIME': 'MOD_TIME',
'GP_COLOR': 'MOD_HUE_SATURATION',
'GP_OPACITY': 'MOD_OPACITY',
'GP_ARRAY': 'MOD_ARRAY',
'GP_BUILD': 'MOD_BUILD',
'GP_LATTICE': 'MOD_LATTICE',
'GP_MIRROR': 'MOD_MIRROR',
'GP_HOOK': 'HOOK',
'GP_OFFSET': 'MOD_OFFSET',
'GP_ARMATURE': 'MOD_ARMATURE',
'GP_MULTIPLY': 'GP_MULTIFRAME_EDITING'
}
class ModifierButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "modifier"
bl_options = {'HIDE_HEADER'}
class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
bl_label = "Modifiers"
def check_conflicts(self, layout, ob):
if ob.type == 'GPENCIL':
mods_s = 'grease_pencil_modifiers'
else:
mods_s = 'modifiers'
for md in getattr(ob, mods_s):
if md.type == 'mtype':
row = layout.row()
row.label(text="Build and Time Offset modifier not compatible", icon='ERROR')
break
@classmethod
def poll(cls, context):
ob = context.object
return ob and ob.type in {'GPENCIL', 'GREASEPENCIL'}
def draw(self, context):
layout = self.layout
ob = context.object
if ob.type == 'GPENCIL':
name_space = "gpencil"
mods_s = 'grease_pencil_modifiers'
template = layout.template_greasepencil_modifier
else:
name_space = "grease_pencil"
mods_s = 'modifiers'
template = layout.template_grease_pencil_modifier
layout.operator_menu_enum(f"object.{name_space}_modifier_add", "type")
for md in getattr(ob, mods_s):
box = template(md)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(self, md.type)(box, ob, md)
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
# so each type must have a function here.
def gpencil_masking(self, layout, ob, md, use_vertex, use_curve=False, use_mat=True):
layout.use_property_split = True
layout.use_property_decorate = True
gpd = ob.data
row = layout.row(align=True)
layout.use_property_split = False
row.prop_search(md, "layer", gpd, "layers", icon='GREASEPENCIL')
layout.use_property_split = True
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
layout.use_property_split = False
row.prop(md, "layer_pass", text="Pass")
layout.use_property_split = True
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
if use_mat:
row = layout.row(align=True)
valid = md.material in (slot.material for slot in ob.material_slots) or md.material is None
if valid:
icon = 'SHADING_TEXTURE'
else:
icon = 'ERROR'
row.alert = not valid
layout.use_property_split = False
row.prop_search(md, "material", gpd, "materials", icon=icon)
layout.use_property_split = True
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
layout.use_property_split = False
row.prop(md, "pass_index", text="Pass")
layout.use_property_split = True
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
if use_vertex:
row = layout.row(align=True)
layout.use_property_split = False
row.prop_search(md, "vertex_group", ob, "vertex_groups")
layout.use_property_split = True
row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
if use_curve:
col = layout.column()
col.separator()
col.prop(md, "use_custom_curve")
if md.use_custom_curve:
col.template_curve_mapping(md, "curve")
def GP_NOISE(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "factor", text="Position")
layout.prop(md, "factor_strength", text="Strength")
layout.prop(md, "factor_thickness", text="Thickness")
layout.prop(md, "factor_uvs", text="UV")
layout.prop(md, "noise_scale")
layout.use_property_split = False
layout.prop(md, "random", text="Randomize")
layout.use_property_split = True
if md.random:
layout.prop(md, "step")
layout.prop(md, "seed")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gnoice_influence", text="Influence")
if addon.preference().modifier.gnoice_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, True, True)
layout.separator()
def GP_SMOOTH(self, layout, ob, md):
layout.use_property_split = False
layout.use_property_decorate = True
layout.separator()
row = layout.row(align=True)
row.prop(md, "use_edit_position", text="Position", toggle=True)
row.prop(md, "use_edit_strength", text="Strength", toggle=True)
row.prop(md, "use_edit_thickness", text="Thickness", toggle=True)
row.prop(md, "use_edit_uv", text="UV", toggle=True)
layout.use_property_split = True
layout.prop(md, "factor")
layout.prop(md, "step", text="Repeat")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gsmooth_influence", text="Influence")
if addon.preference().modifier.gsmooth_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, True, True)
def GP_SUBDIV(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.row().prop(md, "subdivision_type")
layout.prop(md, "level", text="Subdivisions")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gsubsurf_influence", text="Influence")
if addon.preference().modifier.gsubsurf_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()
def GP_SIMPLIFY(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "mode")
if md.mode == 'FIXED':
layout.prop(md, "step")
elif md.mode == 'ADAPTIVE':
layout.prop(md, "factor")
elif md.mode == 'SAMPLE':
layout.prop(md, "length")
elif md.mode == 'MERGE':
layout.prop(md, "distance")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gsimplify_influence", text="Influence")
if addon.preference().modifier.gsimplify_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()
def GP_THICK(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "normalize_thickness")
if md.normalize_thickness:
layout.prop(md, "thickness")
else:
layout.prop(md, "thickness_factor")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gthick_influence", text="Influence")
if addon.preference().modifier.gthick_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, True, True)
layout.separator()
def GP_TEXTURE(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "mode")
if md.mode in {'STROKE', 'STROKE_AND_FILL'}:
layout.prop(md, "fit_method")
layout.prop(md, "uv_offset")
layout.prop(md, "uv_scale")
if md.mode == 'STROKE_AND_FILL':
layout.separator()
if md.mode in {'FILL', 'STROKE_AND_FILL'}:
layout.prop(md, "fill_rotation", text="Rotation")
layout.prop(md, "fill_offset", text="Location")
layout.prop(md, "fill_scale", text="Scale")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gtex_influence", text="Influence")
if addon.preference().modifier.gtex_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, True)
layout.separator()
def GP_TINT(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "vertex_mode")
layout.prop(md, "factor")
layout.row().prop(md, "tint_type", expand=True)
if md.tint_type == 'UNIFORM':
layout.prop(md, "color")
if md.tint_type == 'GRADIENT':
layout.template_color_ramp(md, "colors")
layout.prop(md, "object", text="Object")
layout.prop(md, "radius")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gtint_influence", text="Influence")
if addon.preference().modifier.gtint_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, True, True)
layout.separator()
def GP_TIME(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
gpd = ob.data
row = layout.row()
row.prop(md, "mode", text="Mode")
row = layout.row()
if md.mode == 'FIX':
txt = "Frame"
else:
txt = "Frame Offset"
row.prop(md, "offset", text=txt)
row = layout.row()
row.enabled = md.mode != 'FIX'
row.prop(md, "frame_scale")
row = layout.row()
row.enabled = md.mode != 'FIX'
row.prop(md, "use_keep_loop")
row = layout.row()
row.separator()
row = layout.row()
row.enabled = md.mode != 'FIX'
row.use_property_split = False
row.prop(md, "use_custom_frame_range")
row.use_property_split = True
if md.use_custom_frame_range:
col = layout.column(align=True)
col.enabled = md.mode != 'FIX' and md.use_custom_frame_range is True
col.prop(md, "frame_start")
col.prop(md, "frame_end")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gtime_influence", text="Influence")
if addon.preference().modifier.gtime_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False, use_mat=False)
layout.separator()
def GP_COLOR(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "modify_color")
layout.prop(md, "hue", text="H", slider=True)
layout.prop(md, "saturation", text="S", slider=True)
layout.prop(md, "value", text="V", slider=True)
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gcolor_influence", text="Influence")
if addon.preference().modifier.gcolor_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False, True)
layout.separator()
def GP_OPACITY(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "modify_color")
if md.modify_color == 'HARDNESS':
layout.prop(md, "hardness")
show = False
else:
layout.prop(md, "normalize_opacity")
if md.normalize_opacity is True:
text = "Strength"
else:
text = "Opacity Factor"
layout.prop(md, "factor", text=text)
show = True
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gopacity_influence", text="Influence")
if addon.preference().modifier.gopacity_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, show, show)
layout.separator()
def GP_ARRAY(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "count")
layout.prop(md, "replace_material", text='Material Override')
layout.use_property_split = False
layout.prop(md, "use_relative_offset", text="Relative Offset")
if md.use_relative_offset:
layout.use_property_split = True
layout.prop(md, "relative_offset", expand=True)
layout.use_property_split = False
layout.prop(md, "use_constant_offset", text="Constant Offset")
if md.use_constant_offset:
layout.use_property_split = True
layout.prop(md, "constant_offset", expand=True)
layout.use_property_split = False
layout.prop(md, "use_object_offset")
if md.use_object_offset:
layout.use_property_split = True
layout.prop(md, "offset_object", expand=True)
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "garray_random", text="Randomize")
if addon.preference().modifier.garray_random:
layout.use_property_split = True
layout.prop(md, "random_offset")
layout.prop(md, "random_rotation")
layout.prop(md, "random_scale")
layout.prop(md, "seed")
layout.separator()
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "garray_influence", text="Influence")
if addon.preference().modifier.garray_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()
def GP_BUILD(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
self.check_conflicts(self, layout, ob)
layout.prop(md, "mode")
if md.mode == 'CONCURRENT':
layout.prop(md, "concurrent_time_alignment")
layout.separator()
layout.prop(md, "transition")
layout.prop(md, "start_delay")
layout.prop(md, "length")
row = layout.row(heading="Use Factor", align=True)
layout.use_property_split = False
row.prop(md, "use_percentage", text='')
row.prop(md, "percentage_factor", text='')
layout.use_property_split = False
layout.prop(md, "use_restrict_frame_range", text='Custom Range')
if md.use_restrict_frame_range:
layout.use_property_split = True
layout.prop(md, "frame_start", text="Start")
layout.prop(md, "frame_end", text="End")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "build_influence", text="Influence")
if addon.preference().modifier.build_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False, use_mat=False)
layout.separator()
def GP_LATTICE(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "object")
if md.object and md.object.type == 'ARMATURE':
layout.prop_search(md, "subtarget", md.object.data, "bones", text="")
row = layout.row(align=True)
layout.use_property_split = False
row.prop_search(md, "vertex_group", ob, "vertex_groups")
layout.use_property_split = True
row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
layout.prop(md, "strength", slider=True)
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "glattice_influence", text="Influence")
if addon.preference().modifier.glattice_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()
def GP_MIRROR(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
row = layout.row(heading='Axis', align=True)
if bpy.app.version > (2, 90, 0):
x, y, z = "use_axis_x", "use_axis_y", "use_axis_z"
else:
x, y, z = "x_axis", "y_axis", "z_axis"
row.prop(md, x, toggle=True)
row.prop(md, y, toggle=True)
row.prop(md, z, toggle=True)
layout.prop(md, "object")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gmirror_influence", text="Influence")
if addon.preference().modifier.gmirror_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()
def GP_HOOK(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "object")
if md.object and md.object.type == 'ARMATURE':
layout.prop_search(md, "subtarget", md.object.data, "bones", text="")
row = layout.row(align=True)
layout.use_property_split = False
row.prop_search(md, "vertex_group", ob, "vertex_groups")
layout.use_property_split = True
row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
layout.prop(md, "strength", slider=True)
use_falloff = (md.falloff_type != 'NONE')
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "ghook_falloff", text="Falloff")
if addon.preference().modifier.ghook_falloff:
layout.use_property_split = True
layout.prop(md, "falloff_type")
layout.prop(md, "falloff_radius")
if use_falloff:
if md.falloff_type == 'CURVE':
layout.template_curve_mapping(md, "falloff_curve")
layout.prop(md, "use_falloff_uniform")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "ghook_influence", text="Influence")
if addon.preference().modifier.ghook_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()
def GP_OFFSET(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.column().prop(md, "location")
layout.column().prop(md, "rotation")
layout.column().prop(md, "scale")
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "goffset_influence", text="Influence")
if addon.preference().modifier.goffset_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, True)
layout.separator()
def GP_ARMATURE(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "object")
row = layout.row(align=True)
layout.use_property_split = False
row.prop_search(md, "vertex_group", ob, "vertex_groups")
layout.use_property_split = True
sub = row.row(align=True)
sub.active = bool(md.vertex_group)
sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
col = layout.column(heading='Bind to')
col.prop(md, "use_vertex_groups", text="Vertex Groups")
col.prop(md, "use_bone_envelopes", text="Bone Envelopes")
layout.separator()
def GP_MULTIPLY(self, layout, ob, md):
layout.use_property_split = True
layout.use_property_decorate = True
layout.separator()
layout.prop(md, "duplicates")
subcol = layout.column()
subcol.enabled = md.duplicates > 0
subcol.prop(md, "distance")
subcol.prop(md, "offset", slider=True)
subcol.separator()
layout.use_property_split = False
layout.prop(md, "use_fade")
if md.use_fade:
layout.use_property_split = True
layout.prop(md, "fading_center")
layout.prop(md, "fading_thickness", slider=True)
layout.prop(md, "fading_opacity", slider=True)
layout.use_property_split = False
pref = addon.preference().modifier
layout.prop(pref, "gmulistroke_influence", text="Influence")
if addon.preference().modifier.gmulistroke_influence:
layout.use_property_split = True
self.gpencil_masking(self, layout, ob, md, False)
layout.separator()