python api docs & examples for registrable Menu/Panel/Operator/PropertyGroup classes.

This commit is contained in:
2011-02-18 08:47:37 +00:00
parent c4d7bb80f5
commit 063a7f217b
18 changed files with 473 additions and 17 deletions

View File

@@ -0,0 +1,22 @@
"""
Execution Context
+++++++++++++++++
When calling an operator you may want to pass the execution context.
This determines the context thats given to the operator to run in, and weather
invoke() is called or execute().
'EXEC_DEFAULT' is used by default but you may want the operator to take user
interaction with 'INVOKE_DEFAULT'.
The execution context is as a non keyword, string argument in:
('INVOKE_DEFAULT', 'INVOKE_REGION_WIN', 'INVOKE_REGION_CHANNELS',
'INVOKE_REGION_PREVIEW', 'INVOKE_AREA', 'INVOKE_SCREEN', 'EXEC_DEFAULT',
'EXEC_REGION_WIN', 'EXEC_REGION_CHANNELS', 'EXEC_REGION_PREVIEW', 'EXEC_AREA',
'EXEC_SCREEN')
"""
# group add popup
import bpy
bpy.ops.object.group_instance_add('INVOKE_DEFAULT')

View File

@@ -0,0 +1,30 @@
"""
Calling Operators
+++++++++++++++++
Provides python access to calling operators, this includes operators written in
C, Python or Macros.
Only keyword arguments can be used to pass operator properties.
Operators don't have return values as you might expect, instead they return a
set() which is made up of: {'RUNNING_MODAL', 'CANCELLED', 'FINISHED',
'PASS_THROUGH'}.
Common return values are {'FINISHED'} and {'CANCELLED'}.
Calling an operator in the wrong context will raise a RuntimeError,
there is a poll() method to avoid this problem.
Note that the operator ID (bl_idname) in this example is 'mesh.subdivide',
'bpy.ops' is just the access path for python.
"""
import bpy
# calling an operator
bpy.ops.mesh.subdivide(number_cuts=3, smoothness=0.5)
# check poll() to avoid exception.
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set(mode='EDIT')

View File

@@ -0,0 +1,37 @@
"""
Submenus
++++++++
This menu demonstrates some different functions.
"""
import bpy
class SubMenu(bpy.types.Menu):
bl_idname = "OBJECT_MT_select_submenu"
bl_label = "Select"
def draw(self, context):
layout = self.layout
layout.operator("object.select_all", text="Select/Deselect All")
layout.operator("object.select_inverse", text="Inverse")
layout.operator("object.select_random", text="Random")
# access this operator as a submenu
layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...")
layout.separator()
# expand each operator option into this menu
layout.operator_enum("object.lamp_add", "type")
layout.separator()
# use existing memu
layout.menu("VIEW3D_MT_transform")
bpy.utils.register_class(SubMenu)
# test call to display immediately.
bpy.ops.wm.call_menu(name="OBJECT_MT_select_submenu")

View File

@@ -0,0 +1,16 @@
"""
Extending Menus
+++++++++++++++
When creating menus for addons you can't reference menus in blenders default
scripts.
Instead the addon can add menu items to existing menus.
The function menu_draw acts like Menu.draw
"""
import bpy
def menu_draw(self, context):
self.layout.operator("wm.save_homefile")
bpy.types.INFO_MT_file.append(menu_draw)

View File

@@ -0,0 +1,32 @@
"""
Basic Menu Example
++++++++++++++++++
This script is a simple menu, menus differ from panels in that they must
reference from a header, panel or another menu.
Notice the 'CATEGORY_MT_name' :class:`Menu.bl_idname`, this is a naming
convention for menus.
.. note::
Menu subclasses must be registered before referencing them from blender.
"""
import bpy
class BasicMenu(bpy.types.Menu):
bl_idname = "OBJECT_MT_select_test"
bl_label = "Select"
def draw(self, context):
layout = self.layout
layout.operator("object.select_all", text="Select/Deselect All")
layout.operator("object.select_inverse", text="Inverse")
layout.operator("object.select_random", text="Random")
bpy.utils.register_class(BasicMenu)
# test call to display immediately.
bpy.ops.wm.call_menu(name="OBJECT_MT_select_test")

View File

