Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-09-26 20:36:13 +0300
committerHans Goudey <h.goudey@me.com>2022-09-26 21:10:42 +0300
commit837144b4577f161baf1625f8a5478c83a088ea0f (patch)
tree4cb015aec5d1f8f5d1c6d0ff1ca060eba8b7f387
parent8a6dc0fac71cc5eb6fc945295b9c1f51f72cc407 (diff)
Nodes: Use plain menus for geometry nodes add menu
At the cost of slightly more boilerplate code, we can avoid the `NodeItem` and `NodeCategory` abstractions used to build the node add menu. This makes the menus more flexible and more obvious, which will make them easier to extend with assets. The identifiers for the new menu types are inconsistent with regular class naming for backwards compatibility with the old "category" menu naming. Also adds an item for the "Self Object" node missed in dd5131bd700c. Differential Revision: https://developer.blender.org/D15973
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/node_add_menu.py63
-rw-r--r--release/scripts/startup/bl_ui/node_add_menu_geometry.py395
-rw-r--r--release/scripts/startup/bl_ui/space_node.py8
-rw-r--r--release/scripts/startup/nodeitems_builtins.py305
5 files changed, 466 insertions, 307 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index a57a2cc5a4c..eaf61b58e6d 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -9,6 +9,8 @@ if "bpy" in locals():
del reload
_modules = [
+ "node_add_menu",
+ "node_add_menu_geometry",
"properties_animviz",
"properties_constraint",
"properties_data_armature",
diff --git a/release/scripts/startup/bl_ui/node_add_menu.py b/release/scripts/startup/bl_ui/node_add_menu.py
new file mode 100644
index 00000000000..17bff9a5087
--- /dev/null
+++ b/release/scripts/startup/bl_ui/node_add_menu.py
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+import bpy
+from bpy.types import Menu
+from bpy.app.translations import (
+ pgettext_iface as iface_,
+ contexts as i18n_contexts,
+)
+
+def add_node_type(layout, node_type, *, label=None):
+ """Add a node type to a menu."""
+ bl_rna = bpy.types.Node.bl_rna_get_subclass(node_type)
+ if not label:
+ label = bl_rna.name if bl_rna else iface_("Unknown")
+ translation_context = bl_rna.translation_context if bl_rna else i18n_contexts.default
+ props = layout.operator("node.add_node", text=label, text_ctxt=translation_context)
+ props.type = node_type
+ props.use_transform = True
+ return props
+
+
+def draw_node_group_add_menu(context, layout):
+ """Add items to the layout used for interacting with node groups."""
+ space_node = context.space_data
+ node_tree = space_node.edit_tree
+ all_node_groups = context.blend_data.node_groups
+
+ layout.operator("node.group_make")
+ layout.operator("node.group_ungroup")
+ if node_tree in all_node_groups.values():
+ layout.separator()
+ add_node_type(layout, "NodeGroupInput")
+ add_node_type(layout, "NodeGroupOutput")
+
+ if node_tree:
+ from nodeitems_builtins import node_tree_group_type
+ def contains_group(nodetree, group):
+ if nodetree == group:
+ return True
+ for node in nodetree.nodes:
+ if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
+ if contains_group(node.node_tree, group):
+ return True
+ return False
+
+ groups = [group for group in context.blend_data.node_groups if group.bl_idname == node_tree.bl_idname and
+ not contains_group(group, node_tree) and
+ not group.name.startswith('.')]
+ if groups:
+ layout.separator()
+ for group in groups:
+ props = add_node_type(layout, node_tree_group_type[group.bl_idname], label=group.name)
+ ops = props.settings.add()
+ ops.name = "node_tree"
+ ops.value = "bpy.data.node_groups[%r]" % group.name
+
+
+classes = (
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/node_add_menu_geometry.py b/release/scripts/startup/bl_ui/node_add_menu_geometry.py
new file mode 100644
index 00000000000..d164d0d2c83
--- /dev/null
+++ b/release/scripts/startup/bl_ui/node_add_menu_geometry.py
@@ -0,0 +1,395 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+import bpy
+from bpy.types import Menu
+from bl_ui import node_add_menu
+from bpy.app.translations import pgettext_iface as iface_
+
+class NODE_MT_geometry_node_GEO_ATTRIBUTE(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_ATTRIBUTE"
+ bl_label = "Attribute"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeCaptureAttribute")
+ node_add_menu.add_node_type(layout, "GeometryNodeAttributeDomainSize")
+ node_add_menu.add_node_type(layout, "GeometryNodeAttributeStatistic")
+ node_add_menu.add_node_type(layout, "GeometryNodeAttributeTransfer")
+ node_add_menu.add_node_type(layout, "GeometryNodeRemoveAttribute")
+ node_add_menu.add_node_type(layout, "GeometryNodeStoreNamedAttribute")
+
+class NODE_MT_geometry_node_GEO_COLOR(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_COLOR"
+ bl_label = "Color"
+
+ def draw(self, _context):
+ layout = self.layout
+ props = node_add_menu.add_node_type(layout, "ShaderNodeMix", label=iface_("Mix Color"))
+ ops = props.settings.add()
+ ops.name = "data_type"
+ ops.value = "'RGBA'"
+ node_add_menu.add_node_type(layout, "ShaderNodeRGBCurve")
+ node_add_menu.add_node_type(layout, "ShaderNodeValToRGB")
+ node_add_menu.add_node_type(layout, "FunctionNodeSeparateColor")
+ node_add_menu.add_node_type(layout, "FunctionNodeCombineColor")
+
+class NODE_MT_geometry_node_GEO_CURVE(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_CURVE"
+ bl_label = "Curve"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveLength")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveToMesh")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveToPoints")
+ node_add_menu.add_node_type(layout, "GeometryNodeDeformCurvesOnSurface")
+ node_add_menu.add_node_type(layout, "GeometryNodeFillCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeFilletCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeResampleCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeReverseCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeSampleCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeSubdivideCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeTrimCurve")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeInputControlPointNeighbors")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputCurveHandlePositions")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputTangent")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputCurveTilt")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveEndpointSelection")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveHandleTypeSelection")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputSplineCyclic")
+ node_add_menu.add_node_type(layout, "GeometryNodeSplineLength")
+ node_add_menu.add_node_type(layout, "GeometryNodeSplineParameter")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputSplineResolution")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeSetCurveRadius")
+ node_add_menu.add_node_type(layout, "GeometryNodeSetCurveTilt")
+ node_add_menu.add_node_type(layout, "GeometryNodeSetCurveHandlePositions")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveSetHandles")
+ node_add_menu.add_node_type(layout, "GeometryNodeSetSplineCyclic")
+ node_add_menu.add_node_type(layout, "GeometryNodeSetSplineResolution")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveSplineType")
+
+class NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE"
+ bl_label = "Curve Primitives"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveLine")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveCircle")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveStar")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveSpiral")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveArc")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurveQuadraticBezier")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveQuadrilateral")
+ node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveBezierSegment")
+
+class NODE_MT_geometry_node_GEO_GEOMETRY(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_GEOMETRY"
+ bl_label = "Geometry"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeBoundBox")
+ node_add_menu.add_node_type(layout, "GeometryNodeConvexHull")
+ node_add_menu.add_node_type(layout, "GeometryNodeDeleteGeometry")
+ node_add_menu.add_node_type(layout, "GeometryNodeDuplicateElements")
+ node_add_menu.add_node_type(layout, "GeometryNodeProximity")
+ node_add_menu.add_node_type(layout, "GeometryNodeGeometryToInstance")
+ node_add_menu.add_node_type(layout, "GeometryNodeJoinGeometry")
+ node_add_menu.add_node_type(layout, "GeometryNodeMergeByDistance")
+ node_add_menu.add_node_type(layout, "GeometryNodeRaycast")
+ node_add_menu.add_node_type(layout, "GeometryNodeSampleIndex")
+ node_add_menu.add_node_type(layout, "GeometryNodeSampleNearest")
+ node_add_menu.add_node_type(layout, "GeometryNodeSeparateComponents")
+ node_add_menu.add_node_type(layout, "GeometryNodeSeparateGeometry")
+ node_add_menu.add_node_type(layout, "GeometryNodeTransform")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeSetID")
+ node_add_menu.add_node_type(layout, "GeometryNodeSetPosition")
+
+class NODE_MT_geometry_node_GEO_INPUT(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_INPUT"
+ bl_label = "Input"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "FunctionNodeInputBool")
+ node_add_menu.add_node_type(layout, "GeometryNodeCollectionInfo")
+ node_add_menu.add_node_type(layout, "FunctionNodeInputColor")
+ node_add_menu.add_node_type(layout, "FunctionNodeInputInt")
+ node_add_menu.add_node_type(layout, "GeometryNodeIsViewport")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMaterial")
+ node_add_menu.add_node_type(layout, "GeometryNodeObjectInfo")
+ node_add_menu.add_node_type(layout, "GeometryNodeSelfObject")
+ node_add_menu.add_node_type(layout, "FunctionNodeInputString")
+ node_add_menu.add_node_type(layout, "ShaderNodeValue")
+ node_add_menu.add_node_type(layout, "FunctionNodeInputVector")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeInputID")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputIndex")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputNamedAttribute")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputNormal")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputPosition")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputRadius")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputSceneTime")
+
+class NODE_MT_geometry_node_GEO_INSTANCE(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_INSTANCE"
+ bl_label = "Instances"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeInstanceOnPoints")
+ node_add_menu.add_node_type(layout, "GeometryNodeInstancesToPoints")
+ node_add_menu.add_node_type(layout, "GeometryNodeRealizeInstances")
+ node_add_menu.add_node_type(layout, "GeometryNodeRotateInstances")
+ node_add_menu.add_node_type(layout, "GeometryNodeScaleInstances")
+ node_add_menu.add_node_type(layout, "GeometryNodeTranslateInstances")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceRotation")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceScale")
+
+class NODE_MT_geometry_node_GEO_MATERIAL(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_MATERIAL"
+ bl_label = "Material"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeReplaceMaterial")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMaterialIndex")
+ node_add_menu.add_node_type(layout, "GeometryNodeMaterialSelection")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeSetMaterial")
+ node_add_menu.add_node_type(layout, "GeometryNodeSetMaterialIndex")
+
+class NODE_MT_geometry_node_GEO_MESH(Menu):
+ bl_idname = "NODE_MT_geometry_node_GEO_MESH"
+ bl_label = "Mesh"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeDualMesh")
+ node_add_menu.add_node_type(layout, "GeometryNodeEdgePathsToCurves")
+ node_add_menu.add_node_type(layout, "GeometryNodeEdgePathsToSelection")
+ node_add_menu.add_node_type(layout, "GeometryNodeExtrudeMesh")
+ node_add_menu.add_node_type(layout, "GeometryNodeFlipFaces")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshBoolean")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshToCurve")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshToPoints")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshToVolume")
+ node_add_menu.add_node_type(layout, "GeometryNodeSampleNearestSurface")
+ node_add_menu.add_node_type(layout, "GeometryNodeScaleElements")
+ node_add_menu.add_node_type(layout, "GeometryNodeSplitEdges")
+ node_add_menu.add_node_type(layout, "GeometryNodeSubdivideMesh")
+ node_add_menu.add_node_type(layout, "GeometryNodeSubdivisionSurface")
+ node_add_menu.add_node_type(layout, "GeometryNodeTriangulate")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeAngle")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeNeighbors")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshEdgeVertices")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceArea")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceNeighbors")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshFaceSetBoundaries")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshFaceIsPlanar")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputShadeSmooth")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshIsland")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputShortestEdgePaths")
+ node_add_menu.add_node_type(layout, "GeometryNodeInputMeshVertexNeighbors")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeSetShadeSmooth")
+
+class NODE_MT_category_PRIMITIVES_MESH(Menu):
+ bl_idname = "NODE_MT_category_PRIMITIVES_MESH"
+ bl_label = "Mesh Primitives"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshCircle")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshCone")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshCube")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshCylinder")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshGrid")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshIcoSphere")
+ node_add_menu.add_node_type(layout, "GeometryNodeMeshLine")
+
+class NODE_MT_category_GEO_OUTPUT(Menu):
+ bl_idname = "NODE_MT_category_GEO_OUTPUT"
+ bl_label = "Output"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeViewer")
+
+class NODE_MT_category_GEO_POINT(Menu):
+ bl_idname = "NODE_MT_category_GEO_POINT"
+ bl_label = "Point"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsInVolume")
+ node_add_menu.add_node_type(layout, "GeometryNodeDistributePointsOnFaces")
+ node_add_menu.add_node_type(layout, "GeometryNodePoints")
+ node_add_menu.add_node_type(layout, "GeometryNodePointsToVertices")
+ node_add_menu.add_node_type(layout, "GeometryNodePointsToVolume")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "GeometryNodeSetPointRadius")
+
+class NODE_MT_category_GEO_TEXT(Menu):
+ bl_idname = "NODE_MT_category_GEO_TEXT"
+ bl_label = "Text"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "FunctionNodeSliceString")
+ node_add_menu.add_node_type(layout, "GeometryNodeStringJoin")
+ node_add_menu.add_node_type(layout, "FunctionNodeStringLength")
+ node_add_menu.add_node_type(layout, "FunctionNodeReplaceString")
+ node_add_menu.add_node_type(layout, "FunctionNodeValueToString")
+ node_add_menu.add_node_type(layout, "GeometryNodeStringToCurves")
+ layout.separator()
+ node_add_menu.add_node_type(layout, "FunctionNodeInputSpecialCharacters")
+
+class NODE_MT_category_GEO_TEXTURE(Menu):
+ bl_idname = "NODE_MT_category_GEO_TEXTURE"
+ bl_label = "Texture"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "ShaderNodeTexBrick")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexChecker")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexGradient")
+ node_add_menu.add_node_type(layout, "GeometryNodeImageTexture")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexMagic")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexMusgrave")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexNoise")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexVoronoi")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexWave")
+ node_add_menu.add_node_type(layout, "ShaderNodeTexWhiteNoise")
+
+class NODE_MT_category_GEO_UTILITIES(Menu):
+ bl_idname = "NODE_MT_category_GEO_UTILITIES"
+ bl_label = "Utilities"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeAccumulateField")
+ node_add_menu.add_node_type(layout, "GeometryNodeFieldAtIndex")
+ node_add_menu.add_node_type(layout, "GeometryNodeFieldOnDomain")
+ node_add_menu.add_node_type(layout, "ShaderNodeMapRange")
+ node_add_menu.add_node_type(layout, "ShaderNodeFloatCurve")
+ node_add_menu.add_node_type(layout, "ShaderNodeClamp")
+ node_add_menu.add_node_type(layout, "ShaderNodeMath")
+ node_add_menu.add_node_type(layout, "FunctionNodeBooleanMath")
+ node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler")
+ node_add_menu.add_node_type(layout, "FunctionNodeCompare")
+ node_add_menu.add_node_type(layout, "ShaderNodeMix")
+ node_add_menu.add_node_type(layout, "FunctionNodeFloatToInt")
+ node_add_menu.add_node_type(layout, "GeometryNodeSwitch")
+ node_add_menu.add_node_type(layout, "FunctionNodeRandomValue")
+ node_add_menu.add_node_type(layout, "FunctionNodeAlignEulerToVector")
+
+class NODE_MT_category_GEO_UV(Menu):
+ bl_idname = "NODE_MT_category_GEO_UV"
+ bl_label = "UV"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeUVPackIslands")
+ node_add_menu.add_node_type(layout, "GeometryNodeUVUnwrap")
+
+class NODE_MT_category_GEO_VECTOR(Menu):
+ bl_idname = "NODE_MT_category_GEO_VECTOR"
+ bl_label = "Vector"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "ShaderNodeCombineXYZ")
+ node_add_menu.add_node_type(layout, "ShaderNodeSeparateXYZ")
+ node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve")
+ node_add_menu.add_node_type(layout, "ShaderNodeVectorMath")
+ node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate")
+
+class NODE_MT_category_GEO_VOLUME(Menu):
+ bl_idname = "NODE_MT_category_GEO_VOLUME"
+ bl_label = "Volume"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "GeometryNodeVolumeCube")
+ node_add_menu.add_node_type(layout, "GeometryNodeVolumeToMesh")
+
+class NODE_MT_category_GEO_GROUP(Menu):
+ bl_idname = "NODE_MT_category_GEO_GROUP"
+ bl_label = "Group"
+
+ def draw(self, context):
+ layout = self.layout
+ node_add_menu.draw_node_group_add_menu(context, layout)
+
+class NODE_MT_category_GEO_LAYOUT(Menu):
+ bl_idname = "NODE_MT_category_GEO_LAYOUT"
+ bl_label = "Layout"
+
+ def draw(self, _context):
+ layout = self.layout
+ node_add_menu.add_node_type(layout, "NodeFrame")
+ node_add_menu.add_node_type(layout, "NodeReroute")
+
+class NODE_MT_geometry_node_add_all(Menu):
+ bl_idname = "NODE_MT_geometry_node_add_all"
+ bl_label = ""
+
+ def draw(self, _context):
+ layout = self.layout
+ layout.menu("NODE_MT_geometry_node_GEO_ATTRIBUTE")
+ layout.menu("NODE_MT_geometry_node_GEO_COLOR")
+ layout.menu("NODE_MT_geometry_node_GEO_CURVE")
+ layout.menu("NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE")
+ layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY")
+ layout.menu("NODE_MT_geometry_node_GEO_INPUT")
+ layout.menu("NODE_MT_geometry_node_GEO_INSTANCE")
+ layout.menu("NODE_MT_geometry_node_GEO_MATERIAL")
+ layout.menu("NODE_MT_geometry_node_GEO_MESH")
+ layout.menu("NODE_MT_category_PRIMITIVES_MESH")
+ layout.menu("NODE_MT_category_GEO_OUTPUT")
+ layout.menu("NODE_MT_category_GEO_POINT")
+ layout.menu("NODE_MT_category_GEO_TEXT")
+ layout.menu("NODE_MT_category_GEO_TEXTURE")
+ layout.menu("NODE_MT_category_GEO_UTILITIES")
+ layout.menu("NODE_MT_category_GEO_UV")
+ layout.menu("NODE_MT_category_GEO_VECTOR")
+ layout.menu("NODE_MT_category_GEO_VOLUME")
+ layout.menu("NODE_MT_category_GEO_GROUP")
+ layout.menu("NODE_MT_category_GEO_LAYOUT")
+
+
+classes = (
+ NODE_MT_geometry_node_add_all,
+ NODE_MT_geometry_node_GEO_ATTRIBUTE,
+ NODE_MT_geometry_node_GEO_COLOR,
+ NODE_MT_geometry_node_GEO_CURVE,
+ NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE,
+ NODE_MT_geometry_node_GEO_GEOMETRY,
+ NODE_MT_geometry_node_GEO_INPUT,
+ NODE_MT_geometry_node_GEO_INSTANCE,
+ NODE_MT_geometry_node_GEO_MATERIAL,
+ NODE_MT_geometry_node_GEO_MESH,
+ NODE_MT_category_PRIMITIVES_MESH,
+ NODE_MT_category_GEO_OUTPUT,
+ NODE_MT_category_GEO_POINT,
+ NODE_MT_category_GEO_TEXT,
+ NODE_MT_category_GEO_TEXTURE,
+ NODE_MT_category_GEO_UTILITIES,
+ NODE_MT_category_GEO_UV,
+ NODE_MT_category_GEO_VECTOR,
+ NODE_MT_category_GEO_VOLUME,
+ NODE_MT_category_GEO_GROUP,
+ NODE_MT_category_GEO_LAYOUT,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 118928ef9c6..f4070a8289d 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -219,10 +219,14 @@ class NODE_MT_add(bpy.types.Menu):
import nodeitems_utils
layout = self.layout
-
layout.operator_context = 'INVOKE_DEFAULT'
- if nodeitems_utils.has_node_categories(context):
+ snode = context.space_data
+ if snode.tree_type == 'GeometryNodeTree':
+ props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
+ layout.separator()
+ layout.menu_contents("NODE_MT_geometry_node_add_all")
+ elif nodeitems_utils.has_node_categories(context):
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
props.use_transform = True
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 38629c18ca0..798ac9e37a5 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -39,14 +39,6 @@ class TextureNodeCategory(SortedNodeCategory):
return (context.space_data.type == 'NODE_EDITOR' and
context.space_data.tree_type == 'TextureNodeTree')
-
-class GeometryNodeCategory(SortedNodeCategory):
- @classmethod
- def poll(cls, context):
- return (context.space_data.type == 'NODE_EDITOR' and
- context.space_data.tree_type == 'GeometryNodeTree')
-
-
# menu entry for node group tools
def group_tools_draw(_self, layout, _context):
layout.operator("node.group_make")
@@ -63,198 +55,6 @@ node_tree_group_type = {
}
-# Custom Menu for Geometry Node Curves.
-def curve_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeCurveLength")
- yield NodeItem("GeometryNodeCurveToMesh")
- yield NodeItem("GeometryNodeCurveToPoints")
- yield NodeItem("GeometryNodeDeformCurvesOnSurface")
- yield NodeItem("GeometryNodeFillCurve")
- yield NodeItem("GeometryNodeFilletCurve")
- yield NodeItem("GeometryNodeResampleCurve")
- yield NodeItem("GeometryNodeReverseCurve")
- yield NodeItem("GeometryNodeSampleCurve")
- yield NodeItem("GeometryNodeSubdivideCurve")
- yield NodeItem("GeometryNodeTrimCurve")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeInputControlPointNeighbors")
- yield NodeItem("GeometryNodeInputCurveHandlePositions")
- yield NodeItem("GeometryNodeInputTangent")
- yield NodeItem("GeometryNodeInputCurveTilt")
- yield NodeItem("GeometryNodeCurveEndpointSelection")
- yield NodeItem("GeometryNodeCurveHandleTypeSelection")
- yield NodeItem("GeometryNodeInputSplineCyclic")
- yield NodeItem("GeometryNodeSplineLength")
- yield NodeItem("GeometryNodeSplineParameter")
- yield NodeItem("GeometryNodeInputSplineResolution")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeSetCurveRadius")
- yield NodeItem("GeometryNodeSetCurveTilt")
- yield NodeItem("GeometryNodeSetCurveHandlePositions")
- yield NodeItem("GeometryNodeCurveSetHandles")
- yield NodeItem("GeometryNodeSetSplineCyclic")
- yield NodeItem("GeometryNodeSetSplineResolution")
- yield NodeItem("GeometryNodeCurveSplineType")
-
-
-# Custom Menu for Geometry Node Mesh.
-def mesh_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeDualMesh")
- yield NodeItem("GeometryNodeEdgePathsToCurves")
- yield NodeItem("GeometryNodeEdgePathsToSelection")
- yield NodeItem("GeometryNodeExtrudeMesh")
- yield NodeItem("GeometryNodeFlipFaces")
- yield NodeItem("GeometryNodeMeshBoolean")
- yield NodeItem("GeometryNodeMeshToCurve")
- yield NodeItem("GeometryNodeMeshToPoints")
- yield NodeItem("GeometryNodeMeshToVolume")
- yield NodeItem("GeometryNodeSampleNearestSurface")
- yield NodeItem("GeometryNodeScaleElements")
- yield NodeItem("GeometryNodeSplitEdges")
- yield NodeItem("GeometryNodeSubdivideMesh")
- yield NodeItem("GeometryNodeSubdivisionSurface")
- yield NodeItem("GeometryNodeTriangulate")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeInputMeshEdgeAngle")
- yield NodeItem("GeometryNodeInputMeshEdgeNeighbors")
- yield NodeItem("GeometryNodeInputMeshEdgeVertices")
- yield NodeItem("GeometryNodeInputMeshFaceArea")
- yield NodeItem("GeometryNodeInputMeshFaceNeighbors")
- yield NodeItem("GeometryNodeMeshFaceSetBoundaries")
- yield NodeItem("GeometryNodeInputMeshFaceIsPlanar")
- yield NodeItem("GeometryNodeInputShadeSmooth")
- yield NodeItem("GeometryNodeInputMeshIsland")
- yield NodeItem("GeometryNodeInputShortestEdgePaths")
- yield NodeItem("GeometryNodeInputMeshVertexNeighbors")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeSetShadeSmooth")
-
-
-# Custom Menu for Geometry Nodes "Geometry" category.
-def geometry_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeBoundBox")
- yield NodeItem("GeometryNodeConvexHull")
- yield NodeItem("GeometryNodeDeleteGeometry")
- yield NodeItem("GeometryNodeDuplicateElements")
- yield NodeItem("GeometryNodeProximity")
- yield NodeItem("GeometryNodeGeometryToInstance")
- yield NodeItem("GeometryNodeJoinGeometry")
- yield NodeItem("GeometryNodeMergeByDistance")
- yield NodeItem("GeometryNodeRaycast")
- yield NodeItem("GeometryNodeSampleIndex")
- yield NodeItem("GeometryNodeSampleNearest")
- yield NodeItem("GeometryNodeSeparateComponents")
- yield NodeItem("GeometryNodeSeparateGeometry")
- yield NodeItem("GeometryNodeTransform")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeSetID")
- yield NodeItem("GeometryNodeSetPosition")
-
-
-# Custom Menu for UV Nodes.
-def uv_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeUVPackIslands")
- yield NodeItem("GeometryNodeUVUnwrap")
-
-
-# Custom Menu for Geometry Node Input Nodes.
-def geometry_input_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("FunctionNodeInputBool")
- yield NodeItem("GeometryNodeCollectionInfo")
- yield NodeItem("FunctionNodeInputColor")
- yield NodeItem("FunctionNodeInputInt")
- yield NodeItem("GeometryNodeIsViewport")
- yield NodeItem("GeometryNodeInputMaterial")
- yield NodeItem("GeometryNodeObjectInfo")
- yield NodeItem("FunctionNodeInputString")
- yield NodeItem("ShaderNodeValue")
- yield NodeItem("FunctionNodeInputVector")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeInputID")
- yield NodeItem("GeometryNodeInputIndex")
- yield NodeItem("GeometryNodeInputNamedAttribute")
- yield NodeItem("GeometryNodeInputNormal")
- yield NodeItem("GeometryNodeInputPosition")
- yield NodeItem("GeometryNodeInputRadius")
- yield NodeItem("GeometryNodeInputSceneTime")
-
-
-# Custom Menu for Geometry Node Instance Nodes.
-def geometry_instance_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeInstanceOnPoints")
- yield NodeItem("GeometryNodeInstancesToPoints")
- yield NodeItem("GeometryNodeRealizeInstances")
- yield NodeItem("GeometryNodeRotateInstances")
- yield NodeItem("GeometryNodeScaleInstances")
- yield NodeItem("GeometryNodeTranslateInstances")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeInputInstanceRotation")
- yield NodeItem("GeometryNodeInputInstanceScale")
-
-
-# Custom Menu for Material Nodes.
-def geometry_material_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeReplaceMaterial")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeInputMaterialIndex")
- yield NodeItem("GeometryNodeMaterialSelection")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeSetMaterial")
- yield NodeItem("GeometryNodeSetMaterialIndex")
-
-
-# Custom Menu for Geometry Node Points.
-def point_node_items(context):
- if context is None:
- return
- space = context.space_data
- if not space:
- return
- yield NodeItem("GeometryNodeDistributePointsInVolume")
- yield NodeItem("GeometryNodeDistributePointsOnFaces")
- yield NodeItem("GeometryNodePoints")
- yield NodeItem("GeometryNodePointsToVertices")
- yield NodeItem("GeometryNodePointsToVolume")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
- yield NodeItem("GeometryNodeSetPointRadius")
-
-
# Generic node group items generator for shader, compositor, geometry and texture node groups.
def node_group_items(context):
if context is None:
@@ -648,122 +448,17 @@ texture_node_categories = [
]),
]
-geometry_node_categories = [
- # Geometry Nodes
- GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
- NodeItem("GeometryNodeCaptureAttribute"),
- NodeItem("GeometryNodeAttributeDomainSize"),
- NodeItem("GeometryNodeAttributeStatistic"),
- NodeItem("GeometryNodeRemoveAttribute"),
- NodeItem("GeometryNodeStoreNamedAttribute"),
- ]),
- GeometryNodeCategory("GEO_COLOR", "Color", items=[
- NodeItem("ShaderNodeMix", label="Mix Color", settings={"data_type": "'RGBA'"}),
- NodeItem("ShaderNodeRGBCurve"),
- NodeItem("ShaderNodeValToRGB"),
- NodeItem("FunctionNodeSeparateColor"),
- NodeItem("FunctionNodeCombineColor"),
- ]),
- GeometryNodeCategory("GEO_CURVE", "Curve", items=curve_node_items),
- GeometryNodeCategory("GEO_PRIMITIVES_CURVE", "Curve Primitives", items=[
- NodeItem("GeometryNodeCurvePrimitiveLine"),
- NodeItem("GeometryNodeCurvePrimitiveCircle"),
- NodeItem("GeometryNodeCurveStar"),
- NodeItem("GeometryNodeCurveSpiral"),
- NodeItem("GeometryNodeCurveArc"),
- NodeItem("GeometryNodeCurveQuadraticBezier"),
- NodeItem("GeometryNodeCurvePrimitiveQuadrilateral"),
- NodeItem("GeometryNodeCurvePrimitiveBezierSegment"),
- ]),
- GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=geometry_node_items),
- GeometryNodeCategory("GEO_INPUT", "Input", items=geometry_input_node_items),
- GeometryNodeCategory("GEO_INSTANCE", "Instances", items=geometry_instance_node_items),
- GeometryNodeCategory("GEO_MATERIAL", "Material", items=geometry_material_node_items),
- GeometryNodeCategory("GEO_MESH", "Mesh", items=mesh_node_items),
- GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[
- NodeItem("GeometryNodeMeshCircle"),
- NodeItem("GeometryNodeMeshCone"),
- NodeItem("GeometryNodeMeshCube"),
- NodeItem("GeometryNodeMeshCylinder"),
- NodeItem("GeometryNodeMeshGrid"),
- NodeItem("GeometryNodeMeshIcoSphere"),
- NodeItem("GeometryNodeMeshLine"),
- NodeItem("GeometryNodeMeshUVSphere"),
- ]),
- GeometryNodeCategory("GEO_OUTPUT", "Output", items=[
- NodeItem("GeometryNodeViewer"),
- ]),
- GeometryNodeCategory("GEO_POINT", "Point", items=point_node_items),
- GeometryNodeCategory("GEO_TEXT", "Text", items=[
- NodeItem("FunctionNodeStringLength"),
- NodeItem("FunctionNodeSliceString"),
- NodeItem("FunctionNodeValueToString"),
- NodeItem("GeometryNodeStringJoin"),
- NodeItem("FunctionNodeInputSpecialCharacters"),
- NodeItem("GeometryNodeStringToCurves"),
- NodeItem("FunctionNodeReplaceString"),
- ]),
- GeometryNodeCategory("GEO_TEXTURE", "Texture", items=[
- NodeItem("ShaderNodeTexBrick"),
- NodeItem("ShaderNodeTexChecker"),
- NodeItem("ShaderNodeTexGradient"),
- NodeItem("ShaderNodeTexMagic"),
- NodeItem("ShaderNodeTexMusgrave"),
- NodeItem("ShaderNodeTexNoise"),
- NodeItem("ShaderNodeTexVoronoi"),
- NodeItem("ShaderNodeTexWave"),
- NodeItem("ShaderNodeTexWhiteNoise"),
- NodeItem("GeometryNodeImageTexture"),
- ]),
- GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
- NodeItem("GeometryNodeAccumulateField"),
- NodeItem("GeometryNodeFieldAtIndex"),
- NodeItem("GeometryNodeFieldOnDomain"),
- NodeItem("ShaderNodeMapRange"),
- NodeItem("ShaderNodeFloatCurve"),
- NodeItem("ShaderNodeClamp"),
- NodeItem("ShaderNodeMath"),
- NodeItem("FunctionNodeBooleanMath"),
- NodeItem("FunctionNodeRotateEuler"),
- NodeItem("FunctionNodeCompare"),
- NodeItem("ShaderNodeMix"),
- NodeItem("FunctionNodeFloatToInt"),
- NodeItem("GeometryNodeSwitch"),
- NodeItem("FunctionNodeRandomValue"),
- NodeItem("FunctionNodeAlignEulerToVector"),
- ]),
- GeometryNodeCategory("GEO_UV", "UV", items=uv_node_items),
- GeometryNodeCategory("GEO_VECTOR", "Vector", items=[
- NodeItem("ShaderNodeVectorCurve"),
- NodeItem("ShaderNodeSeparateXYZ"),
- NodeItem("ShaderNodeCombineXYZ"),
- NodeItem("ShaderNodeVectorMath"),
- NodeItem("ShaderNodeVectorRotate"),
- ]),
- GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
- NodeItem("GeometryNodeVolumeCube"),
- NodeItem("GeometryNodeVolumeToMesh"),
- ]),
- GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
- GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
- NodeItem("NodeFrame"),
- NodeItem("NodeReroute"),
- ]),
-]
-
def register():
nodeitems_utils.register_node_categories('SHADER', shader_node_categories)
nodeitems_utils.register_node_categories('COMPOSITING', compositor_node_categories)
nodeitems_utils.register_node_categories('TEXTURE', texture_node_categories)
- nodeitems_utils.register_node_categories('GEOMETRY', geometry_node_categories)
def unregister():
nodeitems_utils.unregister_node_categories('SHADER')
nodeitems_utils.unregister_node_categories('COMPOSITING')
nodeitems_utils.unregister_node_categories('TEXTURE')
- nodeitems_utils.unregister_node_categories('GEOMETRY')
if __name__ == "__main__":