From 02d13c6f29b830591a464e89e720133ce07d0598 Mon Sep 17 00:00:00 2001 From: Pullusb Date: Sat, 8 Oct 2022 01:15:34 +0200 Subject: [PATCH] New project and user prefix management 2.0.6 - changed: Use prefixes toggle is enabled by default - changed: prefixes are now set in preferences as a reorderable UI list with full name for description - This should not affect `PREFIXES` env variable (`'CO, LN'`) - Now can be also passed as prefix:name pair ex: `'CO : Color, LN : Line` --- CHANGELOG.md | 7 +++ OP_layer_manager.py | 49 ++++++++++++---- __init__.py | 139 ++++++++++++++++++++++++++++++++------------ properties.py | 6 +- 4 files changed, 151 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70e4d9c..3587681 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +2.0.6 + +- changed: Use prefixes toggle is enabled by default +- changed: prefixes are now set in preferences as a reorderable UI list with full name for description + - This should not affect `PREFIXES` env variable (`'CO, LN'`) + - Now can be also passed as prefix:name pair ex: `'CO : Color, LN : Line` + 2.0.5 - changed: redo panel for GP layer picker has better name and display active layer name diff --git a/OP_layer_manager.py b/OP_layer_manager.py index cd96dca..67ebb3b 100644 --- a/OP_layer_manager.py +++ b/OP_layer_manager.py @@ -135,12 +135,20 @@ class GPTB_OT_layer_name_build(Operator): @classmethod def poll(cls, context): return True - + prefix : StringProperty(default='', options={'SKIP_SAVE'}) # prefix2 : StringProperty(default='', options={'SKIP_SAVE'}) + prefix_tooltip : StringProperty(default='', options={'SKIP_SAVE'}) desc : StringProperty(default='', options={'SKIP_SAVE'}) suffix : StringProperty(default='', options={'SKIP_SAVE'}) + @classmethod + def description(cls, context, properties): + if properties.prefix_tooltip: + return f"Use prefix: {properties.prefix} ({properties.prefix_tooltip})" + else: + return f"Use prefix: {properties.prefix}" + def execute(self, context): ob = context.object gpl = ob.data.layers @@ -544,7 +552,7 @@ def layer_name_builder_ui(self, context): prefs = get_addon_prefs() if not prefs.show_prefix_buttons: return - if not prefs.prefixes and not prefs.suffixes: + if not len(prefs.prefixes.namespaces) and not prefs.suffixes: return layout = self.layout @@ -552,37 +560,56 @@ def layer_name_builder_ui(self, context): # layout.separator() col = layout.column() - all_prefixes = prefs.prefixes.split(',') - all_suffixes = prefs.suffixes.split(',') - line_limit = 8 + line_limit = 8 + + if len(prefs.prefixes.namespaces): + ct = 0 + # can't use enumerate cause there can be hided prefix + for namespace in prefs.prefixes.namespaces: + if namespace.hide: + continue + if ct % line_limit == 0: + row = col.row(align=True) + ct += 1 + op = row.operator("gp.layer_name_build", text=namespace.prefix) + op.prefix = namespace.prefix + op.prefix_tooltip = namespace.name + + if ct > 0: + row.operator("gp.layer_name_build", text='', icon='X').prefix = 'prefixkillcode' + + ## old single string prefix method + """ if prefs.prefixes: - ## first prefix + p = prefs.prefixes.split(',') 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 ? ## name (description) row = col.row(align=True) row.prop(context.scene.gptoolprops, 'layer_name', text='') - row.operator("gp.layer_new_group", text='', icon='COLLECTION_NEW') - row.operator("gp.layer_group_toggle", text='', icon='OUTLINER_OB_GROUP_INSTANCE') + + ## mimic groups using dash (disabled for now) + # row.operator("gp.layer_new_group", text='', icon='COLLECTION_NEW') + # row.operator("gp.layer_group_toggle", text='', icon='OUTLINER_OB_GROUP_INSTANCE') + ## 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: + all_suffixes = prefs.suffixes.split(',') 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 --- diff --git a/__init__.py b/__init__.py index 0cc898c..8b65479 100755 --- a/__init__.py +++ b/__init__.py @@ -4,7 +4,7 @@ bl_info = { "name": "GP toolbox", "description": "Tool set for Grease Pencil in animation production", "author": "Samuel Bernou, Christophe Seux", -"version": (2, 0, 5), +"version": (2, 0, 6), "blender": (2, 91, 0), "location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", "warning": "", @@ -110,34 +110,36 @@ def remap_on_save_update(self, context): # kmi.active = self.use_precise_eraser - -class GPTB_OT_add_namespace_prefix(bpy.types.Operator): - bl_idname = "gptb.add_namespace_prefix" - bl_label = "Add" +class GPTB_OT_add_namespace_entry(bpy.types.Operator): + bl_idname = "gptb.add_namespace_entry" + bl_label = "Add Namespace Entry" bl_description = "Add item in list" bl_options = {'REGISTER', 'INTERNAL'} idx : bpy.props.IntProperty() new : bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'}) + propname : bpy.props.StringProperty(default='prefixes', options={'SKIP_SAVE'}) def invoke(self, context, event): - self.pg = get_addon_prefs().user_prefixes + self.pg = getattr(get_addon_prefs(), self.propname) + self.proptype = self.propname[:-2] + ## Basic: # self.pg.namespaces.add() # return {'FINISHED'}# can just add empty entry and leave... if self.new: self.pg.namespaces.add() self.idx = len(self.pg.namespaces) - 1 - return context.window_manager.invoke_props_dialog(self, width=650) + return context.window_manager.invoke_props_dialog(self, width=450) def draw(self, context): import re layout = self.layout # layout.use_property_split = True item = self.pg.namespaces[self.idx] - layout.label(text='Enter prefix:', icon='INFO') - layout.prop(item, 'prefix') + layout.label(text=f'Enter {self.proptype}:', icon='INFO') + layout.prop(item, 'prefix') # maybe use a name that fit prefix and suffix if item.prefix and not re.match(r'^[A-Z]{2}$', item.prefix): - layout.label(text='Prefix are preferably two capital letter (ex: CO)', icon='ERROR') + layout.label(text=f'{self.propname} are preferably two capital letter (ex: CO)', icon='ERROR') layout.separator() layout.label(text='Provide a name (Optional):', icon='INFO') @@ -152,10 +154,34 @@ class GPTB_OT_add_namespace_prefix(bpy.types.Operator): if self.new: # in case of new addition, remove just added if nothing specified if not item.prefix and not item.name: - self.pg.dirs.remove(self.idx) + self.pg.namespaces.remove(self.idx) context.area.tag_redraw() return {'FINISHED'} + +class GPTB_OT_remove_namespace_entry(bpy.types.Operator): + bl_idname = "gptb.remove_namespace_entry" + bl_label = "Remove Namespace Entry" + bl_description = "Remove item in list" + bl_options = {'REGISTER', 'INTERNAL'} + + propname : bpy.props.StringProperty(default='prefixes', options={'SKIP_SAVE'}) + + def execute(self, context): + self.pg = getattr(get_addon_prefs(), self.propname) + if not len(self.pg.namespaces): + return {'CANCELLED'} + item = self.pg.namespaces[self.pg.idx] + if item.is_project: + self.report({"ERROR"}, 'Cannot remove a prefix that is defined by project, hide it instead') + return {'CANCELLED'} + + self.pg.namespaces.remove(self.pg.idx) + context.area.tag_redraw() + return {'FINISHED'} + + + class GPTB_OT_move_item(bpy.types.Operator): bl_idname = "gptb.move_item" bl_label = "Move Item" @@ -174,7 +200,7 @@ class GPTB_OT_move_item(bpy.types.Operator): # prop_name : bpy.props.StringProperty() def execute(self, context): - pg = get_addon_prefs().user_prefixes + pg = get_addon_prefs().prefixes # uilist = getattr(pg, self.prop_name) uilist = pg.namespaces index = pg.idx @@ -188,6 +214,7 @@ class GPTB_OT_move_item(bpy.types.Operator): # index = list_index # setattr(pg, self.prop_name + '_idx', list_index) setattr(pg, 'idx', list_index) + context.area.tag_redraw() return {'FINISHED'} class GPTB_UL_namespace_list(bpy.types.UIList): @@ -200,10 +227,15 @@ class GPTB_UL_namespace_list(bpy.types.UIList): # prefs = get_addon_prefs() # split = layout.split(align=False, factor=0.3) row = layout.row() - ico = 'HIDE_ON' if item.hide else 'HIDE_OFF' - row.prop(item, 'hide', text='', icon=ico, invert_checkbox=True) - row.prop(item, 'prefix', text='') - row.prop(item, 'name', text='') + hide_ico = 'HIDE_ON' if item.hide else 'HIDE_OFF' + source_ico = 'NETWORK_DRIVE' if item.is_project else 'USER' # BLANK1 + + row.label(text='', icon=source_ico) + row.prop(item, 'hide', text='', icon=hide_ico, invert_checkbox=True) + subrow = row.row(align=True) + subrow.prop(item, 'prefix', text='') + subrow.prop(item, 'name', text='') + subrow.enabled = not item.is_project # row = layout.split(align=False) # row.label(text=item.prefix) @@ -320,12 +352,13 @@ class GPTB_prefs(bpy.types.AddonPreferences): description="Character delimiter to use for detecting namespace (prefix), default is '_', space if nothing specified", default="_", maxlen=0, subtype='NONE') - prefixes : StringProperty( - name="Layers Prefixes", - description="List of prefixes (two capital letters) available for layers(ex: AN,CO,CL)", - default="", maxlen=0) + ## Old one string comma separated prefix list + # prefixes : StringProperty( + # name="Layers Prefixes", + # description="List of prefixes (two capital letters) available for layers(ex: AN,CO,CL)", + # default="", maxlen=0) - # user_prefixes : PointerProperty(type=GP_PG_namespaces) + prefixes : PointerProperty(type=GP_PG_namespaces) ### proj_prefixes : PointerProperty(type=GP_PG_namespaces) # Store in the same list ? suffixes : StringProperty( @@ -342,7 +375,7 @@ class GPTB_prefs(bpy.types.AddonPreferences): show_prefix_buttons : BoolProperty( name="Show Prefix Buttons", description="Show prefix and suffix buttons above layer stack", - default=False, + default=True, ) ## Playblast prefs @@ -514,20 +547,19 @@ class GPTB_prefs(bpy.types.AddonPreferences): if self.show_prefix_buttons: # subbox.prop(self, 'use_env_namespace') + """ row = subbox.row() row.prop(self, 'prefixes') row.operator('prefs.reset_gp_toolbox_env', text='', icon='LOOP_BACK').mode = 'PREFIXES' row = subbox.row() - row.prop(self, 'suffixes') - row.operator('prefs.reset_gp_toolbox_env', text='', icon='LOOP_BACK').mode = 'SUFFIXES' - - ## Collection UI list version # WIP # TODO - """ - pg = self.user_prefixes + """ + ## Collection UI list version # WIP + pg = self.prefixes row = subbox.row(align=True) - row.template_list("GPTB_UL_namespace_list", "", pg, "namespaces", pg, "idx", rows=6) + row.template_list("GPTB_UL_namespace_list", "", pg, "namespaces", pg, "idx", rows=4) subcol = row.column(align=True) # Lateral right - subcol.operator("gptb.add_namespace_prefix", icon="PLUS", text="") + subcol.operator("gptb.add_namespace_entry", icon="ADD", text="") + subcol.operator("gptb.remove_namespace_entry", icon="REMOVE", text="") subcol.separator() op_move = subcol.operator("gptb.move_item", icon="TRIA_UP", text="") # op_move.prop_name = 'namespaces' @@ -535,7 +567,14 @@ class GPTB_prefs(bpy.types.AddonPreferences): op_move = subcol.operator("gptb.move_item", icon="TRIA_DOWN", text="") # op_move.prop_name = 'namespaces' op_move.direction = 'DOWN' - """ + + ## Reset entry (Not needed anymore) + # subcol.separator() + # subcol.operator('prefs.reset_gp_toolbox_env', text='', icon='LOOP_BACK').mode = 'PREFIXES' + + row = subbox.row(align=True) + row.prop(self, 'suffixes') + row.operator('prefs.reset_gp_toolbox_env', text='', icon='LOOP_BACK').mode = 'SUFFIXES' ### TODO add render settings @@ -765,7 +804,28 @@ def set_env_properties(): # if prefs.use_env_namespace: prefix_list = os.getenv('PREFIXES') - prefs.prefixes = prefix_list if prefix_list else prefs.prefixes + ## old direct string assignment (now a property group) + # prefs.prefixes = prefix_list if prefix_list else prefs.prefixes + + if prefix_list: + prefix_list = prefix_list.strip(',').split(',') + current_pfix = [n.prefix for n in prefs.prefixes.namespaces if n.prefix] + for p in prefix_list: + pf = p.split(':')[0].strip() + name = '' if not ':' in p else p.split(':')[1].strip() + if pf not in current_pfix: + item = prefs.prefixes.namespaces.add() + item.prefix = pf + item.name = name + item.is_project = True + else: + prefix_list = [] + + # "release" suffix that are not in project anymore + for n in prefs.prefixes.namespaces: + # if n.is_project and not n.prefix in prefix_list: + if n.prefix not in prefix_list: + n.is_project = False suffix_list = os.getenv('SUFFIXES') prefs.suffixes = suffix_list if suffix_list else prefs.suffixes @@ -808,11 +868,14 @@ class GPTB_set_env_settings(bpy.types.Operator): classes = ( - # GP_PG_namespace_props, - # GP_PG_namespaces, - # GPTB_OT_add_namespace_prefix, - # GPTB_OT_move_item, - # GPTB_UL_namespace_list, + ## layer name management + GP_PG_namespace_props, + GP_PG_namespaces, + GPTB_OT_add_namespace_entry, + GPTB_OT_remove_namespace_entry, + GPTB_OT_move_item, + GPTB_UL_namespace_list, + GP_PG_FixSettings, GP_PG_ToolsSettings, GPTB_set_env_settings, @@ -867,7 +930,7 @@ def register(): if not 'remap_relative' in [hand.__name__ for hand in bpy.app.handlers.save_pre]: bpy.app.handlers.save_pre.append(remap_relative) - ## change a variable in prefs if a '.git is detected' + ## Change a variable in prefs if a '.git is detected' prefs.is_git_repo = (Path(__file__).parent / '.git').exists() prefs.has_git = bool(which('git')) diff --git a/properties.py b/properties.py index b7a6937..77328b1 100755 --- a/properties.py +++ b/properties.py @@ -234,7 +234,11 @@ class GP_PG_namespace_props(PropertyGroup): name="Name", description="Name that represent this prefix (used as hint and tooltip)", default="") hide : BoolProperty( - name="Hide", description="Hide this prefix from layer prefex management", + name="Hide", description="Hide this prefix from layer prefix management", + default=False) + + is_project : BoolProperty( + name="Project", description="Show this propery was set by project environnement (not deletable if that's the case)", default=False) class GP_PG_namespaces(PropertyGroup):