namespace improvement

1.5.8

- feat: Namespace improvement:
  - new suffixes list that generate suffix buttons
  - dynamic layer name field that show active (msgbus)
  - possible to disable the panel with an option
gpv2
Pullusb 2021-07-20 18:53:39 +02:00
parent 9612c84396
commit 212436c451
5 changed files with 137 additions and 44 deletions

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
1.5.8
- feat: Namespace improvement:
- new suffixes list that generate suffix buttons
- dynamic layer name field that show active (msgbus)
- possible to disable the panel with an option
1.5.7 1.5.7
- feat: check list, specify in addon pref if you prefer a dry run (check without set) - feat: check list, specify in addon pref if you prefer a dry run (check without set)

View File

@ -1,8 +1,9 @@
from os import error
import bpy import bpy
import re import re
from bpy.types import Operator from bpy.types import Operator
from bpy.props import StringProperty, BoolProperty, EnumProperty from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.app.handlers import persistent
from .utils import get_addon_prefs from .utils import get_addon_prefs
@ -11,11 +12,13 @@ from .utils import get_addon_prefs
# pattern = r'([A-Z]{2})?_?([A-Z]{2})?_?(.*)' # bad ! match whithout separator # 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 only two letter
# pattern = r'^([A-Z]{2}_)?([A-Z]{2}_)?(.*)' # matching letters with separator # 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=''): # pattern = r'^([A-Z]{1,6}_)?([A-Z]{1,6}_)?(.*)' # matching capital letters from one to six
pattern = r'^([A-Z]{1,6}_)?([A-Z]{1,6}_)?(.*?)(_[A-Z]{2})?$' # 2 letter suffix
def layer_name_build(layer, prefix='', prefix2='', desc='', suffix=''):
'''GET a layer and infos to build name '''GET a layer and infos to build name
can take one or two prefix and description/name of the layer) Can take one or two prefix and description/name of the layer)
''' '''
global pattern global pattern
@ -26,27 +29,31 @@ def layer_name_build(layer, prefix='', prefix2='', desc=''):
pattern = pattern.replace('_', sep) # set separator pattern = pattern.replace('_', sep) # set separator
res = re.search(pattern, name) res = re.search(pattern, name.strip())
p1, p2, p3 = res.group(1), res.group(2), res.group(3) p1 = '' if res.group(1) is None else res.group(1)
p2 = '' if res.group(2) is None else res.group(2)
## empty instead of None p3 = '' if res.group(3) is None else res.group(3)
p1 = '' if p1 is None else p1 p4 = '' if res.group(4) is None else res.group(4)
p2 = '' if p2 is None else p2
p3 = '' if p3 is None else p3
if prefix: if prefix:
if prefix == 'prefixkillcode': if prefix == 'prefixkillcode':
p1 = '' p1 = ''
else: else:
p1 = prefix.upper() + sep p1 = prefix.upper().strip() + sep
if prefix2: if prefix2:
p2 = prefix2.upper() + sep p2 = prefix2.upper().strip() + sep
if desc: if desc:
p3 = desc p3 = desc
new = f'{p1}{p2}{p3}' if suffix:
if suffix == 'suffixkillcode':
p4 = ''
else:
p4 = sep + suffix.upper().strip()
new = f'{p1}{p2}{p3}{p4}'
layer.info = new layer.info = new
## multi-prefix solution (Caps letters) ## multi-prefix solution (Caps letters)
@ -63,6 +70,7 @@ class GPTB_OT_layer_name_build(Operator):
prefix : StringProperty(default='', options={'SKIP_SAVE'}) prefix : StringProperty(default='', options={'SKIP_SAVE'})
prefix2 : StringProperty(default='', options={'SKIP_SAVE'}) prefix2 : StringProperty(default='', options={'SKIP_SAVE'})
desc : StringProperty(default='', options={'SKIP_SAVE'}) desc : StringProperty(default='', options={'SKIP_SAVE'})
suffix : StringProperty(default='', options={'SKIP_SAVE'})
def execute(self, context): def execute(self, context):
ob = context.object ob = context.object
@ -71,10 +79,10 @@ class GPTB_OT_layer_name_build(Operator):
if not act: if not act:
self.report({'ERROR'}, 'no layer active') self.report({'ERROR'}, 'no layer active')
return {"CANCELLED"} return {"CANCELLED"}
for l in gpl: for l in gpl:
if not l.select: if l.select or l == act:
continue layer_name_build(l, prefix=self.prefix, prefix2=self.prefix2, desc=self.desc, suffix=self.suffix)
layer_name_build(l, prefix=self.prefix, prefix2=self.prefix2, desc=self.desc)
return {"FINISHED"} return {"FINISHED"}
@ -284,7 +292,9 @@ def layer_name_builder(self, context):
'''appended to DATA_PT_gpencil_layers''' '''appended to DATA_PT_gpencil_layers'''
prefs = get_addon_prefs() prefs = get_addon_prefs()
if not prefs.prefixes: if not prefs.show_prefix_buttons:
return
if not prefs.prefixes and not prefs.suffixes:
return return
layout = self.layout layout = self.layout
@ -293,24 +303,31 @@ def layer_name_builder(self, context):
col = layout.column() col = layout.column()
all_prefixes = prefs.prefixes.split(',') all_prefixes = prefs.prefixes.split(',')
all_suffixes = prefs.suffixes.split(',')
line_limit = 8 line_limit = 8
if prefs.prefixes:
## first prefix ## first prefix
for i, prefix in enumerate(all_prefixes): for i, prefix in enumerate(all_prefixes):
if i % line_limit == 0: if i % line_limit == 0:
row = col.row(align=True) row = col.row(align=True)
row.operator("gp.layer_name_build", text=prefix.upper() ).prefix = prefix row.operator("gp.layer_name_build", text=prefix.upper() ).prefix = prefix
row.operator("gp.layer_name_build", text='', icon='X').prefix = 'prefixkillcode' row.operator("gp.layer_name_build", text='', icon='X').prefix = 'prefixkillcode'
## secondary prefix ## secondary prefix ?
# row = layout.row(align=True)
# for task in prefs.prefixes: # 'PO', 'AN'
# row.operator("me.set_layer_name", text=task).prefix2 = task
## name (description)
row = col.row(align=True) row = col.row(align=True)
row.prop(context.scene.gptoolprops, 'layer_name', text='') row.prop(context.scene.gptoolprops, 'layer_name', text='')
row.operator("gp.layer_name_build", text='', icon='EVENT_RETURN').desc = context.scene.gptoolprops.layer_name ## no need for desc ops, already trigerred from update
# row.operator("gp.layer_name_build", text='', icon='EVENT_RETURN').desc = context.scene.gptoolprops.layer_name
if prefs.suffixes:
for i, suffix in enumerate(all_suffixes):
if i % line_limit == 0:
row = col.row(align=True)
row.operator("gp.layer_name_build", text=suffix.upper() ).suffix = suffix
row.operator("gp.layer_name_build", text='', icon='X').suffix = 'suffixkillcode'
## --- UI dopesheet --- ## --- UI dopesheet ---
@ -334,6 +351,39 @@ def gpencil_layer_dropdown_menu(self, context):
'''to append in GPENCIL_MT_layer_context_menu''' '''to append in GPENCIL_MT_layer_context_menu'''
self.layout.operator('gp.rename_gp_layers', icon='BORDERMOVE') self.layout.operator('gp.rename_gp_layers', icon='BORDERMOVE')
## handler and msgbus
def obj_layer_name_callback():
'''assign layer name properties so user an tweak it'''
ob = bpy.context.object
if not ob or ob.type != 'GPENCIL':
return
if not ob.data.layers.active:
return
pattern = r'^([A-Z]{1,6}_)?([A-Z]{1,6}_)?(.*?)(_[A-Z]{2})?$'
res = re.search(pattern, ob.data.layers.active.info)
if not res:
return
if not res.group(3):
return
bpy.context.scene.gptoolprops['layer_name'] = res.group(3)
@persistent
def subscribe_handler(dummy):
subscribe_to = (bpy.types.GreasePencilLayers, "active_index")
bpy.msgbus.subscribe_rna(
key=subscribe_to,
# owner of msgbus subcribe (for clearing later)
# owner=handle,
owner=bpy.types.GreasePencil, # <-- can atach to an ID during all it's lifetime...
# Args passed to callback function (tuple)
args=(),
# Callback function for property update
notify=obj_layer_name_callback,
options={'PERSISTENT'},
)
classes=( classes=(
GPTB_OT_rename_gp_layer, GPTB_OT_rename_gp_layer,
GPTB_OT_layer_name_build, GPTB_OT_layer_name_build,
@ -348,11 +398,16 @@ def register():
bpy.types.DATA_PT_gpencil_layers.prepend(layer_name_builder) bpy.types.DATA_PT_gpencil_layers.prepend(layer_name_builder)
bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header) bpy.types.DOPESHEET_HT_header.append(gpencil_dopesheet_header)
bpy.types.GPENCIL_MT_layer_context_menu.append(gpencil_layer_dropdown_menu) bpy.types.GPENCIL_MT_layer_context_menu.append(gpencil_layer_dropdown_menu)
bpy.app.handlers.load_post.append(subscribe_handler) # need to restart after first activation
def unregister(): def unregister():
bpy.app.handlers.load_post.remove(subscribe_handler)
bpy.types.GPENCIL_MT_layer_context_menu.remove(gpencil_layer_dropdown_menu) bpy.types.GPENCIL_MT_layer_context_menu.remove(gpencil_layer_dropdown_menu)
bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header) bpy.types.DOPESHEET_HT_header.remove(gpencil_dopesheet_header)
bpy.types.DATA_PT_gpencil_layers.remove(layer_name_builder) bpy.types.DATA_PT_gpencil_layers.remove(layer_name_builder)
for cls in reversed(classes): for cls in reversed(classes):
bpy.utils.unregister_class(cls) bpy.utils.unregister_class(cls)
# delete layer index trigger
bpy.msgbus.clear_by_owner(bpy.types.GreasePencil)

View File

@ -33,7 +33,7 @@ Note about palette : For now the importer is not working with linked palette as
> Mainly for devellopers to set project environnement > Mainly for devellopers to set project environnement
Since 1.5.2, following _environnement variable_ can set the project properties in toolbox preferences at register launch. Since 1.5.2, following _environnement variable_ can set the project properties in toolbox preferences at register launch:
`RENDER_WIDTH` : resolution x `RENDER_WIDTH` : resolution x
`RENDER_HEIGHT` : resolution y `RENDER_HEIGHT` : resolution y
@ -41,6 +41,7 @@ Since 1.5.2, following _environnement variable_ can set the project properties i
`PALETTES` : path to the blends (or json) containing materials palettes `PALETTES` : path to the blends (or json) containing materials palettes
`BRUSHES` : path to the blend containing brushes to load `BRUSHES` : path to the blend containing brushes to load
`PREFIXES` : list of prefix (comma separated uppercase letters between 1 and 6 character, ex: 'AN,SP,L') `PREFIXES` : list of prefix (comma separated uppercase letters between 1 and 6 character, ex: 'AN,SP,L')
`SUFFIXES` : list of suffixes (comma separated uppercase letters between 1 and 6 character, ex: 'OL,UL')
`SEPARATOR` : Separator character to determine prefixes, default is '_' (should not be a special regex character) `SEPARATOR` : Separator character to determine prefixes, default is '_' (should not be a special regex character)
### Passive action ### Passive action

