I want to catch the event when a color has been added to a Palette. I have tried subscribe_to = bpy.types.Palette, "colors" and subscribe_to = bpy.context.tool_settings.image_paint.palette.path_resolve("colors", False), but neither has worked. Can anyone please advise how I may detect when a Palette’s colors have changed? Thank you!
There’s currently no automatic publishing for changes to collection properties. Even though there’s both C and python API in place for publishing, many operators still use low level calls that bypass this. For adding colors to a palette, Blender does 1 allocation and one low level linked list append. No publishing.
I tested and found that not even a depsgraph update would be issued when a new color was added, so it looks like you would have to do the ol’ hook into panel’s draw method.
This example was tested for palettes in grease pencil and texture painting. There may be other modes. Note: This only works when the palette color panel is visible.
import bpy
from bl_ui.properties_paint_common import (
ColorPalettePanel, # The color palette panel.
UnifiedPaintPanel # For getting the palette from context.
)
from bl_ui.space_view3d_toolbar import (
VIEW3D_PT_tools_brush_swatches, # Texture palette panel
VIEW3D_PT_tools_grease_pencil_brush_mix_palette # Grease Pencil palette panel
)
def on_palette_colors_changed():
print("Colors were added or removed.")
# Store the last number of colors, keyed to palette name.
last_colors = {}
def check_palette(self, context):
palette = UnifiedPaintPanel.paint_settings(context).palette
num_colors = len(palette.colors)
num_colors_last = last_colors.get(palette.name, num_colors)
if num_colors_last != num_colors:
# Don't execute callbacks inside the panel's draw context.
bpy.app.timers.register(on_palette_colors_changed)
last_colors[palette.name] = num_colors
if __name__ == "__main__":
# For texture paint.
VIEW3D_PT_tools_brush_swatches.append(check_palette)
# For grease pencil palette.
VIEW3D_PT_tools_grease_pencil_brush_mix_palette.append(check_palette)