diff options
Diffstat (limited to 'render_povray/__init__.py')
-rw-r--r-- | render_povray/__init__.py | 577 |
1 files changed, 568 insertions, 9 deletions
diff --git a/render_povray/__init__.py b/render_povray/__init__.py index 31b7671b..85c4e608 100644 --- a/render_povray/__init__.py +++ b/render_povray/__init__.py @@ -1,4 +1,4 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### +# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -19,7 +19,7 @@ # <pep8 compliant> bl_info = { - "name": "POV-Ray 3.7", + "name": "POVRAY-3.7", "author": "Campbell Barton, Silvio Falcinelli, Maurice Raybaud, " "Constantin Rahn, Bastien Montagne, Leonid Desyatkov", "version": (0, 0, 9), @@ -41,10 +41,12 @@ if "bpy" in locals(): else: import bpy import addon_utils # To use some other addons + import nodeitems_utils #for Nodes + from nodeitems_utils import NodeCategory, NodeItem #for Nodes from bpy.types import ( AddonPreferences, PropertyGroup, - Operator, + #Operator, ) from bpy.props import ( StringProperty, @@ -450,6 +452,548 @@ class RenderPovSettingsMaterial(PropertyGroup): default="") + + # NODES + + def use_material_nodes_callback(self, context): + if hasattr(context.space_data, "tree_type"): + context.space_data.tree_type = 'ObjectNodeTree' + mat=context.object.active_material + if mat.pov.material_use_nodes: + mat.use_nodes=True + tree = mat.node_tree + tree.name=mat.name + links = tree.links + default = True + if len(tree.nodes) == 2: + o = 0 + m = 0 + for node in tree.nodes: + if node.type in {"OUTPUT","MATERIAL"}: + tree.nodes.remove(node) + default = True + for node in tree.nodes: + if node.bl_idname == 'PovrayOutputNode': + o+=1 + if node.bl_idname == 'PovrayTextureNode': + m+=1 + if o == 1 and m == 1: + default = False + elif len(tree.nodes) == 0: + default = True + else: + default = False + if default: + output = tree.nodes.new('PovrayOutputNode') + output.location = 200,200 + tmap = tree.nodes.new('PovrayTextureNode') + tmap.location = 0,200 + links.new(tmap.outputs[0],output.inputs[0]) + tmap.select = True + tree.nodes.active = tmap + else: + mat.use_nodes=False + + + def use_texture_nodes_callback(self, context): + tex=context.object.active_material.active_texture + if tex.pov.texture_use_nodes: + tex.use_nodes=True + if len(tex.node_tree.nodes)==2: + for node in tex.node_tree.nodes: + if node.type in {"OUTPUT","CHECKER"}: + tex.node_tree.nodes.remove(node) + else: + tex.use_nodes=False + + def node_active_callback(self, context): + items = [] + mat=context.material + mat.node_tree.nodes + for node in mat.node_tree.nodes: + node.select=False + for node in mat.node_tree.nodes: + if node.name==mat.pov.material_active_node: + node.select=True + mat.node_tree.nodes.active=node + + return node + + def node_enum_callback(self, context): + items = [] + mat=context.material + nodes=mat.node_tree.nodes + for node in nodes: + items.append(("%s"%node.name,"%s"%node.name,"")) + return items + + def pigment_normal_callback(self, context): + render = context.scene.pov.render + items = [("pigment", "Pigment", ""),("normal", "Normal", "")] + if render == 'hgpovray': + items = [("pigment", "Pigment", ""),("normal", "Normal", ""),("modulation", "Modulation", "")] + return items + + def glow_callback(self, context): + scene = context.scene + ob = context.object + ob.pov.mesh_write_as_old = ob.pov.mesh_write_as + if scene.pov.render == 'uberpov' and ob.pov.glow: + ob.pov.mesh_write_as = 'NONE' + else: + ob.pov.mesh_write_as = ob.pov.mesh_write_as_old + + material_use_nodes = BoolProperty(name="Use nodes", description="", update=use_material_nodes_callback, default=False) + material_active_node = EnumProperty(name="Active node", description="", items=node_enum_callback, update=node_active_callback) + preview_settings = BoolProperty(name="Preview Settings", description="",default=False) + object_preview_transform = BoolProperty(name="Transform object", description="",default=False) + object_preview_scale = FloatProperty(name="XYZ", min=0.5, max=2.0, default=1.0) + object_preview_rotate = FloatVectorProperty(name="Rotate", description="", min=-180.0, max=180.0,default=(0.0,0.0,0.0), subtype='XYZ') + object_preview_bgcontrast = FloatProperty(name="Contrast", min=0.0, max=1.0, default=0.5) + + +############################################################################### +# Povray Nodes +############################################################################### +class PovraySocketUniversal(bpy.types.NodeSocket): + bl_idname = 'PovraySocketUniversal' + bl_label = 'Povray Socket' + value_unlimited = bpy.props.FloatProperty(default=0.0) + value_0_1 = bpy.props.FloatProperty(min=0.0,max=1.0,default=0.0) + value_0_10 = bpy.props.FloatProperty(min=0.0,max=10.0,default=0.0) + value_000001_10 = bpy.props.FloatProperty(min=0.000001,max=10.0,default=0.0) + value_1_9 = bpy.props.IntProperty(min=1,max=9,default=1) + value_0_255 = bpy.props.IntProperty(min=0,max=255,default=0) + percent = bpy.props.FloatProperty(min=0.0,max=100.0,default=0.0) + def draw(self, context, layout, node, text): + space = context.space_data + tree = space.edit_tree + links=tree.links + if self.is_linked: + value=[] + for link in links: + if link.from_node==node: + inps=link.to_node.inputs + for inp in inps: + if inp.bl_idname=="PovraySocketFloat_0_1" and inp.is_linked: + prop="value_0_1" + if prop not in value: + value.append(prop) + if inp.bl_idname=="PovraySocketFloat_000001_10" and inp.is_linked: + prop="value_000001_10" + if prop not in value: + value.append(prop) + if inp.bl_idname=="PovraySocketFloat_0_10" and inp.is_linked: + prop="value_0_10" + if prop not in value: + value.append(prop) + if inp.bl_idname=="PovraySocketInt_1_9" and inp.is_linked: + prop="value_1_9" + if prop not in value: + value.append(prop) + if inp.bl_idname=="PovraySocketInt_0_255" and inp.is_linked: + prop="value_0_255" + if prop not in value: + value.append(prop) + if inp.bl_idname=="PovraySocketFloatUnlimited" and inp.is_linked: + prop="value_unlimited" + if prop not in value: + value.append(prop) + if len(value)==1: + layout.prop(self, "%s"%value[0], text=text) + else: + layout.prop(self, "percent", text="Percent") + else: + layout.prop(self, "percent", text=text) + def draw_color(self, context, node): + return (1, 0, 0, 1) + +class PovraySocketFloat_0_1(bpy.types.NodeSocket): + bl_idname = 'PovraySocketFloat_0_1' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(description="Input node Value_0_1",min=0,max=1,default=0) + def draw(self, context, layout, node, text): + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text, slider=True) + + def draw_color(self, context, node): + return (0.5, 0.7, 0.7, 1) + +class PovraySocketFloat_0_10(bpy.types.NodeSocket): + bl_idname = 'PovraySocketFloat_0_10' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(description="Input node Value_0_10",min=0,max=10,default=0) + def draw(self, context, layout, node, text): + if node.bl_idname == 'ShaderNormalMapNode' and node.inputs[2].is_linked: + layout.label('') + self.hide_value=True + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text, slider=True) + def draw_color(self, context, node): + return (0.65, 0.65, 0.65, 1) + +class PovraySocketFloat_10(bpy.types.NodeSocket): + bl_idname = 'PovraySocketFloat_10' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(description="Input node Value_10",min=-10,max=10,default=0) + def draw(self, context, layout, node, text): + if node.bl_idname == 'ShaderNormalMapNode' and node.inputs[2].is_linked: + layout.label('') + self.hide_value=True + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text, slider=True) + def draw_color(self, context, node): + return (0.65, 0.65, 0.65, 1) + +class PovraySocketFloatPositive(bpy.types.NodeSocket): + bl_idname = 'PovraySocketFloatPositive' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(description="Input Node Value Positive", min=0.0, default=0) + def draw(self, context, layout, node, text): + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text, slider=True) + def draw_color(self, context, node): + return (0.045, 0.005, 0.136, 1) + +class PovraySocketFloat_000001_10(bpy.types.NodeSocket): + bl_idname = 'PovraySocketFloat_000001_10' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(min=0.000001,max=10,default=0.000001) + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text, slider=True) + def draw_color(self, context, node): + return (1, 0, 0, 1) + +class PovraySocketFloatUnlimited(bpy.types.NodeSocket): + bl_idname = 'PovraySocketFloatUnlimited' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(default = 0.0) + def draw(self, context, layout, node, text): + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text, slider=True) + def draw_color(self, context, node): + return (0.7, 0.7, 1, 1) + +class PovraySocketInt_1_9(bpy.types.NodeSocket): + bl_idname = 'PovraySocketInt_1_9' + bl_label = 'Povray Socket' + default_value = bpy.props.IntProperty(description="Input node Value_1_9",min=1,max=9,default=6) + def draw(self, context, layout, node, text): + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text) + def draw_color(self, context, node): + return (1, 0.7, 0.7, 1) + +class PovraySocketInt_0_256(bpy.types.NodeSocket): + bl_idname = 'PovraySocketInt_0_256' + bl_label = 'Povray Socket' + default_value = bpy.props.IntProperty(min=0,max=255,default=0) + def draw(self, context, layout, node, text): + if self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text) + def draw_color(self, context, node): + return (0.5, 0.5, 0.5, 1) + + +class PovraySocketPattern(bpy.types.NodeSocket): + bl_idname = 'PovraySocketPattern' + bl_label = 'Povray Socket' + + default_value = bpy.props.EnumProperty( + name="Pattern", + description="Select the pattern", + items=(('boxed', "Boxed", ""),('brick', "Brick", ""),('cells', "Cells", ""), ('checker', "Checker", ""), + ('granite', "Granite", ""),('leopard', "Leopard", ""),('marble', "Marble", ""), + ('onion', "Onion", ""),('planar', "Planar", ""), ('quilted', "Quilted", ""), + ('ripples', "Ripples", ""), ('radial', "Radial", ""),('spherical', "Spherical", ""), + ('spotted', "Spotted", ""), ('waves', "Waves", ""), ('wood', "Wood", ""), + ('wrinkles', "Wrinkles", "")), + default='granite') + + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label("Pattern") + else: + layout.prop(self, "default_value", text=text) + + def draw_color(self, context, node): + return (1, 1, 1, 1) + +class PovraySocketColor(bpy.types.NodeSocket): + bl_idname = 'PovraySocketColor' + bl_label = 'Povray Socket' + + default_value = bpy.props.FloatVectorProperty( + precision=4, step=0.01, min=0, soft_max=1, + default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR') + + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text) + + def draw_color(self, context, node): + return (1, 1, 0, 1) + +class PovraySocketColorRGBFT(bpy.types.NodeSocket): + bl_idname = 'PovraySocketColorRGBFT' + bl_label = 'Povray Socket' + + default_value = bpy.props.FloatVectorProperty( + precision=4, step=0.01, min=0, soft_max=1, + default=(0.0, 0.0, 0.0), options={'ANIMATABLE'}, subtype='COLOR') + f = bpy.props.FloatProperty(default = 0.0,min=0.0,max=1.0) + t = bpy.props.FloatProperty(default = 0.0,min=0.0,max=1.0) + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text) + else: + layout.prop(self, "default_value", text=text) + + def draw_color(self, context, node): + return (1, 1, 0, 1) + +class PovraySocketTexture(bpy.types.NodeSocket): + bl_idname = 'PovraySocketTexture' + bl_label = 'Povray Socket' + default_value = bpy.props.IntProperty() + def draw(self, context, layout, node, text): + layout.label(text) + + def draw_color(self, context, node): + return (0, 1, 0, 1) + + + +class PovraySocketTransform(bpy.types.NodeSocket): + bl_idname = 'PovraySocketTransform' + bl_label = 'Povray Socket' + default_value = bpy.props.IntProperty(min=0,max=255,default=0) + def draw(self, context, layout, node, text): + layout.label(text) + + def draw_color(self, context, node): + return (99/255, 99/255, 199/255, 1) + +class PovraySocketNormal(bpy.types.NodeSocket): + bl_idname = 'PovraySocketNormal' + bl_label = 'Povray Socket' + default_value = bpy.props.IntProperty(min=0,max=255,default=0) + def draw(self, context, layout, node, text): + layout.label(text) + + def draw_color(self, context, node): + return (0.65, 0.65, 0.65, 1) + +class PovraySocketSlope(bpy.types.NodeSocket): + bl_idname = 'PovraySocketSlope' + bl_label = 'Povray Socket' + default_value = bpy.props.FloatProperty(min = 0.0, max = 1.0) + height = bpy.props.FloatProperty(min = 0.0, max = 10.0) + slope = bpy.props.FloatProperty(min = -10.0, max = 10.0) + def draw(self, context, layout, node, text): + if self.is_output or self.is_linked: + layout.label(text) + else: + layout.prop(self,'default_value',text='') + layout.prop(self,'height',text='') + layout.prop(self,'slope',text='') + def draw_color(self, context, node): + return (0, 0, 0, 1) + +class PovraySocketMap(bpy.types.NodeSocket): + bl_idname = 'PovraySocketMap' + bl_label = 'Povray Socket' + default_value = bpy.props.StringProperty() + def draw(self, context, layout, node, text): + layout.label(text) + def draw_color(self, context, node): + return (0.2, 0, 0.2, 1) + +class PovrayShaderNodeCategory(NodeCategory): + @classmethod + def poll(cls, context): + return context.space_data.tree_type == 'ObjectNodeTree' + +class PovrayTextureNodeCategory(NodeCategory): + @classmethod + def poll(cls, context): + return context.space_data.tree_type == 'TextureNodeTree' + +class PovraySceneNodeCategory(NodeCategory): + @classmethod + def poll(cls, context): + return context.space_data.tree_type == 'CompositorNodeTree' + +node_categories = [ + + PovrayShaderNodeCategory("SHADEROUTPUT", "Output", items=[ + NodeItem("PovrayOutputNode"), + ]), + + PovrayShaderNodeCategory("SIMPLE", "Simple texture", items=[ + NodeItem("PovrayTextureNode"), + ]), + + PovrayShaderNodeCategory("MAPS", "Maps", items=[ + NodeItem("PovrayBumpMapNode"), + NodeItem("PovrayColorImageNode"), + NodeItem("ShaderNormalMapNode"), + NodeItem("PovraySlopeNode"), + NodeItem("ShaderTextureMapNode"), + NodeItem("ShaderNodeValToRGB"), + ]), + + PovrayShaderNodeCategory("OTHER", "Other patterns", items=[ + NodeItem("PovrayImagePatternNode"), + NodeItem("ShaderPatternNode"), + ]), + + PovrayShaderNodeCategory("COLOR", "Color", items=[ + NodeItem("PovrayPigmentNode"), + ]), + + PovrayShaderNodeCategory("TRANSFORM", "Transform", items=[ + NodeItem("PovrayMappingNode"), + NodeItem("PovrayMultiplyNode"), + NodeItem("PovrayModifierNode"), + NodeItem("PovrayTransformNode"), + NodeItem("PovrayValueNode"), + ]), + + PovrayShaderNodeCategory("FINISH", "Finish", items=[ + NodeItem("PovrayFinishNode"), + NodeItem("PovrayDiffuseNode"), + NodeItem("PovraySpecularNode"), + NodeItem("PovrayPhongNode"), + NodeItem("PovrayAmbientNode"), + NodeItem("PovrayMirrorNode"), + NodeItem("PovrayIridescenceNode"), + NodeItem("PovraySubsurfaceNode"), + ]), + + PovrayShaderNodeCategory("CYCLES", "Cycles", items=[ + NodeItem("ShaderNodeAddShader"), + NodeItem("ShaderNodeAmbientOcclusion"), + NodeItem("ShaderNodeAttribute"), + NodeItem("ShaderNodeBackground"), + NodeItem("ShaderNodeBlackbody"), + NodeItem("ShaderNodeBrightContrast"), + NodeItem("ShaderNodeBsdfAnisotropic"), + NodeItem("ShaderNodeBsdfDiffuse"), + NodeItem("ShaderNodeBsdfGlass"), + NodeItem("ShaderNodeBsdfGlossy"), + NodeItem("ShaderNodeBsdfHair"), + NodeItem("ShaderNodeBsdfRefraction"), + NodeItem("ShaderNodeBsdfToon"), + NodeItem("ShaderNodeBsdfTranslucent"), + NodeItem("ShaderNodeBsdfTransparent"), + NodeItem("ShaderNodeBsdfVelvet"), + NodeItem("ShaderNodeBump"), + NodeItem("ShaderNodeCameraData"), + NodeItem("ShaderNodeCombineHSV"), + NodeItem("ShaderNodeCombineRGB"), + NodeItem("ShaderNodeCombineXYZ"), + NodeItem("ShaderNodeEmission"), + NodeItem("ShaderNodeExtendedMaterial"), + NodeItem("ShaderNodeFresnel"), + NodeItem("ShaderNodeGamma"), + NodeItem("ShaderNodeGeometry"), + NodeItem("ShaderNodeGroup"), + NodeItem("ShaderNodeHairInfo"), + NodeItem("ShaderNodeHoldout"), + NodeItem("ShaderNodeHueSaturation"), + NodeItem("ShaderNodeInvert"), + NodeItem("ShaderNodeLampData"), + NodeItem("ShaderNodeLayerWeight"), + NodeItem("ShaderNodeLightFalloff"), + NodeItem("ShaderNodeLightPath"), + NodeItem("ShaderNodeMapping"), + NodeItem("ShaderNodeMaterial"), + NodeItem("ShaderNodeMath"), + NodeItem("ShaderNodeMixRGB"), + NodeItem("ShaderNodeMixShader"), + NodeItem("ShaderNodeNewGeometry"), + NodeItem("ShaderNodeNormal"), + NodeItem("ShaderNodeNormalMap"), + NodeItem("ShaderNodeObjectInfo"), + NodeItem("ShaderNodeOutput"), + NodeItem("ShaderNodeOutputLamp"), + NodeItem("ShaderNodeOutputLineStyle"), + NodeItem("ShaderNodeOutputMaterial"), + NodeItem("ShaderNodeOutputWorld"), + NodeItem("ShaderNodeParticleInfo"), + NodeItem("ShaderNodeRGB"), + NodeItem("ShaderNodeRGBCurve"), + NodeItem("ShaderNodeRGBToBW"), + NodeItem("ShaderNodeScript"), + NodeItem("ShaderNodeSeparateHSV"), + NodeItem("ShaderNodeSeparateRGB"), + NodeItem("ShaderNodeSeparateXYZ"), + NodeItem("ShaderNodeSqueeze"), + NodeItem("ShaderNodeSubsurfaceScattering"), + NodeItem("ShaderNodeTangent"), + NodeItem("ShaderNodeTexBrick"), + NodeItem("ShaderNodeTexChecker"), + NodeItem("ShaderNodeTexCoord"), + NodeItem("ShaderNodeTexEnvironment"), + NodeItem("ShaderNodeTexGradient"), + NodeItem("ShaderNodeTexImage"), + NodeItem("ShaderNodeTexMagic"), + NodeItem("ShaderNodeTexMusgrave"), + NodeItem("ShaderNodeTexNoise"), + NodeItem("ShaderNodeTexPointDensity"), + NodeItem("ShaderNodeTexSky"), + NodeItem("ShaderNodeTexVoronoi"), + NodeItem("ShaderNodeTexWave"), + NodeItem("ShaderNodeTexture"), + NodeItem("ShaderNodeUVAlongStroke"), + NodeItem("ShaderNodeUVMap"), + NodeItem("ShaderNodeValToRGB"), + NodeItem("ShaderNodeValue"), + NodeItem("ShaderNodeVectorCurve"), + NodeItem("ShaderNodeVectorMath"), + NodeItem("ShaderNodeVectorTransform"), + NodeItem("ShaderNodeVolumeAbsorption"), + NodeItem("ShaderNodeVolumeScatter"), + NodeItem("ShaderNodeWavelength"), + NodeItem("ShaderNodeWireframe"), + ]), + + PovrayTextureNodeCategory("TEXTUREOUTPUT", "Output", items=[ + NodeItem("TextureNodeValToRGB"), + NodeItem("TextureOutputNode"), + ]), + + PovraySceneNodeCategory("ISOSURFACE", "Isosurface", items=[ + NodeItem("IsoPropsNode"), + ]), + + PovraySceneNodeCategory("FOG", "Fog", items=[ + NodeItem("PovrayFogNode"), + + ]), + ] +############### end nodes + ############################################################################### # Texture POV properties. ############################################################################### @@ -1017,11 +1561,12 @@ class RenderPovSettingsObject(PropertyGroup): ("grid", "Grid", ""), ("mesh", "Mesh", "")), default="mesh") - # shape_as_light = StringProperty(name="Light",maxlen=1024) - # object_ior = FloatProperty( - # name="IOR", description="IOR", - # min=1.0, max=10.0,default=1.0) + object_ior = FloatProperty( + name="IOR", description="IOR", + min=1.0, max=10.0,default=1.0) + + # shape_as_light = StringProperty(name="Light",maxlen=1024) # fake_caustics_power = FloatProperty( # name="Power", description="Fake caustics power", # min=0.0, max=10.0,default=0.0) @@ -1482,7 +2027,16 @@ class PovrayPreferences(AddonPreferences): layout.prop(self, "branch_feature_set_povray") layout.prop(self, "filepath_povray") - + + + + + + + + + + def register(): bpy.utils.register_module(__name__) @@ -1492,6 +2046,9 @@ def register(): addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True) #bpy.types.TEXTURE_PT_context_texture.prepend(TEXTURE_PT_povray_type) + + bpy.types.NODE_HT_header.append(ui.menu_func_nodes) + nodeitems_utils.register_node_categories("POVRAYNODES", node_categories) bpy.types.Scene.pov = PointerProperty(type=RenderPovSettingsScene) bpy.types.Material.pov = PointerProperty(type=RenderPovSettingsMaterial) bpy.types.Texture.pov = PointerProperty(type=RenderPovSettingsTexture) @@ -1502,14 +2059,16 @@ def register(): def unregister(): - #bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_povray_type) del bpy.types.Scene.pov del bpy.types.Material.pov del bpy.types.Texture.pov del bpy.types.Object.pov del bpy.types.Camera.pov del bpy.types.Text.pov + nodeitems_utils.unregister_node_categories("POVRAYNODES") + bpy.types.NODE_HT_header.remove(ui.menu_func_nodes) + #bpy.types.TEXTURE_PT_context_texture.remove(TEXTURE_PT_povray_type) addon_utils.disable("add_mesh_extra_objects", default_set=False) bpy.types.INFO_MT_file_import.remove(ui.menu_func_import) bpy.types.INFO_MT_add.remove(ui.menu_func_add) |