So,I was looking to accelerate the coloring workflow in grease pencil by creating a custom menu of the active GP palette colors. The workflow would be to assign a hotkey to this custom menu and then invoke it while coloring.I have scripted a Python code for this purpose andfacing the following issues-

1.Since GPcolors are array of RGB values(correct me if I am wrong) couldn’t find any pointer functions to point to array values. 2.The code when run indicates an endless loop of menus. Any suggestions would help.The code is given below-

import bpy
class GPcolorMenu(bpy.types.Menu):
    bl_label = "GPcolors"
    bl_idname = "gpencil.GPcolor_menu"

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

        for color in bpy.data.grease_pencil["GPencil"].palettes["GP_Palette"].colors:


            layout.menu(GPcolorMenu.bl_idname, text=color.name)


def register():
    bpy.utils.register_module(__name__)    


def unregister():
    bpy.utils.unregister_module(__name__)  

if __name__ == "__main__":
    register()


bpy.ops.wm.call_menu(name=GPcolorMenu.bl_idname) 
  • So,I edited the code to reflect the grease pencil colors in the active palette and got the following issues - 1.Since GPcolors are arrays I couldn't find any pointer function to point to them. 2.The code when run indicates an endless loop of menus. – starzar Oct 7 at 5:11
  • currently, your code is trying to instantiate its own class - the complete menu - in a loop, leading to the infinite recursion you experience. Your code instead should build menu-ITEMS. The draw() function then already displays them. – aliasguru Oct 7 at 6:35
  • and please, when pasting code, make sure to add one extra indentation level to the whole code. This tells StackExchange to format the text as Python code. – aliasguru Oct 7 at 6:37

Here is the probable solution (but it gives an Anytype error)

import bpy
from bpy.types import Menu

class GPcolorsMenu(bpy.types.Menu):
    bl_label = "GPcolors"
    bl_idname = "gpencil.GPcolorSwitch"

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

        #display active palette 
        palette = bpy.context.scene.grease_pencil.palettes.active
        row = layout.row(align=True)
        row.label(palette.name, icon_value=layout.icon(palette))

        col = layout.column(align=True)
        col.separator()

        #display GPcolor [keys()] for switching in a menu 

        key = bpy.context.scene.grease_pencil.palettes.active.colors.keys()
        for i in key:
            row = layout.row(align=True)
            row.prop(i,'name',text='')


def register():
    bpy.utils.register_class(GPcolorsMenu)


def unregister():
    bpy.utils.unregister_class(GPcolorsMenu)

if __name__ == "__main__":
    register()


    bpy.ops.wm.call_menu(name=GPcolorsMenu.bl_idname)
  • i is the name since blah.keys() is a collection of name strings , whereas you want (for code above with layout.prop(i, "name') to use ...active.colors.values() Often simpler to use for key, value in blah.items(): where each blah[key] = value and in most cases blah[key].name = key Btw properties, except booleans, are not really designed for a menu layout. – batFINGER Oct 28 at 13:19

Currently, your code is trying to instantiate its own class - the complete menu - in a loop, leading to the infinite recursion you experience. Your code instead should build menuITEMS. The draw() function then already displays them.

You can see what I mean if you change the line within your loop to create a label instead of instantiating the whole class:

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

    for color in bpy.data.grease_pencil["GPencil"].palettes["GP_Palette"].colors:
        layout.label(text=color.name)

So what you need to achieve next is to write an operator that does the color switching for you, and replace above code with:

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

    for color in context.scene.grease_pencil.palettes["GP_Palette"].colors:
        layout.operator(MyOwnColorSwitcherClass.bl_idname, text=color.name)

I also suggest digging out the grease pencil palette in a more stable way, but that depends on where you want your GP data to come from. in the example above, I used context.scene.grease_pencil to retrieve the currently active one, instead of digging into bpy.data and pull it by name. You can also check context.active_gpencil_palette and context.active_gpencil_palettecolor, maybe they yield something useful while your're within your class.

@aliasguru thanks for the reply. So I was looking to script the colorswitch operator and found that gpencil color is a collection of two set of props - strokecolor and fillcolor. I am not sure how to access a collection like in case of a gpencil colorindex.I did try using context_pointer_set function to point to the activepalette colors index.The code is given below, but it gives an context attribute error .Plz suggest any way to resolve the error or any other way to resolve this issue, if possible.

import bpy class GPcolorMenu(bpy.types.Menu): bl_label = “GPcolors” bl_idname = “gpencil.GPcolor_menu”

Copy to clipboard def draw(self, context): layout = self.layout

 for color in bpy.data.grease_pencil["GPencil"].palettes["GP_Palette"].colors:

     row = layout.row()

     row.context_pointer_set("active_palettecolors", color) 
     layout.menu(context.active_palettecolors, text=color.name)

def register(): bpy.utils.register_module(name)

def unregister(): bpy.utils.unregister_module(name)

if name == “main”: register()

bpy.ops.wm.call_menu(name=GPcolorMenu.bl_idname)

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.