View File

@ -234,6 +234,17 @@ class GPTB_prefs(bpy.types.AddonPreferences):
description="List of prefixes (two capital letters) available for layers(ex: AN,CO,CL)", description="List of prefixes (two capital letters) available for layers(ex: AN,CO,CL)",
default="", maxlen=0) default="", maxlen=0)
suffixes : StringProperty(
name="Layers Suffixes",
description="List of suffixes (two capital letters) available for layers(ex: OL,UL)",
default="", maxlen=0)
show_prefix_buttons : BoolProperty(
name="Show Prefix Buttons",
description="Show prefix and suffix buttons above layer stack",
default=False,
)
## Playblast prefs ## Playblast prefs
playblast_auto_play : BoolProperty( playblast_auto_play : BoolProperty(
name="Playblast auto play", name="Playblast auto play",
@ -364,7 +375,10 @@ class GPTB_prefs(bpy.types.AddonPreferences):
subbox = box.box() subbox = box.box()
subbox.label(text='Namespace:') subbox.label(text='Namespace:')
subbox.prop(self, 'separator') subbox.prop(self, 'separator')
subbox.prop(self, 'show_prefix_buttons', text='Use Prefixes Toggles')
if self.show_prefix_buttons:
subbox.prop(self, 'prefixes') subbox.prop(self, 'prefixes')
subbox.prop(self, 'suffixes')
### TODO add render settings ### TODO add render settings
@ -505,6 +519,9 @@ def set_env_properties():
prefix_list = os.getenv('PREFIXES') prefix_list = os.getenv('PREFIXES')
prefs.prefixes = prefix_list if prefix_list else prefs.prefixes prefs.prefixes = prefix_list if prefix_list else prefs.prefixes
suffix_list = os.getenv('SUFFIXES')
prefs.suffixes = suffix_list if suffix_list else prefs.suffixes
separator = os.getenv('SEPARATOR') separator = os.getenv('SEPARATOR')
prefs.separator = separator if separator else prefs.separator prefs.separator = separator if separator else prefs.separator

View File

@ -8,7 +8,7 @@ from bpy.props import (
) )
from .OP_cursor_snap_canvas import cursor_follow_update from .OP_cursor_snap_canvas import cursor_follow_update
from .OP_layer_manager import layer_name_build
def change_edit_lines_opacity(self, context): def change_edit_lines_opacity(self, context):
for gp in bpy.data.grease_pencils: for gp in bpy.data.grease_pencils:
@ -16,6 +16,18 @@ def change_edit_lines_opacity(self, context):
gp.edit_line_color[3]=self.edit_lines_opacity gp.edit_line_color[3]=self.edit_lines_opacity
def update_layer_name(self, context):
if not self.layer_name:
# never replace by nothing (since there should be prefix/suffix)
return
if not context.object or context.object.type != 'GPENCIL':
return
if not context.object.data.layers.active:
return
layer_name_build(context.object.data.layers.active, desc=self.layer_name)
# context.object.data.layers.active.info = self.layer_name
class GP_PG_FixSettings(bpy.types.PropertyGroup): class GP_PG_FixSettings(bpy.types.PropertyGroup):
check_only : BoolProperty( check_only : BoolProperty(
@ -168,7 +180,8 @@ class GP_PG_ToolsSettings(bpy.types.PropertyGroup):
layer_name : StringProperty( layer_name : StringProperty(
name="Layer Name", name="Layer Name",
description="The layer name, should describe the content of the layer", description="The layer name, should describe the content of the layer",
default="")# update=None, get=None, set=None default="",
update=update_layer_name)# update=None, get=None, set=None
""" """
reconnect_parent = bpy.props.PointerProperty(type =bpy.types.Object,poll=poll_armature) reconnect_parent = bpy.props.PointerProperty(type =bpy.types.Object,poll=poll_armature)
render_settings = bpy.props.BoolProperty(default = False) render_settings = bpy.props.BoolProperty(default = False)