← sequencer-addon

Changes: - Adapted to work with version 3.3.2 SPA Studios current version. - Added a reload guard in `__init__.py` to dynamically reload submodules if they are already loaded. This ensures that changes to submodule code are reflected without needing to restart Blender. - Modified the `register` and `unregister` functions in `sync/core.py` and `utils.py` to include try-except blocks around class registration and unregistration calls. This prevents errors when attempting to register a class that's already registered or unregister a class that's not. - Added debug print statements across `register` and `unregister` functions to provide clear feedback in the console about the addon's loading state, especially useful during development. - Updated `gpu_utils.py` to use the correct shader `2D_UNIFORM_COLOR` and added comments regarding the use of color attributes in the `OverlayDrawer` class.

ca2690797b2b0ae90bc5354d8e5bf956ce068e0f · ovidiucs · Feb 22, 2024 01:08

+97 −30 · 4 files changed

  • spa_sequencer/__init__.py +30 −5
  • spa_sequencer/gpu_utils.py +4 −1
  • spa_sequencer/sync/core.py +47 −21
  • spa_sequencer/utils.py +16 −3
diff --git a/spa_sequencer/__init__.py b/spa_sequencer/__init__.py
index c5411d4..1071b6d 100644
--- a/spa_sequencer/__init__.py
+++ b/spa_sequencer/__init__.py
@@ -1,6 +1,29 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 # Copyright (C) 2023, The SPA Studios. All rights reserved.
 
