backport cursor follow fix from gpv3 - add msg_bus on selection change owned by GreasePencil type

3.3.2

- added: fix cursor follow and add optional target object (backported from gpv3)
gpv2
pullusb 2024-12-03 17:23:10 +01:00
parent e51cc474d6
commit cca9494ae4
5 changed files with 72 additions and 17 deletions

View File

@ -1,10 +1,15 @@
# Changelog
GPv2
3.3.2
- added: fix cursor follow and add optional target object (backported from gpv3)
3.3.1
- added: improve file checker and visibility conflict feature (backported from gpv3)
-- GPv2 code - Above this line, version is separated from 4.3+ version (using GPv3) --
3.3.0
- added: `Move Material To Layer` has now option to copy instead of moving in pop-up menu.

View File

@ -3,6 +3,7 @@ import bpy
import mathutils
from bpy_extras import view3d_utils
from .utils import get_gp_draw_plane, region_to_location, get_view_origin_position
from bpy.app.handlers import persistent
## override all sursor snap shortcut with this in keymap
class GPTB_OT_cusor_snap(bpy.types.Operator):
@ -110,15 +111,20 @@ prev_matrix = None
# @call_once(bpy.app.handlers.frame_change_post)
def cursor_follow_update(self,context):
## used in properties file to register in boolprop update
def cursor_follow_update(self, context):
'''append or remove cursor_follow handler according a boolean'''
ob = bpy.context.object
if bpy.context.scene.gptoolprops.cursor_follow_target:
## override with target object is specified
ob = bpy.context.scene.gptoolprops.cursor_follow_target
global prev_matrix
# imported in properties to register in boolprop update
if self.cursor_follow:#True
if ob:
# out of below condition to be called when setting target as well
prev_matrix = ob.matrix_world.copy()
if not cursor_follow.__name__ in [hand.__name__ for hand in bpy.app.handlers.frame_change_post]:
if context.object:
prev_matrix = context.object.matrix_world
bpy.app.handlers.frame_change_post.append(cursor_follow)
else:#False
@ -129,11 +135,13 @@ def cursor_follow_update(self,context):
def cursor_follow(scene):
'''Handler to make the cursor follow active object matrix changes on frame change'''
## TODO update global prev_matrix to equal current_matrix on selection change (need another handler)...
if not bpy.context.object:
ob = bpy.context.object
if bpy.context.scene.gptoolprops.cursor_follow_target:
## override with target object is specified
ob = bpy.context.scene.gptoolprops.cursor_follow_target
if not ob:
return
global prev_matrix
ob = bpy.context.object
current_matrix = ob.matrix_world
if not prev_matrix:
prev_matrix = current_matrix.copy()
@ -146,9 +154,7 @@ def cursor_follow(scene):
## translation only
# scene.cursor.location += (current_matrix - prev_matrix).to_translation()
# print('offset:', (current_matrix - prev_matrix).to_translation())
## full
scene.cursor.location = current_matrix @ (prev_matrix.inverted() @ scene.cursor.location)
@ -156,6 +162,38 @@ def cursor_follow(scene):
prev_matrix = current_matrix.copy()
prev_active_obj = None
## Add check for object selection change
def selection_changed():
"""Callback function for selection changes"""
if not bpy.context.scene.gptoolprops.cursor_follow:
return
if bpy.context.scene.gptoolprops.cursor_follow_target:
# we are following a target, nothing to update on selection change
return
global prev_matrix, prev_active_obj
if prev_active_obj != bpy.context.object:
## Set stored matrix to active object
prev_matrix = bpy.context.object.matrix_world.copy()
prev_active_obj = bpy.context.object
## Note: Same owner as layer manager (will be removed as well)
def subscribe_object_change():
subscribe_to = (bpy.types.LayerObjects, 'active')
bpy.msgbus.subscribe_rna(
key=subscribe_to,
# owner of msgbus subcribe (for clearing later)
owner=bpy.types.GreasePencil, # <-- attach to ID during it's lifetime.
args=(),
notify=selection_changed,
options={'PERSISTENT'},
)
@persistent
def subscribe_object_change_handler(dummy):
subscribe_object_change()
classes = (
GPTB_OT_cusor_snap,
)
@ -163,14 +201,18 @@ GPTB_OT_cusor_snap,
def register():
for cls in classes:
bpy.utils.register_class(cls)
# swap_keymap_by_id('view3d.cursor3d','view3d.cursor_snap')#auto swap to custom GP snap wrap
## Follow cursor matrix update on object change
bpy.app.handlers.load_post.append(subscribe_object_change_handler) # select_change
## Directly set msgbus to work at first addon activation # select_change
bpy.app.timers.register(subscribe_object_change, first_interval=1) # select_change
# bpy.app.handlers.frame_change_post.append(cursor_follow)
## No need to frame_change_post.append(cursor_follow). Added by property update, when activating 'cursor follow'
def unregister():
# bpy.app.handlers.frame_change_post.remove(cursor_follow)
bpy.app.handlers.load_post.remove(subscribe_object_change_handler) # select_change
# swap_keymap_by_id('view3d.cursor_snap','view3d.cursor3d')#Restore normal snap
@ -179,4 +221,6 @@ def unregister():
# force remove handler if it's there at unregister
if cursor_follow.__name__ in [hand.__name__ for hand in bpy.app.handlers.frame_change_post]:
bpy.app.handlers.frame_change_post.remove(cursor_follow)
bpy.app.handlers.frame_change_post.remove(cursor_follow)
bpy.msgbus.clear_by_owner(bpy.types.GreasePencil)

View File

@ -279,7 +279,8 @@ class GPTB_PT_anim_manager(Panel):
col.use_property_split = False
text, icon = ('Cursor Follow On', 'PIVOT_CURSOR') if context.scene.gptoolprops.cursor_follow else ('Cursor Follow Off', 'CURSOR')
col.prop(context.scene.gptoolprops, 'cursor_follow', text=text, icon=icon)
if context.scene.gptoolprops.cursor_follow:
col.prop(context.scene.gptoolprops, 'cursor_follow_target', text='Target', icon='OBJECT_DATA')
class GPTB_PT_toolbox_playblast(Panel):
bl_label = "Playblast"

View File

@ -4,7 +4,7 @@ bl_info = {
"name": "GP toolbox",
"description": "Tool set for Grease Pencil in animation production",
"author": "Samuel Bernou, Christophe Seux",
"version": (3, 3, 1),
"version": (3, 3, 2),
"blender": (4, 0, 0),
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
"warning": "",

View File

@ -177,6 +177,11 @@ class GP_PG_ToolsSettings(PropertyGroup):
name='Cursor Follow', description="3D cursor follow active object animation when activated",
default=False, update=cursor_follow_update)
cursor_follow_target : bpy.props.PointerProperty(
name='Cursor Follow Target',
description="Optional target object to follow for cursor instead of active object",
type=bpy.types.Object, update=cursor_follow_update)
edit_lines_opacity : FloatProperty(
name="Edit Lines Opacity", description="Change edit lines opacity for all grease pencils",
default=0.5, min=0.0, max=1.0, step=3, precision=2, update=change_edit_lines_opacity)