Skip to content

Commit ffd4b6c

Browse files
committed
Add YDuplicateLayerMask
1 parent 196505c commit ffd4b6c

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

Mask.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,93 @@ def execute(self, context):
16761676

16771677
return {'FINISHED'}
16781678

1679+
# Copy each modifier from the source - copies references and links modifiers - not working
1680+
def copy_mask_modifiers(layer, source_mask, target_mask):
1681+
for mod in source_mask.modifiers:
1682+
new_mod = target_mask.modifiers.add()
1683+
for attr in dir(mod):
1684+
if attr.startswith("_") or callable(getattr(mod, attr)):
1685+
continue
1686+
try:
1687+
setattr(new_mod, attr, getattr(mod, attr))
1688+
except Exception:
1689+
pass
1690+
1691+
class YDuplicateLayerMask(bpy.types.Operator):
1692+
bl_idname = "wm.y_duplicate_layer_mask"
1693+
bl_label = "Duplicate Layer Mask"
1694+
bl_description = "Duplicate the selected layer mask"
1695+
bl_options = {'REGISTER', 'UNDO'}
1696+
1697+
@classmethod
1698+
def poll(cls, context):
1699+
return hasattr(context, 'mask') and hasattr(context, 'layer')
1700+
1701+
def execute(self, context):
1702+
layer = context.layer
1703+
mask = context.mask
1704+
obj = context.object
1705+
1706+
tree = get_tree(layer)
1707+
source_node = tree.nodes.get(mask.source) if hasattr(mask, 'source') else None
1708+
image = source_node.image if source_node and hasattr(source_node, 'image') else None
1709+
1710+
new_name = mask.name + "_Copy"
1711+
1712+
try:
1713+
new_mask = add_new_mask(
1714+
layer=layer,
1715+
name=new_name,
1716+
mask_type=mask.type,
1717+
texcoord_type=mask.texcoord_type,
1718+
uv_name=mask.uv_name,
1719+
image=image,
1720+
vcol=getattr(mask, 'vcol_name', None),
1721+
segment=getattr(mask, 'segment_name', None),
1722+
object_index=mask.object_index,
1723+
blend_type=mask.blend_type,
1724+
hemi_space=mask.hemi_space,
1725+
hemi_use_prev_normal=mask.hemi_use_prev_normal,
1726+
color_id=mask.color_id,
1727+
source_input=mask.source_input,
1728+
edge_detect_radius=mask.edge_detect_radius,
1729+
modifier_type=getattr(mask, 'modifier_type', 'INVERT'),
1730+
interpolation=getattr(source_node, 'interpolation', 'Linear') if source_node else 'Linear',
1731+
ao_distance=mask.ao_distance
1732+
)
1733+
1734+
# Copy extra float/vector properties
1735+
new_mask.intensity_value = mask.intensity_value
1736+
1737+
# Transform
1738+
new_mask.translation = mask.translation[:]
1739+
new_mask.rotation = mask.rotation[:]
1740+
new_mask.scale = mask.scale[:]
1741+
1742+
#update?
1743+
update_mask_transform(new_mask, context)
1744+
1745+
# Blur vector settings
1746+
new_mask.enable_blur_vector = mask.enable_blur_vector
1747+
new_mask.blur_vector_factor = mask.blur_vector_factor
1748+
1749+
# Decal projection distance
1750+
new_mask.decal_distance_value = mask.decal_distance_value
1751+
1752+
# Copy channel enable states
1753+
for i, ch in enumerate(mask.channels):
1754+
if i < len(new_mask.channels):
1755+
new_mask.channels[i].enable = ch.enable
1756+
1757+
#copy_mask_modifiers(layer, mask, new_mask)
1758+
1759+
#self.report({'INFO'}, f"ucupaint addon: Duplicated mask '{mask.name}' as '{new_mask.name}'")
1760+
return {'FINISHED'}
1761+
1762+
except Exception as e:
1763+
self.report({'ERROR'}, f"ucupaint addon: Failed to duplicate mask: {e}")
1764+
return {'CANCELLED'}
1765+
16791766
class YRemoveLayerMask(bpy.types.Operator):
16801767
bl_idname = "wm.y_remove_layer_mask"
16811768
bl_label = "Remove Layer Mask"
@@ -2648,6 +2735,7 @@ def register():
26482735
bpy.utils.register_class(YOpenImageAsMask)
26492736
bpy.utils.register_class(YOpenAvailableDataAsMask)
26502737
bpy.utils.register_class(YMoveLayerMask)
2738+
bpy.utils.register_class(YDuplicateLayerMask)
26512739
bpy.utils.register_class(YRemoveLayerMask)
26522740
bpy.utils.register_class(YReplaceMaskType)
26532741
bpy.utils.register_class(YFixEdgeDetectAO)
@@ -2659,6 +2747,7 @@ def unregister():
26592747
bpy.utils.unregister_class(YOpenImageAsMask)
26602748
bpy.utils.unregister_class(YOpenAvailableDataAsMask)
26612749
bpy.utils.unregister_class(YMoveLayerMask)
2750+
bpy.utils.unregister_class(YDuplicateLayerMask)
26622751
bpy.utils.unregister_class(YRemoveLayerMask)
26632752
bpy.utils.unregister_class(YReplaceMaskType)
26642753
bpy.utils.unregister_class(YFixEdgeDetectAO)

ui.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6523,6 +6523,8 @@ def draw(self, context):
65236523
col.operator('wm.y_invert_image', text='Invert Image', icon='IMAGE_ALPHA')
65246524

65256525
col.separator()
6526+
col.operator('wm.y_duplicate_layer_mask', icon='DUPLICATE', text='Duplicate Mask')
6527+
col.separator()
65266528

65276529
op = col.operator('wm.y_move_layer_mask', icon='TRIA_UP', text='Move Mask Up')
65286530
op.direction = 'UP'

0 commit comments

Comments
 (0)