+import bpy
+import importlib
+
+# List of submodule names as strings
+submodules = [
+    "editorial",
+    "keymaps",
+    "preferences",
+    "render",
+    "sequence",
+    "shared_folders",
+    "shot",
+    "sync",
+]
+
+# Reload guard
+for submodule in submodules:
+    if submodule in locals():
+        importlib.reload(locals()[submodule])
+    else:
+        exec(f"from . import {submodule}")
+
+# Now, you can safely reference the modules directly
 from spa_sequencer import (
     editorial,
     keymaps,
@@ -12,7 +35,6 @@ from spa_sequencer import (
     sync,
 )
 
-
 bl_info = {
     "name": "Sequencer",
     "author": "The SPA Studios",
@@ -24,7 +46,6 @@ bl_info = {
     "category": "SPA",
 }
 
-
 packages = (
     sync,
     shot,
@@ -36,12 +57,16 @@ packages = (
     keymaps,
 )
 
-
 def register():
+    print("Starting addon registration")
     for package in packages:
+        print(f"Registering package: {package.__name__}")
         package.register()
-
+    print("Addon registration completed")
 
 def unregister():
-    for package in packages:
+    print("Starting addon unregistration")
+    for package in reversed(packages):
+        print(f"Unregistering package: {package.__name__}")
         package.unregister()
+    print("Addon unregistration completed")
diff --git a/spa_sequencer/gpu_utils.py b/spa_sequencer/gpu_utils.py
index 1f386af..f125143 100644
--- a/spa_sequencer/gpu_utils.py
+++ b/spa_sequencer/gpu_utils.py
@@ -22,11 +22,14 @@ class OverlayDrawer:
 
     def __init__(self):
         self.format = gpu.types.GPUVertFormat()
-        self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
+        # Change "UNIFORM_COLOR" to "2D_UNIFORM_COLOR"
+        self.shader = gpu.shader.from_builtin("2D_UNIFORM_COLOR")
 
         self.pos_id = self.format.attr_add(
             id="pos", comp_type="F32", len=2, fetch_mode="FLOAT"
         )
+        # Since you're using a uniform color, you might not need to add a color attribute to the format.
+        # However, if you plan to use per-vertex colors, then keep this line.
         self.color_id = self.format.attr_add(
             id="color", comp_type="F32", len=2, fetch_mode="FLOAT"
         )
diff --git a/spa_sequencer/sync/core.py b/spa_sequencer/sync/core.py
index ed50e09..dcff04e 100644
--- a/spa_sequencer/sync/core.py
+++ b/spa_sequencer/sync/core.py
@@ -634,32 +634,58 @@ classes = (TimelineSyncSettings,)
 
 
 def register():
-    register_classes(classes)
+    # Development-only: Forcefully unregister class if already registered
+    # This is a safeguard and should not be necessary in production
+    try:
+        bpy.utils.unregister_class(TimelineSyncSettings)
+    except Exception as e:
+        print(f"Development-only: Could not unregister TimelineSyncSettings: {e}")
 
+    print("Registering sync/core components")
+    bpy.utils.register_class(TimelineSyncSettings)
+    
     # Store Synchronization settings on the WindowManager type
-    # NOTE: this is not saved in the Blender file
-    bpy.types.WindowManager.timeline_sync_settings = bpy.props.PointerProperty(
-        type=TimelineSyncSettings,
-        name="Timeline Synchronization Settings",
-    )
-
+    if not hasattr(bpy.types.WindowManager, 'timeline_sync_settings'):
+        bpy.types.WindowManager.timeline_sync_settings = bpy.props.PointerProperty(
+            type=TimelineSyncSettings,
+            name="Timeline Synchronization Settings",
+        )
+        
     # React to scenes current frame changes
-    bpy.app.handlers.frame_change_post.append(on_frame_changed)
+    if on_frame_changed not in bpy.app.handlers.frame_change_post:
+        bpy.app.handlers.frame_change_post.append(on_frame_changed)
     # React to file opening
-    bpy.app.handlers.load_pre.append(on_load_pre)
-    bpy.app.handlers.load_post.append(on_load_post)
+    if on_load_pre not in bpy.app.handlers.load_pre:
+        bpy.app.handlers.load_pre.append(on_load_pre)
+    if on_load_post not in bpy.app.handlers.load_post:
+        bpy.app.handlers.load_post.append(on_load_post)
 
-    bpy.app.handlers.undo_post.append(on_undo_redo)
-    bpy.app.handlers.redo_post.append(on_undo_redo)
+    if on_undo_redo not in bpy.app.handlers.undo_post:
+        bpy.app.handlers.undo_post.append(on_undo_redo)
+    if on_undo_redo not in bpy.app.handlers.redo_post:
+        bpy.app.handlers.redo_post.append(on_undo_redo)
 
 
 def unregister():
-    unregister_classes(classes)
-
-    del bpy.types.WindowManager.timeline_sync_settings
-    bpy.app.handlers.frame_change_post.remove(on_frame_changed)
-    bpy.app.handlers.load_pre.remove(on_load_pre)
-    bpy.app.handlers.load_post.remove(on_load_post)
-
-    bpy.app.handlers.undo_post.remove(on_undo_redo)
-    bpy.app.handlers.redo_post.remove(on_undo_redo)
+    print("Unregistering sync/core components")
+    try:
+        bpy.utils.unregister_class(TimelineSyncSettings)
+    except RuntimeError as e:
+        print(f"Could not unregister TimelineSyncSettings: {e}")
+    
+    if hasattr(bpy.types.WindowManager, 'timeline_sync_settings'):
+        del bpy.types.WindowManager.timeline_sync_settings
+    
+    # Remove handlers safely
+    if on_frame_changed in bpy.app.handlers.frame_change_post:
+        bpy.app.handlers.frame_change_post.remove(on_frame_changed)
+    if on_load_pre in bpy.app.handlers.load_pre:
+        bpy.app.handlers.load_pre.remove(on_load_pre)
+    if on_load_post in bpy.app.handlers.load_post:
+        bpy.app.handlers.load_post.remove(on_load_post)
+    if on_undo_redo in bpy.app.handlers.undo_post:
+        bpy.app.handlers.undo_post.remove(on_undo_redo)
+    if on_undo_redo in bpy.app.handlers.redo_post:
+        bpy.app.handlers.redo_post.remove(on_undo_redo)
+
+    print("sync/core components unregistered")
diff --git a/spa_sequencer/utils.py b/spa_sequencer/utils.py
index 439fa0a..2ffe187 100644
--- a/spa_sequencer/utils.py
+++ b/spa_sequencer/utils.py
@@ -77,12 +77,19 @@ def register_classes(classes: tuple[BlenderTypeClass, ...]):
                 continue
 
     for c in classes:
-        bpy.utils.register_class(c)
+        try:
+            bpy.utils.register_class(c)
+        except ValueError as e:
+            # This assumes that the ValueError is due to the class already being registered
+            print(f"Warning: Attempted to register class {c.__name__} that might already be registered. {e}")
+        except Exception as e:
+            print(f"Error: Failed to register class {c.__name__}. {e}")
+
         if issubclass(c, (bpy.types.Operator, bpy.types.Macro)):
             try:
                 register_operator_keymaps(c)
             except Exception as e:
-                log.warning(f"Failed to register {c.bl_idname} keymaps: {e}")
+                print(f"Warning: Failed to register {c.bl_idname} keymaps: {e}")
 
 
 def unregister_classes(classes: tuple[BlenderTypeClass, ...], reverse=True):
@@ -91,7 +98,13 @@ def unregister_classes(classes: tuple[BlenderTypeClass, ...], reverse=True):
     :param classes: the classes to unregister
     """
     for c in reversed(classes) if reverse else classes:
-        bpy.utils.unregister_class(c)
+        try:
+            bpy.utils.unregister_class(c)
+        except ValueError as e:
+            # This assumes that the ValueError is due to the class not being registered
+            print(f"Warning: Attempted to unregister class {c.__name__} that might not be registered. {e}")
+        except Exception as e:
+            print(f"Error: Failed to unregister class {c.__name__}. {e}")
 
 
 def remove_auto_numbering_suffix(name: str) -> str: