5
$\begingroup$

I have successfully created a sub menu which extends the Shift+A menu in the shader editor but I would like to have the options show up as results in the search bar. Is this even possible, and if so how can it be done?

enter image description here

import bpy from bpy.types import Menu, Operator def draw_menu(self, context): layout = self.layout layout.separator() layout.menu("sub_menu") class SubMenu(bpy.types.Menu): bl_label = 'Math' bl_idname = 'sub_menu' def draw(self, context): layout = self.layout layout.operator("divide.node", text="Divide") layout.operator("multiply.node", text="Multiply") layout.operator("add.node", text="Add") layout.operator("subtract.node", text="Subtract") class DivideNode(Operator): bl_idname = "divide.node" bl_label = "DivideNode" def execute(self, context): bpy.ops.node.add_node(type="ShaderNodeMath", use_transform=True) bpy.data.materials["Material"].node_tree.nodes["Math"].operation = 'DIVIDE' return {'FINISHED'} class AddNode(Operator): bl_idname = "add.node" bl_label = "AddNode" def execute(self, context): bpy.ops.node.add_node(type="ShaderNodeMath", use_transform=True) bpy.data.materials["Material"].node_tree.nodes["Math"].operation = 'ADD' return {'FINISHED'} class SubtractNode(Operator): bl_idname = "subtract.node" bl_label = "SubtractNode" def execute(self, context): bpy.ops.node.add_node(type="ShaderNodeMath", use_transform=True) bpy.data.materials["Material"].node_tree.nodes["Math"].operation = 'SUBTRACT' return {'FINISHED'} class MultiplyNode(Operator): bl_idname = "multiply.node" bl_label = "MultiplyNode" def execute(self, context): bpy.ops.node.add_node(type="ShaderNodeMath", use_transform=True) bpy.data.materials["Material"].node_tree.nodes["Math"].operation = 'MULTIPLY' return {'FINISHED'} def register(): bpy.types.NODE_MT_add.append(draw_menu) bpy.utils.register_class(MultiplyNode) bpy.utils.register_class(SubMenu) bpy.utils.register_class(DivideNode) bpy.utils.register_class(SubtractNode) bpy.utils.register_class(AddNode) def unregister(): bpy.types.NODE_MT_add.remove(draw_menu) bpy.utils.unregister_class(MultiplyNode) bpy.utils.unregister_class(SubMenu) bpy.utils.unregister_class(DivideNode) bpy.utils.unregister_class(SubtractNode) bpy.utils.unregister_class(AddNode) if __name__ == "__main__": register() 
$\endgroup$
2

1 Answer 1

7
$\begingroup$

All the math node operations

Note: this doesn't answer how to put your operators into the search, rather is intended to offer another way to have same functionality in a far more easily extendable way

enter image description here

From one look at the question code instantly has me quoting

Foghorn Leghorn

No, no, no your're doing it all wrong

No menus one operator

Have taken code above and edited to have functionality as demonstrated, with no menus and one operator.

All the question operators are doing pretty much the same thing, the code varies little between them. Instead of an operator for each operation, one operator and an enum of possible operations.

The tricky bit.

When we add a math node, we add an instance of the type bpy.types.ShaderNodeMath. All the possible operations are available from its definition of the "operation" property.

[Look for links, been well covered]

Our one operator is going to pinch these.

The menus can be ditched because blender can automatically make a menu from the options. And boy there are a few. The items list can be narrowed to a select few if desired

Categorize the other way

The naming convention of your operators is, going by "standards", a bit A about T. Using "node.add_math_subtract" will classify it with all the other bpy.ops.node prefixed operators.

Operators use context

For any code run in the shader editor the material we're "lookin' at" is context material. This is the material the bpy.ops.node.foo_bar will work on. This will not always be bpy.data.materials["Material"]

Similarly only the first math node added via operator (bpy.ops.node.add_node(..)) will have the name "Math". Hence on subsequent runnings of question code will add a new node but change the operation of the first one added, ie the one with name "Math". Directly after running the operator the new node will be context.active_node .. another context member of the node editor.

Have instead added a math node to the node tree of the context material and set its operation and name accordingly.

import bpy from bpy.types import Menu, Operator, ShaderNodeMath from bpy.props import EnumProperty class AddMathNode(Operator): ''' Add Math Node ''' bl_idname = "node.add_math" bl_label = "Add Math Node" items = [ (p.identifier, p.name, p.description) for p in ShaderNodeMath.bl_rna.properties["operation"].enum_items ] #print(items) operation : EnumProperty( items=items, name="Operation", default='ADD', ) def execute(self, context): # the material in the node editor mat = context.material # add a new math node to its nodes n = mat.node_tree.nodes.new("ShaderNodeMath") # set some properties n.operation = self.operation n.name = self.operation.lower().title() # make active mat.node_tree.nodes.active = n return {'FINISHED'} #return bpy.ops.transform.translate('INVOKE_DEFAULT') # use translate classes = (AddMathNode,) def draw_menu(self, context): layout = self.layout layout.operator_menu_enum("node.add_math", "operation") def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.NODE_MT_add.append(draw_menu) def unregister(): for cls in classes: bpy.utils.register_class(cls) bpy.types.NODE_MT_add.remove(draw_menu) if __name__ == "__main__": register() 

Sorting them

There's lots of them. This change circa lines 9-12 sorts them by IDENTIFIER, eg ADD, SUBTRACT

 items = sorted( (p.identifier, p.name, p.description) for p in ShaderNodeMath.bl_rna.properties["operation"].enum_items ) 

Adding to the search menu.

Because this is now only a single operator removes the sense of searching for it. Possibly the logical extension of this is to categorize the operation (as is done via the UI to select math node operation)

With developer extras set to show view source option can right click over the add nodes menu and view source, revealing how the search menu is constructed and laid out.

def draw(self, context): layout = self.layout layout.operator_context = 'INVOKE_DEFAULT' if nodeitems_utils.has_node_categories(context): props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM') props.use_transform = True layout.separator() # actual node submenus are defined by draw functions from node categories nodeitems_utils.draw_node_categories_menu(self, context) 

Which reveals a helper module nodeitems_utils which we can pretty much pinch, to instead of using enum menu expansion can search and categorize. Perhaps for another day.

$\endgroup$
1
  • $\begingroup$ What does "A about T" mean? I am now intrigued. $\endgroup$ Commented Oct 18, 2023 at 22:16

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.