From 53aec1ccff1b7e6356836a29b36115b475f0c3d2 Mon Sep 17 00:00:00 2001
From: Julian Eisel <eiseljulian@gmail.com>
Date: Tue, 3 Sep 2019 16:04:55 +0200
Subject: [PATCH] UI: New options layout for IO Add-ons

Updates importers/exporters for the new file-browser design. They are
now reorganized into sub-panels.

Updated the Blender version requirement (won't be compatible with older
Blender versions). Left the Add-on versions untouched, will leave that
up to Authors to change.
---
 io_anim_bvh/__init__.py    | 149 +++++++++++-
 io_mesh_ply/__init__.py    |  64 ++++-
 io_mesh_stl/__init__.py    | 170 +++++++++++++-
 io_scene_fbx/__init__.py   | 467 ++++++++++++++++++++++++++++---------
 io_scene_gltf2/__init__.py | 356 ++++++++++++++++++++++------
 io_scene_obj/__init__.py   | 196 ++++++++++++++--
 io_scene_x3d/__init__.py   | 117 +++++++++-
 7 files changed, 1313 insertions(+), 206 deletions(-)

diff --git a/io_anim_bvh/__init__.py b/io_anim_bvh/__init__.py
index b22811fa7..533147583 100644
--- a/io_anim_bvh/__init__.py
+++ b/io_anim_bvh/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
     "name": "BioVision Motion Capture (BVH) format",
     "author": "Campbell Barton",
     "version": (1, 0, 0),
-    "blender": (2, 80, 0),
+    "blender": (2, 81, 6),
     "location": "File > Import-Export",
     "description": "Import-Export BVH from armature objects",
     "warning": "",
@@ -147,6 +147,91 @@ class ImportBVH(bpy.types.Operator, ImportHelper):
         from . import import_bvh
         return import_bvh.load(context, report=self.report, **keywords)
 
+    def draw(self, context):
+        pass
+
+
+class BVH_PT_import_main(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = ""
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'HIDE_HEADER'}
+
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_ANIM_OT_bvh"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "target")
+
+
+class BVH_PT_import_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_ANIM_OT_bvh"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "rotate_mode")
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
+
+class BVH_PT_import_animation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_ANIM_OT_bvh"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "frame_start")
+        layout.prop(operator, "use_fps_scale")
+        layout.prop(operator, "use_cyclic")
+
+        layout.prop(operator, "update_scene_fps")
+        layout.prop(operator, "update_scene_duration")
+
 
 class ExportBVH(bpy.types.Operator, ExportHelper):
     """Save a BVH motion capture file from an armature"""
@@ -225,6 +310,61 @@ class ExportBVH(bpy.types.Operator, ExportHelper):
         from . import export_bvh
         return export_bvh.save(context, **keywords)
 
+    def draw(self, context):
+        pass
+
+
+class BVH_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_ANIM_OT_bvh"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "rotate_mode")
+        layout.prop(operator, "root_transform_only")
+
+
+class BVH_PT_export_animation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_ANIM_OT_bvh"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        col = layout.column(align=True)
+        col.prop(operator, "frame_start", text="Frame Start")
+        col.prop(operator, "frame_end", text="End")
+
 
 def menu_func_import(self, context):
     self.layout.operator(ImportBVH.bl_idname, text="Motion Capture (.bvh)")
@@ -236,7 +376,12 @@ def menu_func_export(self, context):
 
 classes = (
     ImportBVH,
-    ExportBVH
+    BVH_PT_import_main,
+    BVH_PT_import_transform,
+    BVH_PT_import_animation,
+    ExportBVH,
+    BVH_PT_export_transform,
+    BVH_PT_export_animation,
 )
 
 def register():
diff --git a/io_mesh_ply/__init__.py b/io_mesh_ply/__init__.py
index d0713b21a..b89732fd0 100644
--- a/io_mesh_ply/__init__.py
+++ b/io_mesh_ply/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
     "name": "Stanford PLY format",
     "author": "Bruce Merry, Campbell Barton",
     "version": (1, 0, 0),
