Merge branch 'master' of https://gitlab.com/autour-de-minuit/blender/gp_toolbox
commit
e44607bc2c
|
@ -5,6 +5,13 @@
|
||||||
- feat: check file: add check for filepath mapping (if all relative or all absolute)
|
- feat: check file: add check for filepath mapping (if all relative or all absolute)
|
||||||
- change: check file: disable resolution set by default
|
- change: check file: disable resolution set by default
|
||||||
|
|
||||||
|
1.5.4
|
||||||
|
|
||||||
|
- feat: Layer manager
|
||||||
|
- select/set layer prefix
|
||||||
|
- select/set layer color
|
||||||
|
- code: refactor name builder function
|
||||||
|
|
||||||
1.5.3
|
1.5.3
|
||||||
|
|
||||||
- feat: layer aquick-prefix for layer using pref separator
|
- feat: layer aquick-prefix for layer using pref separator
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
import bpy
|
||||||
|
import re
|
||||||
|
from bpy.types import Operator
|
||||||
|
from bpy.props import StringProperty, BoolProperty, EnumProperty
|
||||||
|
|
||||||
|
from .utils import get_addon_prefs
|
||||||
|
|
||||||
|
|
||||||
|
# --- OPS ---
|
||||||
|
|
||||||
|
# pattern = r'([A-Z]{2})?_?([A-Z]{2})?_?(.*)' # bad ! match whithout separator
|
||||||
|
# pattern = r'(?:(^[A-Z]{2})_)?(?:([A-Z]{2})_)?(.*)' # matching only two letter
|
||||||
|
# pattern = r'^([A-Z]{2}_)?([A-Z]{2}_)?(.*)' # matching letters with separator
|
||||||
|
pattern = r'^([A-Z]{1,6}_)?([A-Z]{1,6}_)?(.*)' # matching capital letters from one to six
|
||||||
|
|
||||||
|
def layer_name_build(layer, prefix='', prefix2='', desc=''):
|
||||||
|
'''GET a layer and infos to build name
|
||||||
|
can take one or two prefix and description/name of the layer)
|
||||||
|
'''
|
||||||
|
|
||||||
|
global pattern
|
||||||
|
|
||||||
|
prefs = get_addon_prefs()
|
||||||
|
sep = prefs.separator
|
||||||
|
name = layer.info
|
||||||
|
|
||||||
|
pattern = pattern.replace('_', sep) # set separator
|
||||||
|
|
||||||
|
res = re.search(pattern, name)
|
||||||
|
p1, p2, p3 = res.group(1), res.group(2), res.group(3)
|
||||||
|
|
||||||
|
## empty instead of None
|
||||||
|
p1 = '' if p1 is None else p1
|
||||||
|
p2 = '' if p2 is None else p2
|
||||||
|
p3 = '' if p3 is None else p3
|
||||||
|
|
||||||
|
if prefix:
|
||||||
|
if prefix == 'prefixkillcode':
|
||||||
|
p1 = ''
|
||||||
|
else:
|
||||||
|
p1 = prefix.upper() + sep
|
||||||
|
|
||||||
|
if prefix2:
|
||||||
|
p2 = prefix2.upper() + sep
|
||||||
|
if desc:
|
||||||
|
p3 = desc
|
||||||
|
|
||||||
|
new = f'{p1}{p2}{p3}'
|
||||||
|
|
||||||
|
layer.info = new
|
||||||
|
|
||||||
|
## multi-prefix solution (Caps letters)
|
||||||
|
class GPTB_OT_layer_name_build(Operator):
|
||||||
|
bl_idname = "gp.layer_name_build"
|
||||||
|
bl_label = "Layer Name Build"
|
||||||
|
bl_description = "Change prefix of layer name"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return True
|
||||||
|
|
||||||
|
prefix : StringProperty(default='', options={'SKIP_SAVE'})
|
||||||
|
prefix2 : StringProperty(default='', options={'SKIP_SAVE'})
|
||||||
|
desc : StringProperty(default='', options={'SKIP_SAVE'})
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
ob = context.object
|
||||||
|
gpl = ob.data.layers
|
||||||
|
act = gpl.active
|
||||||
|
if not act:
|
||||||
|
self.report({'ERROR'}, 'no layer active')
|
||||||
|
return {"CANCELLED"}
|
||||||
|
for l in gpl:
|
||||||
|
if not l.select:
|
||||||
|
continue
|
||||||
|
layer_name_build(l, prefix=self.prefix, prefix2=self.prefix2, desc=self.desc)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
#-## SELECTION MANAGEMENT ##-#
|
||||||
|
|
||||||
|
def activate_channel_group_color(context):
|
||||||
|
if not context.preferences.edit.use_anim_channel_group_colors:
|
||||||
|
context.preferences.edit.use_anim_channel_group_colors = True
|
||||||
|
|
||||||
|
def refresh_areas():
|
||||||
|
for area in bpy.context.screen.areas:
|
||||||
|
area.tag_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
class GPTB_OT_select_set_same_prefix(Operator):
|
||||||
|
bl_idname = "gp.select_same_prefix"
|
||||||
|
bl_label = "Select Same Prefix"
|
||||||
|
bl_description = "Select layers that have the same prefix as active\nSet with ctrl+clic"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.object and context.object.type == 'GPENCIL'
|
||||||
|
|
||||||
|
mode : EnumProperty(default='SELECT', options={'SKIP_SAVE'},
|
||||||
|
items=(
|
||||||
|
('SELECT', "Select", "Select layer with same prefix as active"),
|
||||||
|
('SET', "Set", "Set prefix on selected layer to the same as active"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
if event.ctrl:
|
||||||
|
self.mode = 'SET'
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
global pattern
|
||||||
|
prefs = get_addon_prefs()
|
||||||
|
sep = prefs.separator # '_'
|
||||||
|
gpl = context.object.data.layers
|
||||||
|
act = gpl.active
|
||||||
|
|
||||||
|
res = re.search(pattern, act.info)
|
||||||
|
if not res:
|
||||||
|
# self.report({'ERROR'}, f'Error scanning {act.info}')
|
||||||
|
return {"CANCELLED"}
|
||||||
|
namespace = res.group(1)
|
||||||
|
if not namespace:
|
||||||
|
self.report({'WARNING'}, f'No prefix detected in {act.info} with separator {sep}')
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
if self.mode == 'SELECT':
|
||||||
|
## with split
|
||||||
|
# namespace = act.info.split(sep,1)[0]
|
||||||
|
# namespace_bool_list = [l.info.split(sep,1)[0] == namespace for l in gpl]
|
||||||
|
|
||||||
|
## with reg
|
||||||
|
namespace_bool_list = [l.info.split(sep,1)[0] + sep == namespace for l in gpl]
|
||||||
|
gpl.foreach_set('select', namespace_bool_list)
|
||||||
|
|
||||||
|
elif self.mode == 'SET':
|
||||||
|
for l in gpl:
|
||||||
|
if not l.select or l == act:
|
||||||
|
continue
|
||||||
|
layer_name_build(l, prefix=namespace.strip(sep))
|
||||||
|
|
||||||
|
refresh_areas()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class GPTB_OT_select_set_same_color(Operator):
|
||||||
|
bl_idname = "gp.select_same_color"
|
||||||
|
bl_label = "Select Same Color"
|
||||||
|
bl_description = "Select layers that have the same color as active\nSet with ctrl+clic"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.object and context.object.type == 'GPENCIL'
|
||||||
|
|
||||||
|
mode : EnumProperty(default='SELECT', options={'SKIP_SAVE'},
|
||||||
|
items=(
|
||||||
|
('SELECT', "Select", "Select layer with same prefix as active"),
|
||||||
|
('SET', "Set", "Set prefix on selected layer to the same as active"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
if event.ctrl:
|
||||||
|
self.mode = 'SET'
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
gpl = context.object.data.layers
|
||||||
|
act = gpl.active
|
||||||
|
|
||||||
|
if self.mode == 'SELECT':
|
||||||
|
same_color_bool = [l.channel_color == act.channel_color for l in gpl]
|
||||||
|
gpl.foreach_set('select', same_color_bool)
|
||||||
|
|
||||||
|
elif self.mode == 'SET':
|
||||||
|
activate_channel_group_color(context)
|
||||||
|
for l in gpl:
|
||||||
|
if not l.select or l == act:
|
||||||
|
continue
|
||||||
|
l.channel_color = act.channel_color
|
||||||
|
|
||||||
|
refresh_areas()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
def replace_layer_name(target, replacement, selected_only=True, prefix_only=True):
|
||||||
|
prefs = get_addon_prefs()
|
||||||
|
sep = prefs.separator
|
||||||
|
if not target:
|
||||||
|
return
|
||||||
|
scene = bpy.context.scene
|
||||||
|
gpl = bpy.context.object.data.layers
|
||||||
|
|
||||||
|
if scene.gp_rename_selected:
|
||||||
|
lays = [l for l in gpl if l.info != 'background' and l.select]
|
||||||
|
else:
|
||||||
|
lays = [l for l in gpl if l.info != 'background']
|
||||||
|
|
||||||
|
ct = 0
|
||||||
|
for l in lays:
|
||||||
|
if scene.gp_rename_prefix:
|
||||||
|
old = l.info
|
||||||
|
splited = l.info.split(sep)
|
||||||
|
prefix = splited[0]
|
||||||
|
#print(1, splited)
|
||||||
|
new_prefix = prefix.replace(target, replacement)
|
||||||
|
#print(2, splited)
|
||||||
|
if prefix != new_prefix:
|
||||||
|
splited[0] = new_prefix
|
||||||
|
#print(3, splited)
|
||||||
|
l.info = sep.join(splited)
|
||||||
|
print('rename:', old, '-->', l.info)
|
||||||
|
ct+= 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
old = l.info
|
||||||
|
new = l.info.replace(target, replacement)
|
||||||
|
if old != new:
|
||||||
|
print('rename:', old, '-->', l.info)
|
||||||
|
l.info = new
|
||||||
|
ct+= 1
|
||||||
|
return ct
|
||||||
|
|
||||||
|
class GPTB_OT_rename_gp_layer(Operator):
|
||||||
|
'''rename GP layers based on a search and replace'''
|
||||||
|
bl_idname = "gp.rename_gp_layers"
|
||||||
|
bl_label = "Rename Gp Layers"
|
||||||
|
bl_description = "Search/Replace string in all GP layers"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.object and context.object.type == 'GPENCIL'
|
||||||
|
|
||||||
|
find: StringProperty(name="Find", description="Name to replace", default="", maxlen=0, options={'ANIMATABLE'}, subtype='NONE')
|
||||||
|
replace: StringProperty(name="Repl", description="New name placed", default="", maxlen=0, options={'ANIMATABLE'}, subtype='NONE')
|
||||||
|
selected: BoolProperty(name="Selected layer only", description="Affect only selected layers", default=True)
|
||||||
|
prefix: BoolProperty(name="Prefix only", description="Affect only prefix of name (full name if not '_' in it)", default=True)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
count = replace_layer_name(self.find, self.replace, selected_only=self.select, prefix_only=self.prefix)
|
||||||
|
if count:
|
||||||
|
mess = str(count) + ' layers renamed'
|
||||||
|
self.report({'INFO'}, mess)
|
||||||
|
else:
|
||||||
|
self.report({'WARNING'}, 'No text found !')
|
||||||
|
|
||||||
|
return{'FINISHED'}
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
#layout.separator()
|
||||||
|
#layout.label('search/replace GPlayers')
|
||||||
|
layout.prop(self, "selected")
|
||||||
|
layout.prop(self, "prefix")
|
||||||
|
layout.prop(self, "find")#, text = 'find')
|
||||||
|
layout.prop(self, "replace")#, text = 'replace')
|
||||||
|
|
||||||
|
|
||||||
|
## --- UI layer panel---
|
||||||
|
|
||||||
|
def layer_name_builder(self, context):
|
||||||
|
'''appended to DATA_PT_gpencil_layers'''
|
||||||
|
|
||||||
|
prefs = get_addon_prefs()
|
||||||
|
if not prefs.prefixes:
|
||||||
|
return
|
||||||
|
|
||||||
|
layout = self.layout
|
||||||
|
# {'EDIT_GPENCIL', 'PAINT_GPENCIL','SCULPT_GPENCIL','WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}
|
||||||
|
# layout.separator()
|
||||||
|
col = layout.column()
|
||||||
|
|
||||||
|
all_prefixes = prefs.prefixes.split(',')
|
||||||
|
line_limit = 8
|
||||||
|
|
||||||
|
## first prefix
|
||||||
|
for i, prefix in enumerate(all_prefixes):
|
||||||
|
if i % line_limit == 0:
|
||||||
|
row = col.row(align=True)
|
||||||
|
row.operator("gp.layer_name_build", text=prefix.upper() ).prefix = prefix
|
||||||
|
|
||||||
|
row.operator("gp.layer_name_build", text='', icon='X').prefix = 'prefixkillcode'
|
||||||
|
|
||||||
|
## secondary prefix
|
||||||
|
# row = layout.row(align=True)
|
||||||
|
# for task in prefs.prefixes: # 'PO', 'AN'
|
||||||
|
# row.operator("me.set_layer_name", text=task).prefix2 = task
|
||||||
|
|
||||||
|
row = col.row(align=True)
|
||||||
|
row.prop(context.scene.gptoolprops, 'layer_name', text='')
|
||||||
|
row.operator("gp.layer_name_build", text='', icon='EVENT_RETURN').desc = context.scene.gptoolprops.layer_name
|
||||||
|
|
||||||
|
|
||||||
|
## --- UI dopesheet ---
|
||||||
|
|
||||||
|
def gpencil_dopesheet_header(self, context):
|
||||||
|
'''to append in DOPESHEET_HT_header'''
|
||||||
|
layout = self.layout
|
||||||
|
st = context.space_data
|
||||||
|
if st.mode != 'GPENCIL':
|
||||||
|
return
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
# row.operator('gp.active_channel_color_to_selected', text='', icon='RESTRICT_COLOR_ON')
|
||||||
|
row.operator('gp.select_same_prefix', text='', icon='SYNTAX_OFF') # SORTALPHA, SMALL_CAPS
|
||||||
|
row.operator('gp.select_same_color', text='', icon='RESTRICT_COLOR_ON')
|
||||||
|
|
||||||
|
|
||||||
|
classes=(
|
||||||
|
GPTB_OT_rename_gp_layer,
|
||||||
|
GPTB_OT_layer_name_build,
|
||||||
|
GPTB_OT_select_set_same_prefix,
|
||||||
|
GPTB_OT_select_set_same_color,
|
||||||
|
)
|
||||||
|
|
||||||
|
def register():
|
||||||
|
for cls in classes:
|
||||||
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
|
bpy.types.DATA_PT_gpencil_layers.prepend(layer_name_builder)
|
||||||
|
bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header)
|
||||||
|
bpy.types.DATA_PT_gpencil_layers.remove(layer_name_builder)
|
||||||
|
|
||||||
|
for cls in reversed(classes):
|
||||||
|
bpy.utils.unregister_class(cls)
|
|
@ -1,116 +0,0 @@
|
||||||
import bpy
|
|
||||||
import re
|
|
||||||
from bpy.types import Operator
|
|
||||||
from bpy.props import StringProperty, BoolProperty
|
|
||||||
|
|
||||||
|
|
||||||
from .utils import get_addon_prefs
|
|
||||||
|
|
||||||
|
|
||||||
# --- OPS ---
|
|
||||||
|
|
||||||
## multi-prefix solution (Caps letters)
|
|
||||||
class PROJ_OT_layer_name_build(Operator):
|
|
||||||
bl_idname = "gp.layer_name_build"
|
|
||||||
bl_label = "Layer Name Build"
|
|
||||||
bl_description = "Change prefix of layer name"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def poll(cls, context):
|
|
||||||
return True
|
|
||||||
|
|
||||||
prefix : StringProperty(default='', options={'SKIP_SAVE'})
|
|
||||||
prefix2 : StringProperty(default='', options={'SKIP_SAVE'})
|
|
||||||
desc : StringProperty(default='', options={'SKIP_SAVE'})
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
prefs = get_addon_prefs()
|
|
||||||
sep = prefs.separator
|
|
||||||
ob = context.object
|
|
||||||
gpl = ob.data.layers
|
|
||||||
act = gpl.active
|
|
||||||
if not act:
|
|
||||||
self.report({'ERROR'}, 'no layer active')
|
|
||||||
return {"CANCELLED"}
|
|
||||||
|
|
||||||
name = act.info
|
|
||||||
|
|
||||||
# pattern = r'([A-Z]{2})?_?([A-Z]{2})?_?(.*)' # bad ! match whithout separator
|
|
||||||
# pattern = r'(?:(^[A-Z]{2})_)?(?:([A-Z]{2})_)?(.*)' # matching only two letter
|
|
||||||
# pattern = r'^([A-Z]{2}_)?([A-Z]{2}_)?(.*)' # matching letters with separator
|
|
||||||
pattern = r'^([A-Z]{1,6}_)?([A-Z]{1,6}_)?(.*)' # matching capital letters from one to six
|
|
||||||
pattern = pattern.replace('_', sep) # set separator
|
|
||||||
|
|
||||||
res = re.search(pattern, name)
|
|
||||||
p1, p2, p3 = res.group(1), res.group(2), res.group(3)
|
|
||||||
|
|
||||||
## empty instead of None
|
|
||||||
p1 = '' if p1 is None else p1
|
|
||||||
p2 = '' if p2 is None else p2
|
|
||||||
p3 = '' if p3 is None else p3
|
|
||||||
|
|
||||||
if self.prefix:
|
|
||||||
if self.prefix == 'prefixkillcode':
|
|
||||||
p1 = ''
|
|
||||||
else:
|
|
||||||
p1 = self.prefix.upper() + sep
|
|
||||||
|
|
||||||
if self.prefix2:
|
|
||||||
p2 = self.prefix2.upper() + sep
|
|
||||||
if self.desc:
|
|
||||||
p3 = self.desc
|
|
||||||
|
|
||||||
new = f'{p1}{p2}{p3}'
|
|
||||||
|
|
||||||
act.info = new
|
|
||||||
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
## --- UI ---
|
|
||||||
|
|
||||||
def layer_name_builder(self, context):
|
|
||||||
prefs = get_addon_prefs()
|
|
||||||
if not prefs.prefixes:
|
|
||||||
return
|
|
||||||
|
|
||||||
layout = self.layout
|
|
||||||
# {'EDIT_GPENCIL', 'PAINT_GPENCIL','SCULPT_GPENCIL','WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}
|
|
||||||
# layout.separator()
|
|
||||||
col = layout.column()
|
|
||||||
|
|
||||||
all_prefixes = prefs.prefixes.split(',')
|
|
||||||
line_limit = 8
|
|
||||||
|
|
||||||
## first prefix
|
|
||||||
for i, prefix in enumerate(all_prefixes):
|
|
||||||
if i % line_limit == 0:
|
|
||||||
row = col.row(align=True)
|
|
||||||
row.operator("gp.layer_name_build", text=prefix.upper() ).prefix = prefix
|
|
||||||
|
|
||||||
row.operator("gp.layer_name_build", text='', icon='X').prefix = 'prefixkillcode'
|
|
||||||
|
|
||||||
|
|
||||||
## secondary prefix
|
|
||||||
# row = layout.row(align=True)
|
|
||||||
# for task in prefs.prefixes: # 'PO', 'AN'
|
|
||||||
# row.operator("me.set_layer_name", text=task).prefix2 = task
|
|
||||||
|
|
||||||
row = col.row(align=True)
|
|
||||||
row.prop(context.scene.gptoolprops, 'layer_name', text='')
|
|
||||||
row.operator("gp.layer_name_build", text='', icon='EVENT_RETURN').desc = context.scene.gptoolprops.layer_name
|
|
||||||
|
|
||||||
|
|
||||||
classes=(
|
|
||||||
PROJ_OT_layer_name_build,
|
|
||||||
)
|
|
||||||
|
|
||||||
def register():
|
|
||||||
for cls in classes:
|
|
||||||
bpy.utils.register_class(cls)
|
|
||||||
bpy.types.DATA_PT_gpencil_layers.prepend(layer_name_builder)
|
|
||||||
|
|
||||||
def unregister():
|
|
||||||
bpy.types.DATA_PT_gpencil_layers.remove(layer_name_builder)
|
|
||||||
for cls in reversed(classes):
|
|
||||||
bpy.utils.unregister_class(cls)
|
|
|
@ -48,7 +48,7 @@ from . import OP_copy_paste
|
||||||
from . import OP_realign
|
from . import OP_realign
|
||||||
from . import OP_depth_move
|
from . import OP_depth_move
|
||||||
from . import OP_key_duplicate_send
|
from . import OP_key_duplicate_send
|
||||||
from . import OP_layer_name_builder
|
from . import OP_layer_manager
|
||||||
from . import OP_eraser_brush
|
from . import OP_eraser_brush
|
||||||
from . import TOOL_eraser_brush
|
from . import TOOL_eraser_brush
|
||||||
from . import handler_draw_cam
|
from . import handler_draw_cam
|
||||||
|
@ -539,7 +539,7 @@ def register():
|
||||||
OP_realign.register()
|
OP_realign.register()
|
||||||
OP_depth_move.register()
|
OP_depth_move.register()
|
||||||
OP_key_duplicate_send.register()
|
OP_key_duplicate_send.register()
|
||||||
OP_layer_name_builder.register()
|
OP_layer_manager.register()
|
||||||
OP_eraser_brush.register()
|
OP_eraser_brush.register()
|
||||||
TOOL_eraser_brush.register()
|
TOOL_eraser_brush.register()
|
||||||
handler_draw_cam.register()
|
handler_draw_cam.register()
|
||||||
|
@ -568,7 +568,7 @@ def unregister():
|
||||||
handler_draw_cam.unregister()
|
handler_draw_cam.unregister()
|
||||||
OP_eraser_brush.unregister()
|
OP_eraser_brush.unregister()
|
||||||
TOOL_eraser_brush.unregister()
|
TOOL_eraser_brush.unregister()
|
||||||
OP_layer_name_builder.unregister()
|
OP_layer_manager.unregister()
|
||||||
OP_key_duplicate_send.unregister()
|
OP_key_duplicate_send.unregister()
|
||||||
OP_depth_move.unregister()
|
OP_depth_move.unregister()
|
||||||
OP_realign.unregister()
|
OP_realign.unregister()
|
||||||
|
|
Loading…
Reference in New Issue