gpv3 port: create empty frames - add support for group as source
add utility function to check hide-lock state of nested itemsmaster
parent
b525cda28e
commit
49c70860a6
|
@ -11,18 +11,35 @@ def get_layer_list(self, context):
|
||||||
'''return (identifier, name, description) of enum content'''
|
'''return (identifier, name, description) of enum content'''
|
||||||
return [(l.name, l.name, '') for l in context.object.data.layers if l != context.object.data.layers.active]
|
return [(l.name, l.name, '') for l in context.object.data.layers if l != context.object.data.layers.active]
|
||||||
|
|
||||||
|
def get_group_list(self, context):
|
||||||
|
return [(g.name, g.name, '') for g in context.object.data.layer_groups]
|
||||||
|
|
||||||
|
def get_top_layer_from_group(gp, group):
|
||||||
|
upper_layer = None
|
||||||
|
for layer in gp.layers:
|
||||||
|
if layer.parent_group == group:
|
||||||
|
upper_layer = layer
|
||||||
|
return upper_layer
|
||||||
|
|
||||||
class GP_OT_create_empty_frames(bpy.types.Operator):
|
class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
bl_idname = "gp.create_empty_frames"
|
bl_idname = "gp.create_empty_frames"
|
||||||
bl_label = "Create Empty Frames"
|
bl_label = "Create Empty Frames"
|
||||||
bl_description = "Create new empty frames on active layer where there is a frame in layer above\n(usefull in color layers to match line frames)"
|
bl_description = "Create new empty frames on active layer where there is a frame in targeted layers\
|
||||||
|
\n(usefull in color layers to match line frames)"
|
||||||
bl_options = {'REGISTER','UNDO'}
|
bl_options = {'REGISTER','UNDO'}
|
||||||
|
|
||||||
layers_enum : EnumProperty(
|
layers_enum : EnumProperty(
|
||||||
name="Duplicate to layers",
|
name="Empty Keys from Layer",
|
||||||
description="Duplicate selected keys in active layer and send them to choosen layer",
|
description="Reference keys from layer",
|
||||||
items=get_layer_list
|
items=get_layer_list
|
||||||
)
|
)
|
||||||
|
|
||||||
|
groups_enum : EnumProperty(
|
||||||
|
name="Empty Keys from Group",
|
||||||
|
description="Duplicate keys from group",
|
||||||
|
items=get_group_list
|
||||||
|
)
|
||||||
|
|
||||||
targeted_layers : EnumProperty(
|
targeted_layers : EnumProperty(
|
||||||
name="Sources", # Empty keys from targets
|
name="Sources", # Empty keys from targets
|
||||||
description="Duplicate keys as empty on current layer from selected targets",
|
description="Duplicate keys as empty on current layer from selected targets",
|
||||||
|
@ -34,7 +51,8 @@ class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
('ABOVE', 'Layer Directly Above', 'Empty frames from layer directly above'),
|
('ABOVE', 'Layer Directly Above', 'Empty frames from layer directly above'),
|
||||||
('BELOW', 'Layer Directly Below', 'Empty frames from layer directly below'),
|
('BELOW', 'Layer Directly Below', 'Empty frames from layer directly below'),
|
||||||
('ALL_VISIBLE', 'Visible', 'Empty frames from all visible layers'),
|
('ALL_VISIBLE', 'Visible', 'Empty frames from all visible layers'),
|
||||||
('CHOSEN', 'Chosen layer', ''),
|
('CHOSEN', 'Chosen layer', 'Empty frames from a specific layer'),
|
||||||
|
('CHOSEN_GROUP', 'Chosen group', 'Empty frames from a specific layer group'),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,6 +81,13 @@ class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
# Possible preset with shortcut
|
# Possible preset with shortcut
|
||||||
# if event.alt:
|
# if event.alt:
|
||||||
# self.targeted_layers = 'ALL_VISIBLE'
|
# self.targeted_layers = 'ALL_VISIBLE'
|
||||||
|
gp = context.grease_pencil
|
||||||
|
layer_from_group = None
|
||||||
|
if gp.layer_groups.active:
|
||||||
|
layer_from_group = get_top_layer_from_group(gp, gp.layer_groups.active)
|
||||||
|
if not gp.layers.active and not layer_from_group:
|
||||||
|
self.report({'ERROR'}, 'No active layer or active group containing layer on GP object')
|
||||||
|
return {'CANCELLED'}
|
||||||
return context.window_manager.invoke_props_dialog(self)
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
|
@ -74,7 +99,13 @@ class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
if self.layers_enum:
|
if self.layers_enum:
|
||||||
layout.prop(self, 'layers_enum')
|
layout.prop(self, 'layers_enum')
|
||||||
else:
|
else:
|
||||||
layout.label(text='No other layers to match keyframe')
|
layout.label(text='No other layers to match keyframe!', icon='ERROR')
|
||||||
|
|
||||||
|
if self.targeted_layers == 'CHOSEN_GROUP':
|
||||||
|
if self.groups_enum:
|
||||||
|
layout.prop(self, 'groups_enum')
|
||||||
|
else:
|
||||||
|
layout.label(text='No other groups to match keyframe!', icon='ERROR')
|
||||||
|
|
||||||
elif self.targeted_layers == 'NUMBER':
|
elif self.targeted_layers == 'NUMBER':
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
@ -91,20 +122,28 @@ class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = context.object
|
obj = context.object
|
||||||
gpl = obj.data.layers
|
gp = obj.data
|
||||||
|
gpl = gp.layers
|
||||||
|
|
||||||
|
if gp.layer_groups.active:
|
||||||
|
reference_layer = get_top_layer_from_group(gp, gp.layer_groups.active)
|
||||||
|
else:
|
||||||
|
reference_layer = gpl.active
|
||||||
|
|
||||||
|
active_index = next((i for i, l in enumerate(gpl) if l == reference_layer), None)
|
||||||
|
|
||||||
print(self.targeted_layers)
|
print(self.targeted_layers)
|
||||||
if self.targeted_layers == 'ALL_ABOVE':
|
if self.targeted_layers == 'ALL_ABOVE':
|
||||||
tgt_layers = [l for i, l in enumerate(gpl) if i > gpl.active_index]
|
tgt_layers = [l for i, l in enumerate(gpl) if i > active_index]
|
||||||
|
|
||||||
elif self.targeted_layers == 'ALL_BELOW':
|
elif self.targeted_layers == 'ALL_BELOW':
|
||||||
tgt_layers = [l for i, l in enumerate(gpl) if i < gpl.active_index]
|
tgt_layers = [l for i, l in enumerate(gpl) if i < active_index]
|
||||||
|
|
||||||
elif self.targeted_layers == 'ABOVE':
|
elif self.targeted_layers == 'ABOVE':
|
||||||
tgt_layers = [l for i, l in enumerate(gpl) if i == gpl.active_index + 1]
|
tgt_layers = [l for i, l in enumerate(gpl) if i == active_index + 1]
|
||||||
|
|
||||||
elif self.targeted_layers == 'BELOW':
|
elif self.targeted_layers == 'BELOW':
|
||||||
tgt_layers = [l for i, l in enumerate(gpl) if i == gpl.active_index - 1]
|
tgt_layers = [l for i, l in enumerate(gpl) if i == active_index - 1]
|
||||||
|
|
||||||
elif self.targeted_layers == 'ALL_VISIBLE':
|
elif self.targeted_layers == 'ALL_VISIBLE':
|
||||||
tgt_layers = [l for l in gpl if not l.hide and l != gpl.active]
|
tgt_layers = [l for l in gpl if not l.hide and l != gpl.active]
|
||||||
|
@ -115,17 +154,24 @@ class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
tgt_layers = [l for l in gpl if l.name == self.layers_enum]
|
tgt_layers = [l for l in gpl if l.name == self.layers_enum]
|
||||||
|
|
||||||
|
elif self.targeted_layers == 'CHOSEN_GROUP':
|
||||||
|
if not self.groups_enum:
|
||||||
|
self.report({'ERROR'}, f"No chosen groups, aborted")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
group = gp.layer_groups.get(self.groups_enum)
|
||||||
|
tgt_layers = [l for l in gpl if l.parent_group == group]
|
||||||
|
|
||||||
elif self.targeted_layers == 'NUMBER':
|
elif self.targeted_layers == 'NUMBER':
|
||||||
if self.number == 0:
|
if self.number == 0:
|
||||||
self.report({'ERROR'}, f"Can't have 0 as value")
|
self.report({'ERROR'}, f"Can't have 0 as value")
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
l_range = gpl.active_index + self.number
|
l_range = active_index + self.number
|
||||||
print('l_range: ', l_range)
|
print('l_range: ', l_range)
|
||||||
if self.number > 0: # positive
|
if self.number > 0: # positive
|
||||||
tgt_layers = [l for i, l in enumerate(gpl) if gpl.active_index < i <= l_range]
|
tgt_layers = [l for i, l in enumerate(gpl) if active_index < i <= l_range]
|
||||||
else:
|
else:
|
||||||
tgt_layers = [l for i, l in enumerate(gpl) if gpl.active_index > i >= l_range]
|
tgt_layers = [l for i, l in enumerate(gpl) if active_index > i >= l_range]
|
||||||
|
|
||||||
if not tgt_layers:
|
if not tgt_layers:
|
||||||
self.report({'ERROR'}, f"No layers found with chosen Targets")
|
self.report({'ERROR'}, f"No layers found with chosen Targets")
|
||||||
|
@ -163,7 +209,7 @@ class GP_OT_create_empty_frames(bpy.types.Operator):
|
||||||
if num in current_frames:
|
if num in current_frames:
|
||||||
continue
|
continue
|
||||||
#Create empty frame
|
#Create empty frame
|
||||||
gpl.active.frames.new(num, active=False)
|
gpl.active.frames.new(num)
|
||||||
fct += 1
|
fct += 1
|
||||||
|
|
||||||
gpl.update()
|
gpl.update()
|
||||||
|
|
38
utils.py
38
utils.py
|
@ -155,6 +155,44 @@ def gp_stroke_to_bmesh(strokes):
|
||||||
### GP Drawing
|
### GP Drawing
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
|
def layer_active_index(gpl):
|
||||||
|
'''Get layer list and return index of active layer
|
||||||
|
Can return None if no active layer found (active item can be a group)
|
||||||
|
'''
|
||||||
|
return next((i for i, l in enumerate(gpl) if l == gpl.active), None)
|
||||||
|
|
||||||
|
## Check for nested lock
|
||||||
|
def is_locked(stack_item):
|
||||||
|
'''Check if passed stack item (layer or group) is locked
|
||||||
|
either itself or by parent groups'''
|
||||||
|
if stack_item.lock:
|
||||||
|
return True
|
||||||
|
if stack_item.parent_group:
|
||||||
|
return is_locked(stack_item.parent_group)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_parent_locked(stack_item):
|
||||||
|
'''Check if passed stack item (layer or group) is locked by parent groups'''
|
||||||
|
if stack_item.parent_group:
|
||||||
|
return is_locked(stack_item.parent_group)
|
||||||
|
return False
|
||||||
|
|
||||||
|
## Check for nested hide
|
||||||
|
def is_hidden(stack_item):
|
||||||
|
'''Check if passed stack item (layer or group) is hidden
|
||||||
|
either itself or by parent groups'''
|
||||||
|
if stack_item.hide:
|
||||||
|
return True
|
||||||
|
if stack_item.parent_group:
|
||||||
|
return is_hidden(stack_item.parent_group)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_parent_hidden(stack_item):
|
||||||
|
'''Check if passed stack item (layer or group) is hidden by parent groups'''
|
||||||
|
if stack_item.parent_group:
|
||||||
|
return is_hidden(stack_item.parent_group)
|
||||||
|
return False
|
||||||
|
|
||||||
def simple_draw_gp_stroke(pts, frame, width = 2, mat_id = 0):
|
def simple_draw_gp_stroke(pts, frame, width = 2, mat_id = 0):
|
||||||
'''
|
'''
|
||||||
draw basic stroke by passing list of point 3D coordinate
|
draw basic stroke by passing list of point 3D coordinate
|
||||||
|
|
Loading…
Reference in New Issue