-    "blender": (2, 80, 0),
+    "blender": (2, 81, 6),
     "location": "File > Import-Export",
     "description": "Import-Export PLY mesh data with UV's and vertex colors",
     "warning": "",
@@ -165,19 +165,61 @@ class ExportPLY(bpy.types.Operator, ExportHelper):
 
         return export_ply.save(self, context, **keywords)
 
+    def draw(self, context):
+        pass
+
+
+class PLY_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_MESH_OT_ply"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+        layout.prop(operator, "global_scale")
+
+
+class PLY_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_MESH_OT_ply"
+
     def draw(self, context):
         layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
 
-        row = layout.row()
-        row.prop(self, "use_mesh_modifiers")
-        row.prop(self, "use_normals")
-        row = layout.row()
-        row.prop(self, "use_uv_coords")
-        row.prop(self, "use_colors")
+        sfile = context.space_data
+        operator = sfile.active_operator
 
-        layout.prop(self, "axis_forward")
-        layout.prop(self, "axis_up")
-        layout.prop(self, "global_scale")
+        layout.prop(operator, "use_mesh_modifiers")
+        layout.prop(operator, "use_normals")
+        layout.prop(operator, "use_uv_coords")
+        layout.prop(operator, "use_colors")
 
 
 def menu_func_import(self, context):
@@ -191,6 +233,8 @@ def menu_func_export(self, context):
 classes = (
     ImportPLY,
     ExportPLY,
+    PLY_PT_export_transform,
+    PLY_PT_export_geometry,
 )
 
 
diff --git a/io_mesh_stl/__init__.py b/io_mesh_stl/__init__.py
index a5c61d9fc..cd81b228a 100644
--- a/io_mesh_stl/__init__.py
+++ b/io_mesh_stl/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
     "name": "STL format",
     "author": "Guillaume Bouchard (Guillaum)",
     "version": (1, 1, 3),
-    "blender": (2, 80, 0),
+    "blender": (2, 81, 6),
     "location": "File > Import-Export > Stl",
     "description": "Import-Export STL files",
     "warning": "",
@@ -151,6 +151,61 @@ class ImportSTL(Operator, ImportHelper):
 
         return {'FINISHED'}
 
+    def draw(self, context):
+        pass
+
+
+class STL_PT_import_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_MESH_OT_stl"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "use_scene_unit")
+
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
+
+class STL_PT_import_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_MESH_OT_stl"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_facet_normal")
+
 
 @orientation_helper(axis_forward='Y', axis_up='Z')
 class ExportSTL(Operator, ExportHelper):
@@ -244,6 +299,111 @@ class ExportSTL(Operator, ExportHelper):
 
         return {'FINISHED'}
 
+    def draw(self, context):
+        pass
+
+
+class STL_PT_export_main(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = ""
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'HIDE_HEADER'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_MESH_OT_stl"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "ascii")
+        layout.prop(operator, "batch_mode")
+
+
+class STL_PT_export_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_MESH_OT_stl"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_selection")
+
+
+class STL_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_MESH_OT_stl"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "use_scene_unit")
+
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
+
+class STL_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_MESH_OT_stl"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_mesh_modifiers")
+
 
 def menu_import(self, context):
     self.layout.operator(ImportSTL.bl_idname, text="Stl (.stl)")
@@ -255,7 +415,13 @@ def menu_export(self, context):
 
 classes = (
     ImportSTL,
-    ExportSTL
+    STL_PT_import_transform,
+    STL_PT_import_geometry,
+    ExportSTL,
+    STL_PT_export_main,
+    STL_PT_export_include,
+    STL_PT_export_transform,
+    STL_PT_export_geometry,
 )
 
 def register():
diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py
index bf25261c8..7f89ef3a1 100644
--- a/io_scene_fbx/__init__.py
+++ b/io_scene_fbx/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
     "name": "FBX format",
     "author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
     "version": (4, 15, 1),
-    "blender": (2, 80, 0),
+    "blender": (2, 81, 6),
     "location": "File > Import-Export",
     "description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
     "warning": "",
@@ -89,7 +89,7 @@ class ImportFBX(bpy.types.Operator, ImportHelper):
             default=1.0,
             )
     bake_space_transform: BoolProperty(
-            name="!EXPERIMENTAL! Apply Transform",
+            name="Apply Transform",
             description="Bake space transform into object data, avoids getting unwanted rotations to objects when "
                         "target space is not aligned with Blender's space "
                         "(WARNING! experimental option, use at own risks, known broken with armatures/animations)",
@@ -194,43 +194,7 @@ class ImportFBX(bpy.types.Operator, ImportHelper):
             )
 
     def draw(self, context):
-        layout = self.layout
-
-        layout.prop(self, "ui_tab", expand=True)
-        if self.ui_tab == 'MAIN':
-            layout.prop(self, "use_manual_orientation"),
-            sub = layout.column()
-            sub.enabled = self.use_manual_orientation
-            sub.prop(self, "axis_forward")
-            sub.prop(self, "axis_up")
-            layout.prop(self, "global_scale")
-            layout.prop(self, "bake_space_transform")
-
-            layout.prop(self, "use_custom_normals")
-
-            layout.prop(self, "use_anim")
-            layout.prop(self, "anim_offset")
-
-            layout.prop(self, "use_subsurf")
-
-            layout.prop(self, "use_custom_props")
-            sub = layout.row()
-            sub.enabled = self.use_custom_props
-            sub.prop(self, "use_custom_props_enum_as_string")
-
-            layout.prop(self, "use_image_search")
-            # layout.prop(self, "use_alpha_decals")
-            layout.prop(self, "decal_offset")
-
-            layout.prop(self, "use_prepost_rot")
-        elif self.ui_tab == 'ARMATURE':
-            layout.prop(self, "ignore_leaf_bones")
-            layout.prop(self, "force_connect_children"),
-            layout.prop(self, "automatic_bone_orientation"),
-            sub = layout.column()
-            sub.enabled = not self.automatic_bone_orientation
-            sub.prop(self, "primary_bone_axis")
-            sub.prop(self, "secondary_bone_axis")
+        pass
 
     def execute(self, context):
         keywords = self.as_keywords(ignore=("filter_glob", "directory", "ui_tab"))
@@ -239,6 +203,160 @@ class ImportFBX(bpy.types.Operator, ImportHelper):
         return import_fbx.load(self, context, **keywords)
 
 
