diff --git a/doc/python_api/examples/bpy.types.FileHandler.1.py b/doc/python_api/examples/bpy.types.FileHandler.1.py index 8a3c0c8040f..fac02e49f40 100644 --- a/doc/python_api/examples/bpy.types.FileHandler.1.py +++ b/doc/python_api/examples/bpy.types.FileHandler.1.py @@ -1,25 +1,20 @@ """ -Basic FileHandler for Operator that imports just one file ---------------------------------------------------------- +Basic FileHandler for importing a single file +--------------------------------------------- -When creating a ``Operator`` that imports files, you may want to -add them 'drag-and-drop' support, File Handlers helps to define -a set of files extensions (:class:`FileHandler.bl_file_extensions`) -that the ``Operator`` support and a :class:`FileHandler.poll_drop` -function that can be used to check in what specific context the ``Operator`` -can be invoked with 'drag-and-drop' filepath data. +A file handler allows custom 'drag-and-drop' behavior to be associated with a given ``Operator`` +(:class:`FileHandler.bl_import_operator`) and set of file extensions +(:class:`FileHandler.bl_file_extensions`). Control over which area of the UI accepts the +`drag-in-drop` action is specified using the :class:`FileHandler.poll_drop` method. -Same as operators that uses the file select window, this operators -required a set of properties, when the ``Operator`` can import just one -file per execution it needs to define the following property: +Similar to operators that use a file select window, operators participating in 'drag-and-drop', and +only accepting a single file, must define the following property: .. code-block:: python - filepath: bpy.props.StringProperty(subtype='FILE_PATH') - -This ``filepath`` property now will be used by the ``FileHandler`` to -set the 'drag-and-drop' filepath data. + filepath: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'}) +This ``filepath`` property will be set to the full path of the file dropped by the user. """ import bpy @@ -27,13 +22,13 @@ import bpy class CurveTextImport(bpy.types.Operator): """ - Test importer that creates a text object from a text file. + Creates a text object from a text file. """ bl_idname = "curve.text_import" bl_label = "Import a text file as text object" - # This Operator supports import one `.txt` file at the time, we need the - # following file-path property that the file handler will use to set file path data. + # This Operator supports processing one `.txt` file at a time. The following file-path + # property must be defined. filepath: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'}) @classmethod @@ -41,10 +36,12 @@ class CurveTextImport(bpy.types.Operator): return (context.area and context.area.type == "VIEW_3D") def execute(self, context): - # Calls to this Operator can set unfiltered file-paths, ensure the file extension is `.txt`. + # Direct calls to this Operator may use unsupported file-paths. Ensure the incoming + # file-path is one that is supported. if not self.filepath or not self.filepath.endswith(".txt"): return {'CANCELLED'} + # Create a Blender Text object from the contents of the provided file. with open(self.filepath) as file: text_curve = bpy.data.curves.new(type="FONT", name="Text") text_curve.body = ''.join(file.readlines()) @@ -52,11 +49,12 @@ class CurveTextImport(bpy.types.Operator): bpy.context.scene.collection.objects.link(text_object) return {'FINISHED'} - # By default the file handler invokes the operator with the file-path property set. - # In this example if this property is set the operator is executed, if not the - # file select window is invoked. - # This depends on setting `options={'SKIP_SAVE'}` to the property options to avoid - # to reuse file-path data between operator calls. + # By default the file handler invokes the operator with the file-path property set. If the + # operator also supports being invoked with no file-path set, and allows the user to pick from a + # file select window instead, the following logic can be used. + # + # Note: It is important to use `options={'SKIP_SAVE'}` when defining the file-path property to + # avoid prior values from being reused on subsequent calls. def invoke(self, context, event): if self.filepath: @@ -65,6 +63,9 @@ class CurveTextImport(bpy.types.Operator): return {'RUNNING_MODAL'} +# Define a file handler that supports the following set of conditions: +# - Execute the `curve.text_import` operator +# - When `.txt` files are dropped in the 3D Viewport class CURVE_FH_text_import(bpy.types.FileHandler): bl_idname = "CURVE_FH_text_import" bl_label = "File handler for curve text object import" diff --git a/doc/python_api/examples/bpy.types.FileHandler.2.py b/doc/python_api/examples/bpy.types.FileHandler.2.py index 1c8caa0c6a9..f3f4090ba84 100644 --- a/doc/python_api/examples/bpy.types.FileHandler.2.py +++ b/doc/python_api/examples/bpy.types.FileHandler.2.py @@ -1,17 +1,21 @@ """ -Basic FileHandler for Operator that imports multiple files ----------------------------------------------------------- +FileHandler for Importing multiple files and exposing Operator options +---------------------------------------------------------------------- -Also operators can be invoked with multiple files from 'drag-and-drop', -but for this it is require to define the following properties: +Operators which support being executed with multiple files from 'drag-and-drop' require the +following properties be defined: .. code-block:: python - directory: StringProperty(subtype='DIR_PATH') - files: CollectionProperty(type=bpy.types.OperatorFileListElement) + directory: StringProperty(subtype='DIR_PATH', options={'SKIP_SAVE', 'HIDDEN'}) + files: CollectionProperty(type=OperatorFileListElement, options={'SKIP_SAVE', 'HIDDEN'}) -This ``directory`` and ``files`` properties now will be used by the -``FileHandler`` to set 'drag-and-drop' filepath data. +These ``directory`` and ``files`` properties will be set with the necessary data from the +`drag-and-drop` operation. + +Additionally, if the operator provides operator properties that need to be accessible to the user, +the :class:`ImportHelper.invoke_popup` method can be used to show a dialog leveraging the standard +:class:`Operator.draw` method for layout and display. """ @@ -21,18 +25,18 @@ from mathutils import Vector class ShaderScriptImport(bpy.types.Operator, ImportHelper): - """Test importer that creates scripts nodes from .txt files""" + """ + Creates one or more Shader Script nodes from text files. + """ bl_idname = "shader.script_import" bl_label = "Import a text file as a script node" - """ - This Operator can import multiple .txt files, we need following directory and files - properties that the file handler will use to set files path data - """ + # This Operator supports processing multiple `.txt` files at a time. The following properties + # must be defined. directory: bpy.props.StringProperty(subtype='DIR_PATH', options={'SKIP_SAVE', 'HIDDEN'}) files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE', 'HIDDEN'}) - """Allow the user to select if the node's label is set or not""" + # Allow the user to choose whether the node's label is set or not set_label: bpy.props.BoolProperty(name="Set Label", default=False) @classmethod @@ -45,22 +49,22 @@ class ShaderScriptImport(bpy.types.Operator, ImportHelper): ) def execute(self, context): - """ The directory property need to be set. """ + # The directory property must be set. if not self.directory: return {'CANCELLED'} + x = 0.0 y = 0.0 for file in self.files: - """ - Calls to the operator can set unfiltered file names, - ensure the file extension is .txt - """ + # Direct calls to this Operator may use unsupported file-paths. Ensure the incoming + # files are ones that are supported. if file.name.endswith(".txt"): + import os + filepath = os.path.join(self.directory, file.name) + node_tree = context.material.node_tree text_node = node_tree.nodes.new(type="ShaderNodeScript") text_node.mode = 'EXTERNAL' - import os - filepath = os.path.join(self.directory, file.name) text_node.filepath = filepath text_node.location = Vector((x, y)) @@ -70,12 +74,13 @@ class ShaderScriptImport(bpy.types.Operator, ImportHelper): x += 20.0 y -= 20.0 + return {'FINISHED'} # Use ImportHelper's invoke_popup() to handle the invocation so that this operator's properties - # are shown in a popup. This allows the user to configure additional settings on the operator like - # the `set_label` property. Consider having a draw() method on the operator in order to layout the - # properties in the UI appropriately. + # are shown in a popup. This allows the user to configure additional settings on the operator + # like the `set_label` property. Consider having a draw() method on the operator in order to + # layout the properties in the UI appropriately. # # If filepath information is not provided the file select window will be invoked instead. @@ -83,6 +88,9 @@ class ShaderScriptImport(bpy.types.Operator, ImportHelper): return self.invoke_popup(context) +# Define a file handler that supports the following set of conditions: +# - Execute the `shader.script_import` operator +# - When `.txt` files are dropped in the Shader Editor class SHADER_FH_script_import(bpy.types.FileHandler): bl_idname = "SHADER_FH_script_import" bl_label = "File handler for shader script node import"