diff --git a/CHANGELOG.md b/CHANGELOG.md index 8815163..5912f61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +4.0.1 + +- fixed: layer nav operator on page up/down + +4.0.0 + +- changed: version for Blender 4.3 - Breaking retrocompatibility with previous. + 3.3.0 - added: `Move Material To Layer` has now option to copy instead of moving in pop-up menu. diff --git a/GP_guided_colorize/OP_create_empty_frames.py b/GP_guided_colorize/OP_create_empty_frames.py index 1fe1c2f..2ca5fe3 100644 --- a/GP_guided_colorize/OP_create_empty_frames.py +++ b/GP_guided_colorize/OP_create_empty_frames.py @@ -5,6 +5,7 @@ from bpy.props import (FloatProperty, EnumProperty, StringProperty, IntProperty) +from .. import utils ## copied from OP_key_duplicate_send def get_layer_list(self, context): @@ -14,12 +15,6 @@ def get_layer_list(self, context): 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): bl_idname = "gp.create_empty_frames" @@ -84,7 +79,8 @@ class GP_OT_create_empty_frames(bpy.types.Operator): 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) + layer_from_group = utils.get_top_layer_from_group(gp, gp.layer_groups.active) + ## Can just do if not utils.get_closest_active_layer(context.grease_pencil): 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'} @@ -126,7 +122,7 @@ class GP_OT_create_empty_frames(bpy.types.Operator): gpl = gp.layers if gp.layer_groups.active: - reference_layer = get_top_layer_from_group(gp, gp.layer_groups.active) + reference_layer = utils.get_top_layer_from_group(gp, gp.layer_groups.active) else: reference_layer = gpl.active diff --git a/OP_layer_nav.py b/OP_layer_nav.py index b5e9306..918662f 100644 --- a/OP_layer_nav.py +++ b/OP_layer_nav.py @@ -26,10 +26,11 @@ class GPT_OT_layer_nav(bpy.types.Operator): prefs = utils.get_addon_prefs() if not prefs.nav_use_fade: if self.direction == 'DOWN': - utils.iterate_selector(context.object.data.layers, 'active_index', -1, info_attr = 'name') + utils.iterate_active_layer(context.grease_pencil, -1) + # utils.iterate_selector(context.object.data.layers, 'active_index', -1, info_attr = 'name') # gpv2 if self.direction == 'UP': - utils.iterate_selector(context.object.data.layers, 'active_index', 1, info_attr = 'name') + utils.iterate_active_layer(context.grease_pencil, 1) return {'FINISHED'} ## get up and down keys for use in modal @@ -91,12 +92,11 @@ class GPT_OT_layer_nav(bpy.types.Operator): context.space_data.overlay.gpencil_fade_layer = fade if self.direction == 'DOWN' or ((event.type in self.down_keys) and event.value == 'PRESS'): - _val = utils.iterate_selector(context.object.data.layers, 'active_index', -1, info_attr = 'name') + _val = utils.iterate_active_layer(context.grease_pencil, -1) trigger = True if self.direction == 'UP' or ((event.type in self.up_keys) and event.value == 'PRESS'): - _val = utils.iterate_selector(context.object.data.layers, 'active_index', 1, info_attr = 'name') - # utils.iterate_selector(bpy.context.scene.grease_pencil.layers, 'active_index', 1, info_attr = 'name')#layers + _val = utils.iterate_active_layer(context.grease_pencil, 1) trigger = True if trigger: diff --git a/__init__.py b/__init__.py index d71a6bd..7030933 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": (4, 0, 0), +"version": (4, 0, 1), "blender": (4, 3, 0), "location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", "warning": "", @@ -336,7 +336,7 @@ class GPTB_prefs(bpy.types.AddonPreferences): nav_fade_val : FloatProperty( name='Fade Value', description='Fade value for other layers when navigating (0=invisible)', - default=0.35, min=0.0, max=0.95, step=1, precision=2) + default=0.1, min=0.0, max=0.95, step=1, precision=2) nav_limit : FloatProperty( name='Fade Duration', diff --git a/utils.py b/utils.py index 7040ef8..6fae8c8 100644 --- a/utils.py +++ b/utils.py @@ -162,6 +162,33 @@ def layer_active_index(gpl): ''' return next((i for i, l in enumerate(gpl) if l == gpl.active), None) +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 + +def get_closest_active_layer(gp): + '''Get active layer from GP object, getting upper layer if in group + if a group is active, return the top layer of this group + if group is active but no layer in it, return None + ''' + + if gp.layers.active: + return gp.layers.active + ## No active layer, return active from group (can be None !) + return get_top_layer_from_group(gp, gp.layer_groups.active) + +def closest_layer_active_index(gp, fallback_index=0): + '''Get active layer index from GP object, getting upper layer if in group + if a group is active, return index at the top layer of this group + if group is active but no layer in it, return fallback_index (0 by default, stack bottom)''' + closest_active_layer = get_closest_active_layer(gp) + if closest_active_layer: + return next((i for i, l in enumerate(gp.layers) if l == closest_active_layer), fallback_index) + return fallback_index + ## Check for nested lock def is_locked(stack_item): '''Check if passed stack item (layer or group) is locked @@ -1200,6 +1227,38 @@ def iterate_selector(zone, attr, state, info_attr = None, active_access='active' return info, bottom +def iterate_active_layer(gpd, state): + '''Iterate active GP layer in stack + gpd: Grease Pencil Data + ''' + layers = gpd.layers + l_count = len(layers) + + if state: # swap + # info = None + # bottom = None + + ## Get active layer index + active_index = closest_layer_active_index(gpd, fallback_index=None) + if active_index == None: + ## fallback to first layer if nothing found + gpd.layers.active = layers[0] + return + + target_index = active_index + state + new_index = target_index % l_count + + ## set active layer + gpd.layers.active = layers[new_index] + + if target_index == l_count: + bottom = 1 # bottom reached, cycle to first + elif target_index < 0: + bottom = -1 # up reached, cycle to last + + # info = gpd.layers.active.name + # return info, bottom + # ----------------- ### Curve handle # -----------------