+class FBX_PT_import_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_custom_normals")
+        layout.prop(operator, "use_subsurf")
+        layout.prop(operator, "use_custom_props")
+        sub = layout.row()
+        sub.enabled = operator.use_custom_props
+        sub.prop(operator, "use_custom_props_enum_as_string")
+        layout.prop(operator, "use_image_search")
+
+
+class FBX_PT_import_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "decal_offset")
+        layout.prop(operator, "bake_space_transform")
+        layout.prop(operator, "use_prepost_rot")
+
+
+class FBX_PT_import_transform_manual_orientation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Manual Orientation"
+    bl_parent_id = "FBX_PT_import_transform"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_fbx"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        self.layout.prop(operator, "use_manual_orientation", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.enabled = operator.use_manual_orientation
+
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
+
+class FBX_PT_import_animation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_fbx"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        self.layout.prop(operator, "use_anim", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.enabled = operator.use_anim
+
+        layout.prop(operator, "anim_offset")
+
+
+class FBX_PT_import_armature(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Armature"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "ignore_leaf_bones")
+        layout.prop(operator, "force_connect_children"),
+        layout.prop(operator, "automatic_bone_orientation"),
+        sub = layout.column()
+        sub.enabled = not operator.automatic_bone_orientation
+        sub.prop(operator, "primary_bone_axis")
+        sub.prop(operator, "secondary_bone_axis")
+
+
 @orientation_helper(axis_forward='-Z', axis_up='Y')
 class ExportFBX(bpy.types.Operator, ExportHelper):
     """Write a FBX file"""
@@ -252,16 +370,6 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
     # List of operator properties, the attributes will be assigned
     # to the class instance from the operator settings before calling.
 
-    ui_tab: EnumProperty(
-            items=(('MAIN', "Main", "Main basic settings"),
-                   ('GEOMETRY', "Geometries", "Geometry-related settings"),
-                   ('ARMATURE', "Armatures", "Armature-related settings"),
-                   ('ANIMATION', "Animation", "Animation-related settings"),
-                   ),
-            name="ui_tab",
-            description="Export options categories",
-            )
-
     use_selection: BoolProperty(
             name="Selected Objects",
             description="Export selected and visible objects only",
@@ -300,7 +408,7 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
                         "but many other applications do not handle the same way)",
             )
     bake_space_transform: BoolProperty(
-            name="!EXPERIMENTAL! Apply Transform",
+            name="Apply Transform",
             description="Bake space transform into object data, avoids getting unwanted rotations to objects when "
                         "target space is not aligned with Blender's space "
                         "(WARNING! experimental option, use at own risks, known broken with armatures/animations)",
@@ -482,66 +590,200 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
             options={'HIDDEN'},
             )
 
+    def draw(self, context):
+        pass
+
+
+class FBX_PT_export_main(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = ""
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'HIDE_HEADER'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        row = layout.row(align=True)
+        row.prop(operator, "path_mode")
+        sub = row.row(align=True)
+        sub.enabled = (operator.path_mode == 'COPY')
+        sub.prop(operator, "embed_textures", text="", icon='PACKAGE' if operator.embed_textures else 'UGLYPACKAGE')
+        row = layout.row(align=True)
+        row.prop(operator, "batch_mode")
+        sub = row.row(align=True)
+        sub.prop(operator, "use_batch_own_dir", text="", icon='NEWFOLDER')
+
+
+class FBX_PT_export_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_selection")
+        layout.prop(operator, "use_active_collection")
+        layout.column().prop(operator, "object_types")
+        layout.prop(operator, "use_custom_props")
+
+
+class FBX_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_fbx"
+
     def draw(self, context):
         layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "apply_scale_options")
+
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
+        layout.prop(operator, "apply_unit_scale")
+        layout.prop(operator, "bake_space_transform")
+
+
+class FBX_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "mesh_smooth_type")
+        layout.prop(operator, "use_subsurf")
+        layout.prop(operator, "use_mesh_modifiers")
+        #sub = layout.row()
+        #sub.enabled = operator.use_mesh_modifiers and False  # disabled in 2.8...
+        #sub.prop(operator, "use_mesh_modifiers_render")
+        layout.prop(operator, "use_mesh_edges")
+        sub = layout.row()
+        #~ sub.enabled = operator.mesh_smooth_type in {'OFF'}
+        sub.prop(operator, "use_tspace")
+
+
+class FBX_PT_export_armature(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Armature"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_fbx"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "primary_bone_axis")
+        layout.prop(operator, "secondary_bone_axis")
+        layout.prop(operator, "armature_nodetype")
+        layout.prop(operator, "use_armature_deform_only")
+        layout.prop(operator, "add_leaf_bones")
+
+
+class FBX_PT_export_bake_animation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Bake Animation"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_fbx"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        self.layout.prop(operator, "bake_anim", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.enabled = operator.bake_anim
+        layout.prop(operator, "bake_anim_use_all_bones")
+        layout.prop(operator, "bake_anim_use_nla_strips")
+        layout.prop(operator, "bake_anim_use_all_actions")
+        layout.prop(operator, "bake_anim_force_startend_keying")
+        layout.prop(operator, "bake_anim_step")
+        layout.prop(operator, "bake_anim_simplify_factor")
 
-        layout.prop(self, "ui_tab", expand=True)
-        if self.ui_tab == 'MAIN':
-            layout.prop(self, "use_selection")
-            layout.prop(self, "use_active_collection")
-
-            col = layout.column(align=True)
-            row = col.row(align=True)
-            row.prop(self, "global_scale")
-            sub = row.row(align=True)
-            sub.prop(self, "apply_unit_scale", text="", icon='NDOF_TRANS')
-            col.prop(self, "apply_scale_options")
-
-            layout.prop(self, "axis_forward")
-            layout.prop(self, "axis_up")
-
-            layout.separator()
-            layout.prop(self, "object_types")
-            layout.prop(self, "bake_space_transform")
-            layout.prop(self, "use_custom_props")
-
-            layout.separator()
-            row = layout.row(align=True)
-            row.prop(self, "path_mode")
-            sub = row.row(align=True)
-            sub.enabled = (self.path_mode == 'COPY')
-            sub.prop(self, "embed_textures", text="", icon='PACKAGE' if self.embed_textures else 'UGLYPACKAGE')
-            row = layout.row(align=True)
-            row.prop(self, "batch_mode")
-            sub = row.row(align=True)
-            sub.prop(self, "use_batch_own_dir", text="", icon='NEWFOLDER')
-        elif self.ui_tab == 'GEOMETRY':
-            layout.prop(self, "use_mesh_modifiers")
-            sub = layout.row()
-            sub.enabled = self.use_mesh_modifiers and False  # disabled in 2.8...
-            sub.prop(self, "use_mesh_modifiers_render")
-            layout.prop(self, "mesh_smooth_type")
-            layout.prop(self, "use_subsurf")
-            layout.prop(self, "use_mesh_edges")
-            sub = layout.row()
-            #~ sub.enabled = self.mesh_smooth_type in {'OFF'}
-            sub.prop(self, "use_tspace")
-        elif self.ui_tab == 'ARMATURE':
-            layout.prop(self, "use_armature_deform_only")
-            layout.prop(self, "add_leaf_bones")
-            layout.prop(self, "primary_bone_axis")
-            layout.prop(self, "secondary_bone_axis")
-            layout.prop(self, "armature_nodetype")
-        elif self.ui_tab == 'ANIMATION':
-            layout.prop(self, "bake_anim")
-            col = layout.column()
-            col.enabled = self.bake_anim
-            col.prop(self, "bake_anim_use_all_bones")
-            col.prop(self, "bake_anim_use_nla_strips")
-            col.prop(self, "bake_anim_use_all_actions")
-            col.prop(self, "bake_anim_force_startend_keying")
-            col.prop(self, "bake_anim_step")
-            col.prop(self, "bake_anim_simplify_factor")
 
     @property
     def check_extension(self):
@@ -577,7 +819,18 @@ def menu_func_export(self, context):
 
 classes = (
     ImportFBX,
+    FBX_PT_import_include,
+    FBX_PT_import_transform,
+    FBX_PT_import_transform_manual_orientation,
+    FBX_PT_import_animation,
+    FBX_PT_import_armature,
     ExportFBX,
+    FBX_PT_export_main,
+    FBX_PT_export_include,
+    FBX_PT_export_transform,
+    FBX_PT_export_geometry,
+    FBX_PT_export_armature,
+    FBX_PT_export_bake_animation,
 )
 
 
diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index ed81b1d2d..19cf45605 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -16,7 +16,7 @@ bl_info = {
     'name': 'glTF 2.0 format',
     'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
     "version": (0, 9, 54),
-    'blender': (2, 80, 0),
+    'blender': (2, 81, 6),
     'location': 'File > Import-Export',
     'description': 'Import-Export as glTF 2.0',
     'warning': '',
@@ -412,71 +412,286 @@ class ExportGLTF2_Base:
         return gltf2_blender_export.save(context, export_settings)
 
     def draw(self, context):
-        self.layout.prop(self, 'ui_tab', expand=True)
-        if self.ui_tab == 'GENERAL':
-            self.draw_general_settings()
-        elif self.ui_tab == 'MESHES':
-            self.draw_mesh_settings()
-        elif self.ui_tab == 'OBJECTS':
-            self.draw_object_settings()
-        elif self.ui_tab == 'MATERIALS':
-            self.draw_material_settings()
-        elif self.ui_tab == 'ANIMATION':
-            self.draw_animation_settings()
-
-    def draw_general_settings(self):
-        col = self.layout.box().column()
-        col.prop(self, 'export_format')
-        col.prop(self, 'export_selected')
-        col.prop(self, 'export_apply')
-        col.prop(self, 'export_yup')
-        col.prop(self, 'export_extras')
-        col.prop(self, 'will_save_settings')
-        col.prop(self, 'export_copyright')
-
-    def draw_mesh_settings(self):
-        col = self.layout.box().column()
-        col.prop(self, 'export_texcoords')
-        col.prop(self, 'export_normals')
-        if self.export_normals:
-            col.prop(self, 'export_tangents')
-        col.prop(self, 'export_colors')
-        col.prop(self, 'export_materials')
-        if self.export_materials:
-            col.prop(self, 'export_image_format')
-
-        # Add Draco compression option only if the DLL could be found.
-        if self.is_draco_available:
-            col.prop(self, 'export_draco_mesh_compression_enable')
-
-            # Display options when Draco compression is enabled.
-            if self.export_draco_mesh_compression_enable:
-                col.prop(self, 'export_draco_mesh_compression_level')
-                col.prop(self, 'export_draco_position_quantization')
-                col.prop(self, 'export_draco_normal_quantization')
-                col.prop(self, 'export_draco_texcoord_quantization')
-
-    def draw_object_settings(self):
-        col = self.layout.box().column()
-        col.prop(self, 'export_cameras')
-        col.prop(self, 'export_lights')
-
-    def draw_animation_settings(self):
-        col = self.layout.box().column()
-        col.prop(self, 'export_current_frame')
-        col.prop(self, 'export_animations')
-        if self.export_animations:
-            col.prop(self, 'export_frame_range')
-            col.prop(self, 'export_frame_step')
-            col.prop(self, 'export_force_sampling')
-        col.prop(self, 'export_skins')
-        if self.export_skins:
-            col.prop(self, 'export_all_influences')
-        col.prop(self, 'export_morph')
-        if self.export_morph:
-            col.prop(self, 'export_morph_normal')
-            if self.export_morph_normal:
-                col.prop(self, 'export_morph_tangent')
+        pass
+
+
+class GLTF_PT_export_main(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = ""
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'HIDE_HEADER'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_format')
+        layout.prop(operator, 'export_copyright')
+        layout.prop(operator, 'will_save_settings')
+
+
+class GLTF_PT_export_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_selected')
+        layout.prop(operator, 'export_extras')
+        layout.prop(operator, 'export_cameras')
+        layout.prop(operator, 'export_lights')
+
+
+class GLTF_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_yup')
+
+
+class GLTF_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_apply')
+        layout.prop(operator, 'export_texcoords')
+        layout.prop(operator, 'export_normals')
+        col = layout.column()
+        col.active = operator.export_normals
+        col.prop(operator, 'export_tangents')
+        layout.prop(operator, 'export_colors')
+        layout.prop(operator, 'export_materials')
+        col = layout.column()
+        col.active = operator.export_materials
+        col.prop(operator, 'export_image_format')
+
+
+class GLTF_PT_export_geometry_compression(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Compression"
+    bl_parent_id = "GLTF_PT_export_geometry"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def __init__(self):
+        self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists()
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        if operator.is_draco_available:
+            return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_draco_mesh_compression_enable", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_draco_mesh_compression_enable
+        layout.prop(operator, 'export_draco_mesh_compression_level')
+
+        col = layout.column(align=True)
+        col.prop(operator, 'export_draco_position_quantization', text="Quantize Position")
+        col.prop(operator, 'export_draco_normal_quantization', text="Normal")
+        col.prop(operator, 'export_draco_texcoord_quantization', text="Tex Coords")
+
+
+class GLTF_PT_export_animation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_current_frame')
+
+
+class GLTF_PT_export_animation_export(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "GLTF_PT_export_animation"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_animations", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_animations
+
+        layout.prop(operator, 'export_frame_range')
+        layout.prop(operator, 'export_frame_step')
+        layout.prop(operator, 'export_force_sampling')
+
+
+class GLTF_PT_export_animation_shapekeys(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Shape Keys"
+    bl_parent_id = "GLTF_PT_export_animation"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_morph", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_morph
+
+        layout.prop(operator, 'export_morph_normal')
+        col = layout.column()
+        col.active = operator.export_morph_normal
+        col.prop(operator, 'export_morph_tangent')
+
+
+class GLTF_PT_export_animation_skinning(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Skinning"
+    bl_parent_id = "GLTF_PT_export_animation"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_skins", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_skins
+        layout.prop(operator, 'export_all_influences')
 
 
 class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
@@ -573,6 +788,15 @@ def menu_func_import(self, context):
 
 classes = (
     ExportGLTF2,
+    GLTF_PT_export_main,
+    GLTF_PT_export_include,
+    GLTF_PT_export_transform,
+    GLTF_PT_export_geometry,
+    GLTF_PT_export_geometry_compression,
+    GLTF_PT_export_animation,
+    GLTF_PT_export_animation_export,
+    GLTF_PT_export_animation_shapekeys,
+    GLTF_PT_export_animation_skinning,
     ImportGLTF2
 )
 
diff --git a/io_scene_obj/__init__.py b/io_scene_obj/__init__.py
index ccf5ee3b6..2e3dcc43f 100644
--- a/io_scene_obj/__init__.py
+++ b/io_scene_obj/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
     "name": "Wavefront OBJ format",
     "author": "Campbell Barton, Bastien Montagne",
     "version": (3, 5, 15),
-    "blender": (2, 80, 0),
+    "blender": (2, 81, 6),
     "location": "File > Import-Export",
     "description": "Import-Export OBJ, Import OBJ mesh, UV's, materials and textures",
     "warning": "",
@@ -144,31 +144,182 @@ class ImportOBJ(bpy.types.Operator, ImportHelper):
 
         return import_obj.load(context, **keywords)
 
+    def draw(self, context):
+        pass
+
+
+class OBJ_PT_import_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_obj"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'use_image_search')
+        layout.prop(operator, 'use_smooth_groups')
+        layout.prop(operator, 'use_edges')
+
+
+class OBJ_PT_import_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_obj"
+
     def draw(self, context):
         layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_clight_size")
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
 
-        row = layout.row(align=True)
-        row.prop(self, "use_smooth_groups")
-        row.prop(self, "use_edges")
 
-        box = layout.box()
-        row = box.row()
-        row.prop(self, "split_mode", expand=True)
+class OBJ_PT_import_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
 
-        row = box.row()
-        if self.split_mode == 'ON':
-            row.label(text="Split by:")
-            row.prop(self, "use_split_objects")
-            row.prop(self, "use_split_groups")
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_obj"
+
+    def draw(self, context):
+        layout = self.layout
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.row().prop(operator, "split_mode", expand=True)
+
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        col = layout.column()
+        if operator.split_mode == 'ON':
+            col.prop(operator, "use_split_objects", text="Split by Object")
+            col.prop(operator, "use_split_groups", text="Split by Group")
         else:
-            row.prop(self, "use_groups_as_vgroups")
+            col.prop(operator, "use_groups_as_vgroups")
+
 
-        row = layout.split(factor=0.67)
-        row.prop(self, "global_clight_size")
-        layout.prop(self, "axis_forward")
-        layout.prop(self, "axis_up")
+class OBJ_PT_export_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
 
-        layout.prop(self, "use_image_search")
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_obj"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'use_selection')
+        layout.prop(operator, 'use_blen_objects')
+        layout.prop(operator, 'group_by_object')
+        layout.prop(operator, 'group_by_material')
+        layout.prop(operator, 'use_animation')
+
+
+class OBJ_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_obj"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'global_scale')
+        layout.prop(operator, 'path_mode')
+        layout.prop(operator, 'axis_forward')
+        layout.prop(operator, 'axis_up')
+
+
+class OBJ_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_obj"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'use_mesh_modifiers')
+        layout.prop(operator, 'use_mesh_modifiers_render')
+        layout.prop(operator, 'use_smooth_groups')
+        layout.prop(operator, 'use_smooth_groups_bitflags')
+        layout.prop(operator, 'use_normals')
+        layout.prop(operator, 'use_uvs')
+        layout.prop(operator, 'use_materials')
+        layout.prop(operator, 'use_triangles')
+        layout.prop(operator, 'use_nurbs', text="Curves as NURBS")
+        layout.prop(operator, 'keep_vertex_order')
 
 
 @orientation_helper(axis_forward='-Z', axis_up='Y')
@@ -310,6 +461,9 @@ class ExportOBJ(bpy.types.Operator, ExportHelper):
         keywords["global_matrix"] = global_matrix
         return export_obj.save(context, **keywords)
 
+    def draw(self, context):
+        pass
+
 
 def menu_func_import(self, context):
     self.layout.operator(ImportOBJ.bl_idname, text="Wavefront (.obj)")
@@ -321,7 +475,13 @@ def menu_func_export(self, context):
 
 classes = (
     ImportOBJ,
+    OBJ_PT_import_include,
+    OBJ_PT_import_transform,
+    OBJ_PT_import_geometry,
     ExportOBJ,
+    OBJ_PT_export_include,
+    OBJ_PT_export_transform,
+    OBJ_PT_export_geometry,
 )
 
 
diff --git a/io_scene_x3d/__init__.py b/io_scene_x3d/__init__.py
index a08b9a901..1b3060b09 100644
--- a/io_scene_x3d/__init__.py
+++ b/io_scene_x3d/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
     "name": "Web3D X3D/VRML2 format",
     "author": "Campbell Barton, Bart, Bastien Montagne, Seva Alekseyev",
     "version": (2, 2, 2),
-    "blender": (2, 80, 0),
+    "blender": (2, 81, 6),
     "location": "File > Import-Export",
     "description": "Import-Export X3D, Import VRML2",
     "warning": "",
@@ -78,6 +78,89 @@ class ImportX3D(bpy.types.Operator, ImportHelper):
 
         return import_x3d.load(context, **keywords)
 
+    def draw(self, context):
+        pass
+
+
+class X3D_PT_export_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "include"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_x3d"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_selection")
+        layout.prop(operator, "use_hierarchy")
+        layout.prop(operator, "name_decorations")
+        layout.prop(operator, "use_h3d")
+
+
+class X3D_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_x3d"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "global_scale")
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
+
+class X3D_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_x3d"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "use_mesh_modifiers")
+        layout.prop(operator, "use_triangulate")
+        layout.prop(operator, "use_normals")
+        layout.prop(operator, "use_compress")
+
 
 @orientation_helper(axis_forward='Z', axis_up='Y')
 class ExportX3D(bpy.types.Operator, ExportHelper):
@@ -157,6 +240,34 @@ class ExportX3D(bpy.types.Operator, ExportHelper):
 
         return export_x3d.save(context, **keywords)
 
+    def draw(self, context):
+        pass
+
+
+class X3D_PT_import_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "IMPORT_SCENE_OT_x3d"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, "axis_forward")
+        layout.prop(operator, "axis_up")
+
 
 def menu_func_import(self, context):
     self.layout.operator(ImportX3D.bl_idname,
@@ -170,7 +281,11 @@ def menu_func_export(self, context):
 
 classes = (
     ExportX3D,
+    X3D_PT_export_include,
+    X3D_PT_export_transform,
+    X3D_PT_export_geometry,
     ImportX3D,
+    X3D_PT_import_transform,
 )
 
 
-- 
GitLab