From 063a7f217be43718a69f6cbcfcf322ca71bdeeb0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Feb 2011 08:47:37 +0000 Subject: python api docs & examples for registrable Menu/Panel/Operator/PropertyGroup classes. --- doc/python_api/examples/bpy.ops.1.py | 22 ++++++++ doc/python_api/examples/bpy.ops.py | 30 +++++++++++ doc/python_api/examples/bpy.types.Menu.1.py | 37 ++++++++++++++ doc/python_api/examples/bpy.types.Menu.2.py | 16 ++++++ doc/python_api/examples/bpy.types.Menu.py | 32 ++++++++++++ doc/python_api/examples/bpy.types.Operator.1.py | 11 +++- doc/python_api/examples/bpy.types.Operator.2.py | 18 ++++++- doc/python_api/examples/bpy.types.Operator.3.py | 31 ++++++++++++ doc/python_api/examples/bpy.types.Operator.4.py | 46 +++++++++++++++++ doc/python_api/examples/bpy.types.Operator.5.py | 58 ++++++++++++++++++++++ doc/python_api/examples/bpy.types.Operator.py | 9 +++- doc/python_api/examples/bpy.types.Panel.1.py | 44 ++++++++++++++++ doc/python_api/examples/bpy.types.Panel.2.py | 35 +++++++++++++ doc/python_api/examples/bpy.types.Panel.py | 28 +++++++++++ doc/python_api/examples/bpy.types.PropertyGroup.py | 40 +++++++++++++++ doc/python_api/sphinx_doc_gen.py | 29 +++++++---- 16 files changed, 471 insertions(+), 15 deletions(-) create mode 100644 doc/python_api/examples/bpy.ops.1.py create mode 100644 doc/python_api/examples/bpy.ops.py create mode 100644 doc/python_api/examples/bpy.types.Menu.1.py create mode 100644 doc/python_api/examples/bpy.types.Menu.2.py create mode 100644 doc/python_api/examples/bpy.types.Menu.py create mode 100644 doc/python_api/examples/bpy.types.Operator.3.py create mode 100644 doc/python_api/examples/bpy.types.Operator.4.py create mode 100644 doc/python_api/examples/bpy.types.Operator.5.py create mode 100644 doc/python_api/examples/bpy.types.Panel.1.py create mode 100644 doc/python_api/examples/bpy.types.Panel.2.py create mode 100644 doc/python_api/examples/bpy.types.Panel.py create mode 100644 doc/python_api/examples/bpy.types.PropertyGroup.py (limited to 'doc') diff --git a/doc/python_api/examples/bpy.ops.1.py b/doc/python_api/examples/bpy.ops.1.py new file mode 100644 index 00000000000..f43be2b0f63 --- /dev/null +++ b/doc/python_api/examples/bpy.ops.1.py @@ -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') diff --git a/doc/python_api/examples/bpy.ops.py b/doc/python_api/examples/bpy.ops.py new file mode 100644 index 00000000000..487d6039327 --- /dev/null +++ b/doc/python_api/examples/bpy.ops.py @@ -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') diff --git a/doc/python_api/examples/bpy.types.Menu.1.py b/doc/python_api/examples/bpy.types.Menu.1.py new file mode 100644 index 00000000000..fa23e2dcfd3 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Menu.1.py @@ -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") diff --git a/doc/python_api/examples/bpy.types.Menu.2.py b/doc/python_api/examples/bpy.types.Menu.2.py new file mode 100644 index 00000000000..4579dd6c485 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Menu.2.py @@ -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) diff --git a/doc/python_api/examples/bpy.types.Menu.py b/doc/python_api/examples/bpy.types.Menu.py new file mode 100644 index 00000000000..a6abba6bfad --- /dev/null +++ b/doc/python_api/examples/bpy.types.Menu.py @@ -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") diff --git a/doc/python_api/examples/bpy.types.Operator.1.py b/doc/python_api/examples/bpy.types.Operator.1.py index 03a3f6d70d6..133dc09af46 100644 --- a/doc/python_api/examples/bpy.types.Operator.1.py +++ b/doc/python_api/examples/bpy.types.Operator.1.py @@ -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" diff --git a/doc/python_api/examples/bpy.types.Operator.2.py b/doc/python_api/examples/bpy.types.Operator.2.py index 1673b22fbf1..54bd481b339 100644 --- a/doc/python_api/examples/bpy.types.Operator.2.py +++ b/doc/python_api/examples/bpy.types.Operator.2.py @@ -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): diff --git a/doc/python_api/examples/bpy.types.Operator.3.py b/doc/python_api/examples/bpy.types.Operator.3.py new file mode 100644 index 00000000000..887657bec7a --- /dev/null +++ b/doc/python_api/examples/bpy.types.Operator.3.py @@ -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') diff --git a/doc/python_api/examples/bpy.types.Operator.4.py b/doc/python_api/examples/bpy.types.Operator.4.py new file mode 100644 index 00000000000..4cb7b02fdc6 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Operator.4.py @@ -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') diff --git a/doc/python_api/examples/bpy.types.Operator.5.py b/doc/python_api/examples/bpy.types.Operator.5.py new file mode 100644 index 00000000000..fd09120d3b0 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Operator.5.py @@ -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') diff --git a/doc/python_api/examples/bpy.types.Operator.py b/doc/python_api/examples/bpy.types.Operator.py index 2efa99ce795..52edfa0a61b 100644 --- a/doc/python_api/examples/bpy.types.Operator.py +++ b/doc/python_api/examples/bpy.types.Operator.py @@ -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 diff --git a/doc/python_api/examples/bpy.types.Panel.1.py b/doc/python_api/examples/bpy.types.Panel.1.py new file mode 100644 index 00000000000..2fe476cff9c --- /dev/null +++ b/doc/python_api/examples/bpy.types.Panel.1.py @@ -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) \ No newline at end of file diff --git a/doc/python_api/examples/bpy.types.Panel.2.py b/doc/python_api/examples/bpy.types.Panel.2.py new file mode 100644 index 00000000000..661d7cba766 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Panel.2.py @@ -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) diff --git a/doc/python_api/examples/bpy.types.Panel.py b/doc/python_api/examples/bpy.types.Panel.py new file mode 100644 index 00000000000..210665b5a47 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Panel.py @@ -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) \ No newline at end of file diff --git a/doc/python_api/examples/bpy.types.PropertyGroup.py b/doc/python_api/examples/bpy.types.PropertyGroup.py new file mode 100644 index 00000000000..219cd28609c --- /dev/null +++ b/doc/python_api/examples/bpy.types.PropertyGroup.py @@ -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 diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 38218675484..5f9505a7ea3 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -61,9 +61,10 @@ else: "bpy.app", "bpy.path", "bpy.data", - "bpy.props", + # "bpy.props", "bpy.utils", - #"bpy.types", # supports filtering + "bpy.context", + # "bpy.types", # supports filtering "bpy.ops", # supports filtering "bge", "aud", @@ -73,8 +74,8 @@ else: "mathutils.geometry", ) - FILTER_BPY_TYPES = ("Operator", ) # allow - FILTER_BPY_OPS = ("import_scene", ) # allow + FILTER_BPY_TYPES = ("PropertyGroup", "Panel", "Menu", "Operator") # allow + FILTER_BPY_OPS = ("import.scene", ) # allow # for quick rebuilds """ @@ -156,19 +157,20 @@ def example_extract_docstring(filepath): def write_example_ref(ident, fw, example_id, ext="py"): if example_id in EXAMPLE_SET: - + # extract the comment filepath = "../examples/%s.%s" % (example_id, ext) filepath_full = os.path.join(os.path.dirname(fw.__self__.name), filepath) - + text, line_no = example_extract_docstring(filepath_full) - + for line in text.split("\n"): fw("%s\n" % (ident + line).rstrip()) fw("\n") fw("%s.. literalinclude:: %s\n" % (ident, filepath)) - fw("%s :lines: %d-\n" % (ident, line_no)) + if line_no > 0: + fw("%s :lines: %d-\n" % (ident, line_no)) fw("\n") EXAMPLE_SET_USED.add(example_id) else: @@ -563,6 +565,7 @@ def pyrna2sphinx(BASEPATH): fw(".. module:: bpy.types\n\n") + # docs first?, ok write_example_ref("", fw, "bpy.types.%s" % struct.identifier) base_ids = [base.identifier for base in struct.get_bases()] @@ -726,6 +729,9 @@ def pyrna2sphinx(BASEPATH): fw(" * :class:`%s`\n" % ref) fw("\n") + # docs last?, disable for now + # write_example_ref("", fw, "bpy.types.%s" % struct.identifier) + if "bpy.types" not in EXCLUDE_MODULES: for struct in structs.values(): # TODO, rna_info should filter these out! @@ -854,9 +860,10 @@ def rna2sphinx(BASEPATH): fw("\n") fw("This document is an API reference for Blender %s. built %s.\n" % (version_string, bpy.app.build_date)) fw("\n") - fw("An introduction to Blender and Python can be found at \n") + fw("| An introduction to Blender and Python can be found at `Quickstart Intro `_,\n") + fw("| For a more general explanation of blender/python see the `API Overview `_\n") fw("\n") - fw("`A PDF version of this document is also available `__\n" % version_string_fp) + fw("`A PDF version of this document is also available `_\n" % version_string_fp) fw("\n") fw(".. warning:: The Python API in Blender is **UNSTABLE**, It should only be used for testing, any script written now may break in future releases.\n") fw(" \n") @@ -943,6 +950,7 @@ def rna2sphinx(BASEPATH): fw = file.write fw("Operators (bpy.ops)\n") fw("===================\n\n") + write_example_ref("", fw, "bpy.ops") fw(".. toctree::\n") fw(" :glob:\n\n") fw(" bpy.ops.*\n\n") @@ -1010,7 +1018,6 @@ def rna2sphinx(BASEPATH): import mathutils as module pymodule2sphinx(BASEPATH, "mathutils", module, "Math Types & Utilities (mathutils)") - if "mathutils.geometry" not in EXCLUDE_MODULES: import mathutils.geometry as module pymodule2sphinx(BASEPATH, "mathutils.geometry", module, "Geometry Utilities (mathutils.geometry)") -- cgit v1.2.3