0
$\begingroup$

Im trying to set the blend_mode property of a GPencilLayer in the setter of an EnumProperty, so, when that enum changes, also changes the GPencilLayer's blend_mode

Modifying this @Karan's answer in a previous question:

(This will only work if a GreasePencil object is active (it takes its first GPencilLayer)).

import bpy
from bpy.types import Panel, PropertyGroup
from bpy.props import *


def get_layer0():
    return bpy.context.active_object.data.layers[0]

class CUSTOM_PG_property_group(PropertyGroup):

    def get_blend_mode(self):
        return self.get("blend_mode", "REGULAR")

    def set_blend_mode(self, value):
        layer_value = ""
        print(f"{value=}")
        if value == 'REGULAR':
            layer_value = "REGULAR"
            value = 0
        elif value == 'HARDLIGHT':
            value = 1
            layer_value = "HARDLIGHT"
        elif value == 'ADD':
            value = 2
            layer_value = "ADD"
        elif value == 'SUBTRACT':
            value = 3
            layer_value = "SUBTRACT"
        elif value == 'MULTIPLY':
            layer_value = 'MULTIPLY'
            value = 4
        elif value == 'DIVIDE':
            layer_value = "DIVIDE"
            value = 5

        self["blend_mode"] = value
        layer0 = get_layer0()
        print(f"{layer_value = }")
        print(f"{type(layer_value) = }")
#        layer0.blend_mode =  "ADD" # This works!
#        None of these works: (WHY???)
#        layer0.blend_mode = layer_value
#        layer0.blend_mode = value
#        layer0.blend_mode = str(layer_value)
#        layer0.blend_mode = {layer_value}

        setattr(layer0, "blend_mode", layer_value)



    blend_mode : EnumProperty(
        name = "Blend Mode",
        description = "TODO add description",
        items = (
            ("REGULAR", "Regular", ""),
            ("HARDLIGHT", "Hardlight", ""),
            ("ADD", "Add", ""),
            ("SUBTRACT", "Subtract", ""),
            ("MULTIPLY", "Multiply", ""),
            ("DIVIDE", "Divide", ""),
        ),
        get = get_blend_mode,
        set = set_blend_mode,
        default = "REGULAR",
    )


class HelloWorldPanel(Panel):
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Test"

    def draw(self, context):
        layout = self.layout

        custom = context.scene.custom
        
        layout.prop(custom, 'blend_mode')
        
        layout.label(text=f"{get_layer0().blend_mode=}")


classes = (
    CUSTOM_PG_property_group,
    HelloWorldPanel,
)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)

    bpy.types.Scene.custom = PointerProperty(type=CUSTOM_PG_property_group)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    
    del bpy.types.Scene.custom


if __name__ == "__main__":
    register()

I can't understand how some of the commented code do not work. The only thing that works is setting the blend mode to a constant value. But if this value comes from a variable, it just don't work.

I tried the same code in Blender's console:

layer0 = bpy.context.active_object.data.layers[0]
a_blend_mode = "ADD"
layer0.blend_mode = a_blend_mode

And it works perfectly. But when is called the same from the setter, it doesn't.

Why?

$\endgroup$
1
  • $\begingroup$ I think you should use update() of the EnumProperty $\endgroup$
    – Karan
    Jul 29, 2023 at 19:10

2 Answers 2

2
$\begingroup$

Your set_blend_mode function has some problems and needs cleanup. The value param is an int but your if/elif block treats it as a string. Because of this, layer_value is not updated and still holds "". Now you should understand why layer0.blend_mode = "ADD" works, but all the other versions not, they get wrong data feeded. When you open the console with Window > Toggle System Console you'll see this error message:

Traceback (most recent call last):
  File "\Text", line 47, in set_blend_mode
TypeError: bpy_struct: item.attr = val: enum "" not found in ('REGULAR', 'HARDLIGHT', 'ADD', 'SUBTRACT', 'MULTIPLY', 'DIVIDE')
File "\Text", line 14, in set_blend_mode

which makes hopefully sense now because as said layer_value = "", hence enum "" not found in ... when this line is executed setattr(layer0, "blend_mode", layer_value).

Your if/elif is suboptimal anyway. If you want to easily add new enum items without fixing the if/elif everytime, you should map the value param to your enum items in a general way. Replace the whole if/elif block with:

enum_items = [ i.identifier for i in self.bl_rna.properties["blend_mode"].enum_items ]
layer_value = enum_items[value]

This grabs all the identifiers ("REGULAR", "HARDLIGHT", ...) of the enum items you defined in your EnumProperty blend_mode and value is just the correct index to return the one you need.

$\endgroup$
2
  • $\begingroup$ OMG What a mistake! I mixed some code. Thank you so much for the help friend, and also thanks for the further explanation for simplifying the if! Much appreciated :) $\endgroup$
    – Ommadawn
    Jul 29, 2023 at 13:30
  • 1
    $\begingroup$ You're welcome, happy coding. $\endgroup$
    – taiyo
    Jul 29, 2023 at 13:43
2
$\begingroup$

Use update() of the EnumProperty

import bpy
from bpy.types import Panel, PropertyGroup
from bpy.props import *


class CUSTOM_PG_property_group(PropertyGroup):
    
    def update_blend_mode(self, context):
        if context.object.type != 'GPENCIL':
            return
        context.object.data.layers.active.blend_mode = self.blend_mode

    blend_mode : EnumProperty(
        name = "Blend Mode",
        description = "TODO add description",
        items = (
            ("REGULAR", "Regular", ""),
            ("HARDLIGHT", "Hardlight", ""),
            ("ADD", "Add", ""),
            ("SUBTRACT", "Subtract", ""),
            ("MULTIPLY", "Multiply", ""),
            ("DIVIDE", "Divide", ""),
        ),
        update = update_blend_mode,
        default = "REGULAR",
    )


class HelloWorldPanel(Panel):
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Test"

    def draw(self, context):
        layout = self.layout

        custom = context.scene.custom

        layout.prop(custom, 'blend_mode')


classes = (
    CUSTOM_PG_property_group,
    HelloWorldPanel,
)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)

    bpy.types.Scene.custom = PointerProperty(type=CUSTOM_PG_property_group)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    
    del bpy.types.Scene.custom


if __name__ == "__main__":
    register()
$\endgroup$
1
  • $\begingroup$ Thats also a nice option. Thank you so much mate, much appreciated! 🙏 $\endgroup$
    – Ommadawn
    Jul 29, 2023 at 19:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .