How to add a Button to the F-Curve Modifier Panel?

I’d like to add an icon button next to the copy & paste icon buttons in the F-Curve Modifier panel.
F-Curve Modifier Panel

Looking at the Blender source code, the panel’s name is GRAPH_PT_modifiers. Knowing that, I am using the following code (which works for adding to menus).

def menu_func(self, context):
    self.layout.operator(GRAPH_OT_My_Operator.bl_idname, text="", icon="RESTRICT_SELECT_OFF")

def register():

However, when I run this code, I get this error:

AttributeError: 'module' object has no attribute 'GRAPH_PT_modifiers'

Can anyone help me get a button to appear at this location? Thank you!

If you rightclick on the button and press ‘Edit Source’ is says that the button is not from a script, it is written inside the C codebase.

However you can place the function in another useful place, such as the toolbar.
Right click and edit source again: blender\3.0\scripts\startup\bl_ui\

Good thing is that you can append your operator to an existing menu or toolbar without having to modify the source (though if you really have to modify it you still can).

1 Like

Hi! Thank you for the reply! Yes, I’m familiar with editing the source from the startup\bl_ui files and appending a menu function. Could you please expand upon your last comment on how to modify the source? This is for an add-on, so I’d like for it to install a button in the user interface. It seems like one can only prepend or append to a toolbar, but not insert an operator at a specific location. Could I somehow access the panel’s layout and add a function in it? Panel.layout seems to be readonly. Thank you!

One problem is that you can’t modify these panels since they are implemented in the C source code.

If you go to the file you can see only that there are only menu items or the header toolbar that are extensible.

One flexible way is to append, at the last place of the top toolbar. But not in the place you want.

Another way is to modify your source code, which is a bit monolithic approach but at least you are very explicit. Adding this if statement first, will protect from breaking, just in case your addon isn’t loaded at startup or is inactive.

There is also another very advanced technique that you can modify the menus. I have not tried it yet. I am thinking if it causes any instability in the long term.

You can’t add a button exactly where you want (on the same row as the dropdown and copy/paste buttons) as they’re written in C as @const said.

You can, however, add things directly below it.

This creates a header-less panel using bl_options = {'HIDE_HEADER'}, which should make it topmost.

import bpy

class GRAPH_PT_hello(bpy.types.Panel):
    bl_label = "Hello World Panel"
    bl_idname = "GRAPH_PT_hello"
    bl_space_type = 'GRAPH_EDITOR'
    bl_region_type = 'UI'
    bl_category = 'Modifiers'
    bl_options = {'HIDE_HEADER'}

    def draw(self, context):
        row = self.layout.row()
        row.label(text="Hello World!")

if __name__ == "__main__":


I did this a few years ago when I made an incremental save addon and wanted to insert it in-between the Save entries under File. It kinda still “just works” ™

The procedure I used was roughly:

  1. Getting the panel’s draw method source using inspect
  2. String search and find the entry after which to insert.
  3. Insert my own entry.
  4. Ran exec to compile the new draw method.
  5. Use _dyn_ui_initialize() on the panel to get the draw functions list
  6. Replace the old draw method with the newly compiled one (backup the old)

The post and source: