IO: Add support for Drag and Drop to FileHandlers
Added support to Drag and Drop to file handlers, part of #111242. If file handlers are registered with an import operator they can now be invoked with drag and drop path data. Import operators must either declare a `filepath` StringProperty or both a `directory` StringProperty and a `files` CollectionProperty depending on if they support single or multiple files respectively. Multiple FileHandlers could be valid for handling a dropped path. When this happens a menu is shown so the user can choose which exact handler to use for the file. Pull Request: https://projects.blender.org/blender/blender/pulls/116047
This commit is contained in:
committed by
Jesse Yurkovich
parent
09063a3632
commit
1254fee589
81
doc/python_api/examples/bpy.types.FileHandler.1.py
Normal file
81
doc/python_api/examples/bpy.types.FileHandler.1.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
Basic FileHandler for Operator that imports just one 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.
|
||||
|
||||
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:
|
||||
|
||||
.. 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.
|
||||
|
||||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
class CurveTextImport(bpy.types.Operator):
|
||||
""" Test importer that creates a text object from a .txt 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 filepath property that the file handler will use to set file path data.
|
||||
"""
|
||||
filepath: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'})
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.area and context.area.type == "VIEW_3D")
|
||||
|
||||
def execute(self, context):
|
||||
""" Calls to this Operator can set unfiltered filepaths, ensure the file extension is .txt. """
|
||||
if not self.filepath or not self.filepath.endswith(".txt"):
|
||||
return {'CANCELLED'}
|
||||
|
||||
with open(self.filepath) as file:
|
||||
text_curve = bpy.data.curves.new(type="FONT", name="Text")
|
||||
text_curve.body = ''.join(file.readlines())
|
||||
text_object = bpy.data.objects.new(name="Text", object_data=text_curve)
|
||||
bpy.context.scene.collection.objects.link(text_object)
|
||||
return {'FINISHED'}
|
||||
|
||||
"""
|
||||
By default the file handler invokes the operator with the filepath 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 filepath data between operator calls.
|
||||
"""
|
||||
|
||||
def invoke(self, context, event):
|
||||
if self.filepath:
|
||||
return self.execute(context)
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
class CURVE_FH_text_import(bpy.types.FileHandler):
|
||||
bl_idname = "CURVE_FH_text_import"
|
||||
bl_label = "File handler for curve text object import"
|
||||
bl_import_operator = "curve.text_import"
|
||||
bl_file_extensions = ".txt"
|
||||
|
||||
@classmethod
|
||||
def poll_drop(cls, context):
|
||||
return (context.area and context.area.type == 'VIEW_3D')
|
||||
|
||||
|
||||
bpy.utils.register_class(CurveTextImport)
|
||||
bpy.utils.register_class(CURVE_FH_text_import)
|
||||
91
doc/python_api/examples/bpy.types.FileHandler.2.py
Normal file
91
doc/python_api/examples/bpy.types.FileHandler.2.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Basic FileHandler for Operator that imports multiple files
|
||||
-----------------
|
||||
|
||||
Also operators can be invoked with multiple files from 'drag-and-drop',
|
||||
but for this it is require to define the following properties:
|
||||
|
||||
.. code-block:: python
|
||||
directory: StringProperty(subtype='FILE_PATH')
|
||||
files: CollectionProperty(type=bpy.types.OperatorFileListElement)
|
||||
|
||||
This ``directory`` and ``files`` properties now will be used by the
|
||||
``FileHandler`` to set 'drag-and-drop' filepath data.
|
||||
|
||||
"""
|
||||
|
||||
import bpy
|
||||
from mathutils import Vector
|
||||
|
||||
|
||||
class ShaderScriptImport(bpy.types.Operator):
|
||||
"""Test importer that creates scripts nodes from .txt 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
|
||||
"""
|
||||
directory: bpy.props.StringProperty(subtype='FILE_PATH', options={'SKIP_SAVE'})
|
||||
files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'SKIP_SAVE'})
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.region and context.region.type == 'WINDOW'
|
||||
and context.area and context.area.ui_type == 'ShaderNodeTree'
|
||||
and context.object and context.object.type == 'MESH'
|
||||
and context.material)
|
||||
|
||||
def execute(self, context):
|
||||
""" The directory property need to 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
|
||||
"""
|
||||
if file.name.endswith(".txt"):
|
||||
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))
|
||||
x += 20.0
|
||||
y -= 20.0
|
||||
return {'FINISHED'}
|
||||
|
||||
"""
|
||||
By default the file handler invokes the operator with the directory and files properties set.
|
||||
In this example if this properties are set the operator is executed, if not the
|
||||
file select window is invoked.
|
||||
This depends on setting 'options={'SKIP_SAVE'}' to the properties options to avoid
|
||||
to reuse filepath data between operator calls.
|
||||
"""
|
||||
|
||||
def invoke(self, context, event):
|
||||
if self.directory:
|
||||
return self.execute(context)
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
class SHADER_FH_script_import(bpy.types.FileHandler):
|
||||
bl_idname = "SHADER_FH_script_import"
|
||||
bl_label = "File handler for shader script node import"
|
||||
bl_import_operator = "shader.script_import"
|
||||
bl_file_extensions = ".txt"
|
||||
|
||||
@classmethod
|
||||
def poll_drop(cls, context):
|
||||
return (context.region and context.region.type == 'WINDOW'
|
||||
and context.area and context.area.ui_type == 'ShaderNodeTree')
|
||||
|
||||
|
||||
bpy.utils.register_class(ShaderScriptImport)
|
||||
bpy.utils.register_class(SHADER_FH_script_import)
|
||||
Reference in New Issue
Block a user