-
-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'b/main'
- Loading branch information
Showing
146 changed files
with
44,407 additions
and
11,999 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,63 @@ | ||
""" | ||
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. | ||
Also notice this operator defines its own properties, these are different | ||
to typical class properties because blender registers them with the | ||
operator, to use as arguments when called, saved for operator undo/redo and | ||
automatically added into the user interface. | ||
.. _operator_modifying_blender_data_undo: | ||
Modifying Blender Data & Undo | ||
+++++++++++++++++++++++++++++ | ||
Any operator modifying Blender data should enable the ``'UNDO'`` option. | ||
This will make Blender automatically create an undo step when the operator | ||
finishes its ``execute`` (or ``invoke``, see below) functions, and returns | ||
``{'FINISHED'}``. | ||
Otherwise, no undo step will be created, which will at best corrupt the | ||
undo stack and confuse the user (since modifications done by the operator | ||
may either not be undoable, or be undone together with other edits done | ||
before). In many cases, this can even lead to data corruption and crashes. | ||
Note that when an operator returns ``{'CANCELLED'}``, no undo step will be | ||
created. This means that if an error occurs *after* modifying some data | ||
already, it is better to return ``{'FINISHED'}``, unless it is possible to | ||
fully undo the changes before returning. | ||
.. note:: | ||
Most examples in this page do not do any edit to Blender data, which is | ||
why it is safe to keep the default ``bl_options`` value for these operators. | ||
.. note:: | ||
In some complex cases, the automatic undo step created on operator exit may | ||
not be enough. For example, if the operator does mode switching, or calls | ||
other operators that should create an extra undo step, etc. | ||
Such manual undo push is possible using the :class:`bpy.ops.ed.undo_push` | ||
function. Be careful though, this is considered an advanced feature and | ||
requires some understanding of the actual undo system in Blender code. | ||
""" | ||
import bpy | ||
|
||
|
||
class SimpleMouseOperator(bpy.types.Operator): | ||
""" 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" | ||
|
||
x: bpy.props.IntProperty() | ||
y: bpy.props.IntProperty() | ||
class DataEditOperator(bpy.types.Operator): | ||
bl_idname = "object.data_edit" | ||
bl_label = "Data Editing Operator" | ||
# The default value is only 'REGISTER', 'UNDO' is mandatory when Blender data is modified | ||
# (and does require 'REGISTER' as well). | ||
bl_options = {'REGISTER', 'UNDO'} | ||
|
||
def execute(self, context): | ||
# rather than printing, use the report function, | ||
# this way the message appears in the header, | ||
self.report({'INFO'}, "Mouse coords are {:d} {:d}".format(self.x, self.y)) | ||
context.object.location.x += 1.0 | ||
return {'FINISHED'} | ||
|
||
def invoke(self, context, event): | ||
self.x = event.mouse_x | ||
self.y = event.mouse_y | ||
return self.execute(context) | ||
|
||
|
||
# Only needed if you want to add into a dynamic menu. | ||
def menu_func(self, context): | ||
self.layout.operator(SimpleMouseOperator.bl_idname, text="Simple Mouse Operator") | ||
self.layout.operator(DataEditOperator.bl_idname, text="Blender Data Editing Operator") | ||
|
||
|
||
# Register and add to the view menu (required to also use F3 search "Simple Mouse Operator" for quick access) | ||
bpy.utils.register_class(SimpleMouseOperator) | ||
# Register. | ||
bpy.utils.register_class(DataEditOperator) | ||
bpy.types.VIEW3D_MT_view.append(menu_func) | ||
|
||
# Test call to the newly defined operator. | ||
# Here we call the operator and invoke it, meaning that the settings are taken | ||
# from the mouse. | ||
bpy.ops.wm.mouse_position('INVOKE_DEFAULT') | ||
|
||
# Another test call, this time call execute() directly with pre-defined settings. | ||
bpy.ops.wm.mouse_position('EXEC_DEFAULT', x=20, y=66) | ||
bpy.ops.object.data_edit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,61 @@ | ||
""" | ||
Calling a 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. | ||
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. | ||
Also notice this operator defines its own properties, these are different | ||
to typical class properties because blender registers them with the | ||
operator, to use as arguments when called, saved for operator undo/redo and | ||
automatically added into the user interface. | ||
""" | ||
import bpy | ||
|
||
|
||
class ExportSomeData(bpy.types.Operator): | ||
"""Test exporter which just writes hello world""" | ||
bl_idname = "export.some_data" | ||
bl_label = "Export Some Data" | ||
|
||
filepath: bpy.props.StringProperty(subtype="FILE_PATH") | ||
class SimpleMouseOperator(bpy.types.Operator): | ||
""" 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" | ||
|
||
@classmethod | ||
def poll(cls, context): | ||
return context.object is not None | ||
x: bpy.props.IntProperty() | ||
y: bpy.props.IntProperty() | ||
|
||
def execute(self, context): | ||
file = open(self.filepath, 'w') | ||
file.write("Hello World " + context.object.name) | ||
# rather than printing, use the report function, | ||
# this way the message appears in the header, | ||
self.report({'INFO'}, "Mouse coords are {:d} {:d}".format(self.x, self.y)) | ||
return {'FINISHED'} | ||
|
||
def invoke(self, context, event): | ||
context.window_manager.fileselect_add(self) | ||
return {'RUNNING_MODAL'} | ||
self.x = event.mouse_x | ||
self.y = event.mouse_y | ||
return self.execute(context) | ||
|
||
|
||
# Only needed if you want to add into a dynamic menu. | ||
def menu_func(self, context): | ||
self.layout.operator_context = 'INVOKE_DEFAULT' | ||
self.layout.operator(ExportSomeData.bl_idname, text="Text Export Operator") | ||
self.layout.operator(SimpleMouseOperator.bl_idname, text="Simple Mouse Operator") | ||
|
||
|
||
# Register and add to the file selector (required to also use F3 search "Text Export Operator" for quick access) | ||
bpy.utils.register_class(ExportSomeData) | ||
bpy.types.TOPBAR_MT_file_export.append(menu_func) | ||
# Register and add to the view menu (required to also use F3 search "Simple Mouse Operator" for quick access) | ||
bpy.utils.register_class(SimpleMouseOperator) | ||
bpy.types.VIEW3D_MT_view.append(menu_func) | ||
|
||
# Test call to the newly defined operator. | ||
# Here we call the operator and invoke it, meaning that the settings are taken | ||
# from the mouse. | ||
bpy.ops.wm.mouse_position('INVOKE_DEFAULT') | ||
|
||
# test call | ||
bpy.ops.export.some_data('INVOKE_DEFAULT') | ||
# Another test call, this time call execute() directly with pre-defined settings. | ||
bpy.ops.wm.mouse_position('EXEC_DEFAULT', x=20, y=66) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,52 @@ | ||
""" | ||
Dialog Box | ||
++++++++++ | ||
Calling a File Selector | ||
+++++++++++++++++++++++ | ||
This example shows how an operator can use the file selector. | ||
This operator uses its :class:`Operator.invoke` function to call a popup. | ||
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 | ||
|
||
|
||
class DialogOperator(bpy.types.Operator): | ||
bl_idname = "object.dialog_operator" | ||
bl_label = "Simple Dialog Operator" | ||
class ExportSomeData(bpy.types.Operator): | ||
"""Test exporter which just writes hello world""" | ||
bl_idname = "export.some_data" | ||
bl_label = "Export Some Data" | ||
|
||
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") | ||
filepath: bpy.props.StringProperty(subtype="FILE_PATH") | ||
|
||
@classmethod | ||
def poll(cls, context): | ||
return context.object is not None | ||
|
||
def execute(self, context): | ||
message = "Popup Values: {:f}, {:d}, '{:s}'".format( | ||
self.my_float, self.my_bool, self.my_string, | ||
) | ||
self.report({'INFO'}, message) | ||
file = open(self.filepath, 'w') | ||
file.write("Hello World " + context.object.name) | ||
return {'FINISHED'} | ||
|
||
def invoke(self, context, event): | ||
wm = context.window_manager | ||
return wm.invoke_props_dialog(self) | ||
context.window_manager.fileselect_add(self) | ||
return {'RUNNING_MODAL'} | ||
|
||
|
||
# Only needed if you want to add into a dynamic menu. | ||
def menu_func(self, context): | ||
self.layout.operator(DialogOperator.bl_idname, text="Dialog Operator") | ||
self.layout.operator_context = 'INVOKE_DEFAULT' | ||
self.layout.operator(ExportSomeData.bl_idname, text="Text Export Operator") | ||
|
||
|
||
# Register and add to the file selector (required to also use F3 search "Text Export Operator" for quick access) | ||
bpy.utils.register_class(ExportSomeData) | ||
bpy.types.TOPBAR_MT_file_export.append(menu_func) | ||
|
||
# Register and add to the object menu (required to also use F3 search "Dialog Operator" for quick access) | ||
bpy.utils.register_class(DialogOperator) | ||
bpy.types.VIEW3D_MT_object.append(menu_func) | ||
|
||
# Test call. | ||
bpy.ops.object.dialog_operator('INVOKE_DEFAULT') | ||
# test call | ||
bpy.ops.export.some_data('INVOKE_DEFAULT') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,40 @@ | ||
""" | ||
Custom Drawing | ||
++++++++++++++ | ||
Dialog Box | ||
++++++++++ | ||
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. | ||
This operator uses its :class:`Operator.invoke` function to call a popup. | ||
""" | ||
import bpy | ||
|
||
|
||
class CustomDrawOperator(bpy.types.Operator): | ||
bl_idname = "object.custom_draw" | ||
bl_label = "Simple Modal Operator" | ||
|
||
filepath: bpy.props.StringProperty(subtype="FILE_PATH") | ||
class DialogOperator(bpy.types.Operator): | ||
bl_idname = "object.dialog_operator" | ||
bl_label = "Simple Dialog Operator" | ||
|
||
my_float: bpy.props.FloatProperty(name="Float") | ||
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): | ||
print("Test", self) | ||
message = "Popup Values: {:f}, {:d}, '{:s}'".format( | ||
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) | ||
|
||
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") | ||
|
||
|
||
# Only needed if you want to add into a dynamic menu. | ||
def menu_func(self, context): | ||
self.layout.operator(CustomDrawOperator.bl_idname, text="Custom Draw Operator") | ||
self.layout.operator(DialogOperator.bl_idname, text="Dialog Operator") | ||
|
||
|
||
# Register and add to the object menu (required to also use F3 search "Custom Draw Operator" for quick access). | ||
bpy.utils.register_class(CustomDrawOperator) | ||
# Register and add to the object menu (required to also use F3 search "Dialog Operator" for quick access) | ||
bpy.utils.register_class(DialogOperator) | ||
bpy.types.VIEW3D_MT_object.append(menu_func) | ||
|
||
# test call | ||
bpy.ops.object.custom_draw('INVOKE_DEFAULT') | ||
# Test call. | ||
bpy.ops.object.dialog_operator('INVOKE_DEFAULT') |
Oops, something went wrong.