From 22e203e9cc98d99c376c6e6721e509e84ca6eeed Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Fri, 22 Mar 2024 01:41:20 -0700 Subject: [PATCH 1/2] ImportHelper: Provide common methods for drag and drop --- scripts/modules/bpy_extras/io_utils.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scripts/modules/bpy_extras/io_utils.py b/scripts/modules/bpy_extras/io_utils.py index 536747b3930..07d859f2685 100644 --- a/scripts/modules/bpy_extras/io_utils.py +++ b/scripts/modules/bpy_extras/io_utils.py @@ -102,6 +102,16 @@ class ImportHelper: context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} + def invoke_popup(self, context, confirm_text="Ok"): + if self.properties.is_property_set("filepath"): + title = self.filepath + if len(self.files) > 1: + title = "Import %d files" % len(self.files) + context.window_manager.invoke_props_dialog(self, confirm_text=confirm_text, title=title) + return {'RUNNING_MODAL'} + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} + def check(self, _context): return _check_axis_conversion(self) @@ -394,6 +404,19 @@ def unpack_face_list(list_of_tuples): return flat_ls +def poll_file_object_drop(context): + """ + A default implementation for FileHandler poll_drop methods. Allows for both the 3D Viewport and + the Outliner (in ViewLayer display mode) to be targets for file drag and drop. + """ + area = context.area + if not area: + return False + is_v3d = area.type == 'VIEW_3D' + is_outliner_view_layer = area.type == 'OUTLINER' and area.spaces.active.display_mode == 'VIEW_LAYER' + return is_v3d or is_outliner_view_layer + + path_reference_mode = EnumProperty( name="Path Mode", description="Method used to reference paths", -- 2.30.2 From 5df89af457ed54b2a74f823069a3307cba739340 Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Sun, 24 Mar 2024 19:53:21 -0700 Subject: [PATCH 2/2] Feedback --- .../examples/bpy.types.FileHandler.2.py | 32 +++++++++++-------- scripts/modules/bpy_extras/io_utils.py | 19 ++++++++--- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/doc/python_api/examples/bpy.types.FileHandler.2.py b/doc/python_api/examples/bpy.types.FileHandler.2.py index d510bb88c37..aae178659ac 100644 --- a/doc/python_api/examples/bpy.types.FileHandler.2.py +++ b/doc/python_api/examples/bpy.types.FileHandler.2.py @@ -16,10 +16,11 @@ This ``directory`` and ``files`` properties now will be used by the """ import bpy +from bpy_extras.io_utils import ImportHelper from mathutils import Vector -class ShaderScriptImport(bpy.types.Operator): +class ShaderScriptImport(bpy.types.Operator, ImportHelper): """Test importer that creates scripts nodes from .txt files""" bl_idname = "shader.script_import" bl_label = "Import a text file as a script node" @@ -28,8 +29,11 @@ class ShaderScriptImport(bpy.types.Operator): 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'}) + directory: bpy.props.StringProperty(subtype='FILE_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""" + set_label: bpy.props.BoolProperty(name="Set Label", default=False) @classmethod def poll(cls, context): @@ -57,23 +61,25 @@ class ShaderScriptImport(bpy.types.Operator): filepath = os.path.join(self.directory, file.name) text_node.filepath = filepath text_node.location = Vector((x, y)) + + # Set the node's title to the file name + if self.set_label: + text_node.label = file.name + 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. - """ + 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. + If filepath information is not provided the file select window will be invoked instead. + """ def invoke(self, context, event): - if self.directory: - return self.execute(context) - context.window_manager.fileselect_add(self) - return {'RUNNING_MODAL'} + return self.invoke_popup(context) class SHADER_FH_script_import(bpy.types.FileHandler): diff --git a/scripts/modules/bpy_extras/io_utils.py b/scripts/modules/bpy_extras/io_utils.py index 07d859f2685..da4d3174c30 100644 --- a/scripts/modules/bpy_extras/io_utils.py +++ b/scripts/modules/bpy_extras/io_utils.py @@ -23,7 +23,10 @@ from bpy.props import ( EnumProperty, StringProperty, ) -from bpy.app.translations import pgettext_data as data_ +from bpy.app.translations import ( + pgettext_iface as iface_, + pgettext_data as data_, +) def _check_axis_conversion(op): @@ -96,19 +99,25 @@ class ImportHelper: description="Filepath used for importing the file", maxlen=1024, subtype='FILE_PATH', + options={'SKIP_PRESET', 'HIDDEN'} ) def invoke(self, context, _event): context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} - def invoke_popup(self, context, confirm_text="Ok"): + def invoke_popup(self, context, confirm_text=""): if self.properties.is_property_set("filepath"): title = self.filepath if len(self.files) > 1: - title = "Import %d files" % len(self.files) - context.window_manager.invoke_props_dialog(self, confirm_text=confirm_text, title=title) - return {'RUNNING_MODAL'} + title = iface_("Import {} files").format(len(self.files)) + + if not confirm_text: + confirm_text = self.bl_label + + confirm_text = iface_(confirm_text) + return context.window_manager.invoke_props_dialog(self, confirm_text=confirm_text, title=title, translate=False) + context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} -- 2.30.2