@@ -1,6 +1,13 @@
"""
Invoke Function
+++++++++++++++
:class:`Operator.invoke` is used to initialize the operator from the context
at the moment the operator is called.
invoke() is typically used to assign properties which are then used by
execute().
Some operators don't have an execute() function, removing the ability to be
repeated from a script or macro.
This example shows how to define an operator which gets mouse input to
execute a function and that this operator can be invoked or executed from
the python api.
@@ -14,7 +21,9 @@ import bpy
class SimpleMouseOperator(bpy.types.Operator):
"""This operator shows the mouse location, this string is used for the tooltip and API docs"""
""" This operator shows the mouse location,
this string is used for the tooltip and API docs
"""
bl_idname = "wm.mouse_position"
bl_label = "Invoke Mouse Operator"

View File

@@ -1,7 +1,17 @@
"""
Calling a File Selector
+++++++++++++++++++++++
This example shows how an operator can use the file selector
This example shows how an operator can use the file selector.
Notice the invoke function calls a window manager method and returns
RUNNING_MODAL, this means the file selector stays open and the operator does not
exit immediately after invoke finishes.
The file selector runs the operator, calling :class:`Operator.execute` when the
user confirms.
The :class:`Operator.poll` function is optional, used to check if the operator
can run.
"""
import bpy
@@ -13,9 +23,13 @@ class ExportSomeData(bpy.types.Operator):
filepath = bpy.props.StringProperty(subtype="FILE_PATH")
@classmethod
def poll(cls, context):
return context.object is not None
def execute(self, context):
file = open(self.filepath, 'w')
file.write("Hello World")
file.write("Hello World " + context.object.name)
return {'FINISHED'}
def invoke(self, context, event):

View File

@@ -0,0 +1,31 @@
"""
Dialog Box
++++++++++
This operator uses its :class:`Operator.invoke` function to call a popup.
"""
import bpy
class DialogOperator(bpy.types.Operator):
bl_idname = "object.modal_operator"
bl_label = "Simple Modal Operator"
my_float = bpy.props.FloatProperty(name="Some Floating Point")
my_bool = bpy.props.BoolProperty(name="Toggle Option")
my_string = bpy.props.StringProperty(name="String Value")
def execute(self, context):
message = "Popup Values: %f, %d, '%s'" % \
(self.my_float, self.my_bool, self.my_string)
self.report({'INFO'}, message)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
bpy.utils.register_class(DialogOperator)
# test call
bpy.ops.object.modal_operator('INVOKE_DEFAULT')

View File

@@ -0,0 +1,46 @@
"""
Custom Drawing
++++++++++++++
By default operator properties use an automatic user interface layout.
If you need more control you can create your own layout with a
:class:`Operator.draw` function.
This works like the :class:`Panel` and :class:`Menu` draw functions, its used
for dialogs and file selectors.
"""
import bpy
class CustomDrawOperator(bpy.types.Operator):
bl_idname = "object.custom_draw"
bl_label = "Simple Modal Operator"
filepath = bpy.props.StringProperty(subtype="FILE_PATH")
my_float = bpy.props.FloatProperty(name="Float")
my_bool = bpy.props.BoolProperty(name="Toggle Option")
my_string = bpy.props.StringProperty(name="String Value")
def execute(self, context):
print()
return {'FINISHED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def draw(self, context):
layout = self.layout
col = layout.column()
col.label(text="Custom Interface!")
row = col.row()
row.prop(self, "my_float")
row.prop(self, "my_bool")
col.prop(self, "my_string")
bpy.utils.register_class(CustomDrawOperator)
# test call
bpy.ops.object.custom_draw('INVOKE_DEFAULT')

View File

@@ -0,0 +1,58 @@
"""
Modal Execution
+++++++++++++++
This operator defines a :class:`Operator.modal` function which running,
handling events until it returns {'FINISHED'} or {'CANCELLED'}.
Grab, Rotate, Scale and Fly-Mode are examples of modal operators.
They are especially useful for interactive tools,
your operator can have its own state where keys toggle options as the operator
runs.
:class:`Operator.invoke` is used to initialize the operator as being by
returning {'RUNNING_MODAL'}, initializing the modal loop.
Notice __init__() and __del__() are declared.
For other operator types they are not useful but for modal operators they will
be called before the :class:`Operator.invoke` and after the operator finishes.
"""
import bpy
class ModalOperator(bpy.types.Operator):
bl_idname = "object.modal_operator"
bl_label = "Simple Modal Operator"
def __init__(self):
print("Start")
def __del__(self):
print("End")
def execute(self, context):
context.object.location.x = self.value / 100.0
def modal(self, context, event):
if event.type == 'MOUSEMOVE': # Apply
self.value = event.mouse_x
self.execute(context)
elif event.type == 'LEFTMOUSE': # Confirm
return {'FINISHED'}
elif event.type in ('RIGHTMOUSE', 'ESC'): # Cancel
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
self.value = event.mouse_x
self.execute(context)
print(context.window_manager.modal_handler_add(self))
return {'RUNNING_MODAL'}
bpy.utils.register_class(ModalOperator)
# test call
bpy.ops.object.modal_operator('INVOKE_DEFAULT')

View File

@@ -1,7 +1,14 @@
"""
Basic Operator Example
++++++++++++++++++++++
This script is the most simple operator you can write that does something.
This script shows simple operator which prints a message.
Since the operator only has an :class:`Operator.execute` function it takes no
user input.
.. note::
Operator subclasses must be registered before accessing them from blender.
"""
import bpy

View File

@@ -0,0 +1,44 @@
"""
Simple Object Panel
+++++++++++++++++++
This panel has a :class:`Panel.poll` and :class:`Panel.draw_header` function,
even though the contents is basic this closely resemples blenders panels.
"""
import bpy
class ObjectSelectPanel(bpy.types.Panel):
bl_idname = "OBJECT_PT_select"
bl_label = "Select"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object is not None)
def draw_header(self, context):
layout = self.layout
obj = context.object
layout.prop(obj, "select", text="")
def draw(self, context):
layout = self.layout
obj = context.object
row = layout.row()
row.prop(obj, "hide_select")
row.prop(obj, "hide_render")
box = layout.box()
box.label("Selection Tools")
box.operator("object.select_all")
row = box.row()
row.operator("object.select_inverse")
row.operator("object.select_random")
bpy.utils.register_class(ObjectSelectPanel)

View File

@@ -0,0 +1,35 @@
"""
Mix-in Classes
++++++++++++++
A mix-in parent class can be used to share common properties and
:class:`Menu.poll` function.
"""
import bpy
class View3DPanel():
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
@classmethod
def poll(cls, context):
return (context.object is not None)
class PanelOne(View3DPanel, bpy.types.Panel):
bl_idname = "VIEW3D_PT_test_1"
bl_label = "Panel One"
def draw(self, context):
self.layout.label("Small Class")
class PanelTwo(View3DPanel, bpy.types.Panel):
bl_idname = "VIEW3D_PT_test_2"
bl_label = "Panel Two"
def draw(self, context):
self.layout.label("Also Small Class")
bpy.utils.register_class(PanelOne)
bpy.utils.register_class(PanelTwo)

View File

@@ -0,0 +1,28 @@
"""
Basic Panel Example
+++++++++++++++++++
This script is a simple panel which will draw into the object properties
section.
Notice the 'CATEGORY_PT_name' :class:`Panel.bl_idname`, this is a naming
convention for panels.
.. note::
Panel subclasses must be registered for blender to use them.
"""
import bpy
class HelloWorldPanel(bpy.types.Panel):
bl_idname = "OBJECT_PT_hello_world"
bl_label = "Hello World"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
def draw(self, context):
self.layout.label(text="Hello World")
bpy.utils.register_class(HelloWorldPanel)

View File

@@ -0,0 +1,40 @@
"""
Custom Properties
+++++++++++++++++
PropertyGroups are the base class for dynamically defined sets of properties.
They can be used to extend existing blender data with your own types which can
be animated, accessed from the user interface and from python.
.. note::
The values assigned to blender data are saved to disk but the class
definitions are not, this means whenever you load blender the class needs
to be registered too.
This is best done by creating an addon which loads on startup and registers
your properties.
.. note::
PropertyGroups must be registered before assigning them to blender data.
.. seealso::
Property types used in class declarations are all in :mod:`bpy.props`
"""
import bpy
class MyPropertyGroup(bpy.types.PropertyGroup):
custom_1 = bpy.props.FloatProperty(name="My Float")
custom_2 = bpy.props.IntProperty(name="My Int")
bpy.utils.register_class(MyPropertyGroup)
bpy.types.Object.my_properties = MyPropertyGroup
# test this worked
bpy.data.objects[0].my_properties.custom_1 = 22.0