1
$\begingroup$

I need to create buttons in a custom panel to run some simple commands in python. For example toggling subsurf on and off with this script:

if bpy.data.objects["Cube"].modifiers["Subsurf"].show_viewport:
        bpy.data.objects["Cube"].modifiers["Subsurf"].show_viewport = False
    else:
        bpy.data.objects["Cube"].modifiers["Subsurf"].show_viewport = True

I need to create a bunch of similar buttons to toggle different things about the mesh. For example toggle display wire on the object, shade smooth/flat etc.

Is there a more practical way to do this than creating a dozens of separate operators for each of these commands. And using layout operator?

layout.operator("my.toggle_subsurf", text="Toggle Subsurf", icon="MOD_SUBSURF")
$\endgroup$
1

1 Answer 1

3
$\begingroup$

Main concept is that Operators executing something based on given data (e.g. convert all polygons of object xy to triangles). Properties on the other hand can either store the actual 'state' of something (e.g. Wireframe ON/OFF) or any 'value' (e.g. Subdivisions=3 or Crease=0.0001).

In fact, Operators like OPS.object.delete() can be called because these are 'functions' (note the parentheses at the end). However, a Property like Object.wireframe just stores True or False so it can not be called (it's basically not a 'function').

Means that you have to write an Operator if you want to change/toggle any Property.


Another way which you might not think of, is expanding each property to make it look like a 'Button', which also gives instant feedback to the user whether the property is ON/OFF.

enter image description here

import bpy
from bpy.types import (Panel, Operator)

# ------------------------------------------------------------------------
#    Operators
# ------------------------------------------------------------------------

class SimpleOperator(Operator):
    """Print object name in Console"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"

    def execute(self, context):
        print (context.object)
        return {'FINISHED'}

# ------------------------------------------------------------------------
#    Panel in Object Mode
# ------------------------------------------------------------------------

class OBJECT_PT_CustomPanel(Panel):
    bl_idname = "object.custom_panel"
    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"   


    @classmethod
    def poll(self,context):
        return context.object is not None

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

        layout.label(text="Properties:")

        col = layout.column(align=True)
        row = col.row(align=True)
        row.prop(obj, "show_name", toggle=True, icon="FILE_FONT")
        row.prop(obj, "show_wire", toggle=True, text="Wireframe", icon="SHADING_WIRE")
        col.prop(obj, "show_all_edges", toggle=True, text="Show all Edges", icon="MOD_EDGESPLIT")
        layout.separator()

        layout.label(text="Operators:")

        col = layout.column(align=True)
        col.operator(SimpleOperator.bl_idname, text="Execute Something", icon="CONSOLE")
        col.operator(SimpleOperator.bl_idname, text="Execute Something Else", icon="CONSOLE")

        layout.separator()

# ------------------------------------------------------------------------
#    Registration
# ------------------------------------------------------------------------

def register():
    bpy.utils.register_class(OBJECT_PT_CustomPanel)
    bpy.utils.register_class(SimpleOperator)

def unregister():
    bpy.utils.unregister_class(OBJECT_PT_CustomPanel)
    bpy.utils.unregister_class(SimpleOperator)

if __name__ == "__main__":
    register()

You should definitely read: How to create a custom UI?

$\endgroup$

You must log in to answer this question.