diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2019-09-03 16:43:38 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2019-09-03 17:10:40 +0300 |
commit | ee8f69c96cba62b083fb089432cddd0bce5d08e1 (patch) | |
tree | 3be49501a9174fcf6d271ac2a3938a6304abddfb /release/scripts/startup/bl_ui/space_filebrowser.py | |
parent | 545f565426562604eeaa84c6f098a4dda829ba0a (diff) |
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
Diffstat (limited to 'release/scripts/startup/bl_ui/space_filebrowser.py')
-rw-r--r-- | release/scripts/startup/bl_ui/space_filebrowser.py | 354 |
1 files changed, 304 insertions, 50 deletions
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index b939586ff81..e9c11301909 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -34,58 +34,131 @@ class FILEBROWSER_HT_header(Header): layout.menu("FILEBROWSER_MT_view") - row = layout.row(align=True) - row.operator("file.previous", text="", icon='BACK') - row.operator("file.next", text="", icon='FORWARD') - row.operator("file.parent", text="", icon='FILE_PARENT') - row.operator("file.refresh", text="", icon='FILE_REFRESH') + # can be None when save/reload with a file selector open - layout.operator_context = 'EXEC_DEFAULT' - layout.operator("file.directory_new", icon='NEWFOLDER', text="") + layout.separator_spacer() - layout.operator_context = 'INVOKE_DEFAULT' + layout.template_running_jobs() + + +class FILEBROWSER_PT_display(Panel): + bl_space_type = 'FILE_BROWSER' + bl_region_type = 'HEADER' + bl_label = "Display" + @classmethod + def poll(cls, context): # can be None when save/reload with a file selector open - if params: - is_lib_browser = params.use_library_browsing + return context.space_data.params is not None - layout.prop(params, "display_type", expand=True, text="") - layout.prop(params, "sort_method", expand=True, text="") - layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN') + def draw(self, context): + layout = self.layout - layout.separator_spacer() + space = context.space_data + params = space.params + is_lib_browser = params.use_library_browsing - layout.template_running_jobs() + layout.label(text="Display as") + layout.column().prop(params, "display_type", expand=True) - if params: - layout.prop(params, "use_filter", text="", icon='FILTER') + layout.use_property_split = True + layout.use_property_decorate = False # No animation. - row = layout.row(align=True) - row.active = params.use_filter - row.prop(params, "use_filter_folder", text="") + if params.display_type == 'THUMBNAIL': + layout.prop(params, "display_size", text="Size") + else: + layout.prop(params, "show_details_size", text="Size") + layout.prop(params, "show_details_datetime", text="Date") - if params.filter_glob: - # if st.active_operator and hasattr(st.active_operator, "filter_glob"): - # row.prop(params, "filter_glob", text="") - row.label(text=params.filter_glob) - else: - row.prop(params, "use_filter_blender", text="") - row.prop(params, "use_filter_backup", text="") - row.prop(params, "use_filter_image", text="") - row.prop(params, "use_filter_movie", text="") - row.prop(params, "use_filter_script", text="") - row.prop(params, "use_filter_font", text="") - row.prop(params, "use_filter_sound", text="") - row.prop(params, "use_filter_text", text="") + layout.prop(params, "recursion_level", text="Recursions") - if is_lib_browser: - row.prop(params, "use_filter_blendid", text="") - if params.use_filter_blendid: - row.separator() - row.prop(params, "filter_id_category", text="") + layout.use_property_split = False + layout.separator() + + layout.label(text="Sort by") + layout.column().prop(params, "sort_method", expand=True) + layout.prop(params, "use_sort_invert") - row.separator() - row.prop(params, "filter_search", text="", icon='VIEWZOOM') + +class FILEBROWSER_PT_filter(Panel): + bl_space_type = 'FILE_BROWSER' + bl_region_type = 'HEADER' + bl_label = "Filter" + + @classmethod + def poll(cls, context): + # can be None when save/reload with a file selector open + return context.space_data.params is not None + + def draw(self, context): + layout = self.layout + + space = context.space_data + params = space.params + is_lib_browser = params.use_library_browsing + + row = layout.row(align=True) + row.prop(params, "use_filter", text="", toggle=0) + row.label(text="Filter") + + col = layout.column() + col.active = params.use_filter + + row = col.row() + row.label(icon='FILE_FOLDER') + row.prop(params, "use_filter_folder", text="Folders", toggle=0) + + if params.filter_glob: + col.label(text=params.filter_glob) + else: + row = col.row() + row.label(icon='FILE_BLEND') + row.prop(params, "use_filter_blender", + text=".blend Files", toggle=0) + row = col.row() + row.label(icon='FILE_BACKUP') + row.prop(params, "use_filter_backup", + text="Backup .blend Files", toggle=0) + row = col.row() + row.label(icon='FILE_IMAGE') + row.prop(params, "use_filter_image", text="Image Files", toggle=0) + row = col.row() + row.label(icon='FILE_MOVIE') + row.prop(params, "use_filter_movie", text="Movie Files", toggle=0) + row = col.row() + row.label(icon='FILE_SCRIPT') + row.prop(params, "use_filter_script", + text="Script Files", toggle=0) + row = col.row() + row.label(icon='FILE_FONT') + row.prop(params, "use_filter_font", text="Font Files", toggle=0) + row = col.row() + row.label(icon='FILE_SOUND') + row.prop(params, "use_filter_sound", text="Sound Files", toggle=0) + row = col.row() + row.label(icon='FILE_TEXT') + row.prop(params, "use_filter_text", text="Text Files", toggle=0) + + col.separator() + + if is_lib_browser: + row = col.row() + row.label(icon='BLANK1') # Indentation + row.prop(params, "use_filter_blendid", + text="Blender IDs", toggle=0) + if params.use_filter_blendid: + row = col.row() + row.label(icon='BLANK1') # Indentation + row.prop(params, "filter_id_category", text="") + + col.separator() + + layout.prop(params, "show_hidden") + + +def panel_poll_is_upper_region(region): + # The upper region is left-aligned, the lower is split into it then. + return region.alignment == 'LEFT' class FILEBROWSER_UL_dir(UIList): @@ -119,10 +192,13 @@ class FILEBROWSER_UL_dir(UIList): class FILEBROWSER_PT_bookmarks_volumes(Panel): bl_space_type = 'FILE_BROWSER' bl_region_type = 'TOOLS' - bl_options = {'DEFAULT_CLOSED'} bl_category = "Bookmarks" bl_label = "Volumes" + @classmethod + def poll(cls, context): + return panel_poll_is_upper_region(context.region) + def draw(self, context): layout = self.layout space = context.space_data @@ -141,7 +217,7 @@ class FILEBROWSER_PT_bookmarks_system(Panel): @classmethod def poll(cls, context): - return not context.preferences.filepaths.hide_system_bookmarks + return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region) def draw(self, context): layout = self.layout @@ -161,8 +237,10 @@ class FILEBROWSER_MT_bookmarks_context_menu(Menu): layout.operator("file.bookmark_cleanup", icon='X', text="Cleanup") layout.separator() - layout.operator("file.bookmark_move", icon='TRIA_UP_BAR', text="Move To Top").direction = 'TOP' - layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR', text="Move To Bottom").direction = 'BOTTOM' + layout.operator("file.bookmark_move", icon='TRIA_UP_BAR', + text="Move To Top").direction = 'TOP' + layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR', + text="Move To Bottom").direction = 'BOTTOM' class FILEBROWSER_PT_bookmarks_favorites(Panel): @@ -171,6 +249,10 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel): bl_category = "Bookmarks" bl_label = "Favorites" + @classmethod + def poll(cls, context): + return panel_poll_is_upper_region(context.region) + def draw(self, context): layout = self.layout space = context.space_data @@ -185,12 +267,15 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel): col = row.column(align=True) col.operator("file.bookmark_add", icon='ADD', text="") col.operator("file.bookmark_delete", icon='REMOVE', text="") - col.menu("FILEBROWSER_MT_bookmarks_context_menu", icon='DOWNARROW_HLT', text="") + col.menu("FILEBROWSER_MT_bookmarks_context_menu", + icon='DOWNARROW_HLT', text="") if num_rows > 1: col.separator() - col.operator("file.bookmark_move", icon='TRIA_UP', text="").direction = 'UP' - col.operator("file.bookmark_move", icon='TRIA_DOWN', text="").direction = 'DOWN' + col.operator("file.bookmark_move", icon='TRIA_UP', + text="").direction = 'UP' + col.operator("file.bookmark_move", icon='TRIA_DOWN', + text="").direction = 'DOWN' else: layout.operator("file.bookmark_add", icon='ADD') @@ -203,7 +288,7 @@ class FILEBROWSER_PT_bookmarks_recents(Panel): @classmethod def poll(cls, context): - return not context.preferences.filepaths.hide_recent_locations + return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region) def draw(self, context): layout = self.layout @@ -227,7 +312,7 @@ class FILEBROWSER_PT_advanced_filter(Panel): @classmethod def poll(cls, context): # only useful in append/link (library) context currently... - return context.space_data.params.use_library_browsing + return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region) def draw(self, context): layout = self.layout @@ -242,6 +327,133 @@ class FILEBROWSER_PT_advanced_filter(Panel): col.prop(params, "filter_id") +class FILEBROWSER_PT_options_toggle(Panel): + bl_space_type = 'FILE_BROWSER' + bl_region_type = 'TOOLS' + bl_label = "Options Toggle" + bl_options = {'HIDE_HEADER'} + + @classmethod + def poll(cls, context): + sfile = context.space_data + return context.region.alignment == 'BOTTOM' and sfile.active_operator + + def is_option_region_visible(self, context): + for region in context.area.regions: + if region.type == 'TOOL_PROPS' and region.width <= 1: + return False + + return True + + def draw(self, context): + layout = self.layout + label = "Hide Options" if self.is_option_region_visible( + context) else "Options" + + layout.scale_x = 1.3 + layout.scale_y = 1.3 + + layout.operator("screen.region_toggle", + text=label).region_type = 'TOOL_PROPS' + + +class FILEBROWSER_PT_directory_path(Panel): + bl_space_type = 'FILE_BROWSER' + bl_region_type = 'UI' + bl_label = "Directory Path" + bl_category = "Attributes" + bl_options = {'HIDE_HEADER'} + + def is_header_visible(self, context): + for region in context.area.regions: + if region.type == 'HEADER' and region.height <= 1: + return False + + return True + + def draw(self, context): + layout = self.layout + space = context.space_data + params = space.params + + layout.scale_x = 1.3 + layout.scale_y = 1.3 + + row = layout.row() + + subrow = row.row(align=True) + subrow.operator("file.previous", text="", icon='BACK') + subrow.operator("file.next", text="", icon='FORWARD') + subrow.operator("file.parent", text="", icon='FILE_PARENT') + subrow.operator("file.refresh", text="", icon='FILE_REFRESH') + + row.operator("file.directory_new", icon='NEWFOLDER', text="") + + subrow = row.row() + subrow.prop(params, "directory", text="") + + subrow = row.row() + subrow.scale_x = 0.5 + subrow.prop(params, "filter_search", text="", icon='VIEWZOOM') + + # Uses prop_with_popover() as popover() only adds the triangle icon in headers. + row.prop_with_popover( + params, + "display_type", + panel="FILEBROWSER_PT_display", + text="", + icon_only=True, + ) + row.prop_with_popover( + params, + "display_type", + panel="FILEBROWSER_PT_filter", + text="", + icon='FILTER', + icon_only=True, + ) + + +class FILEBROWSER_PT_file_operation(Panel): + bl_space_type = 'FILE_BROWSER' + bl_region_type = 'EXECUTE' + bl_label = "Execute File Operation" + bl_options = {'HIDE_HEADER'} + + @classmethod + def poll(cls, context): + return context.space_data.active_operator + + def draw(self, context): + import sys + + layout = self.layout + space = context.space_data + params = space.params + + layout.scale_x = 1.3 + layout.scale_y = 1.3 + + row = layout.row() + sub = row.row() + sub.prop(params, "filename", text="") + sub = row.row() + sub.ui_units_x = 5 + + # subsub = sub.row(align=True) + # subsub.operator("file.filenum", text="", icon='ADD').increment = 1 + # subsub.operator("file.filenum", text="", icon='REMOVE').increment = -1 + + # organize buttons according to the OS standard + if sys.platform != "win": + sub.operator("FILE_OT_cancel", text="Cancel") + subsub = sub.row() + subsub.active_default = True + subsub.operator("FILE_OT_execute", text=params.title) + if sys.platform == "win": + sub.operator("FILE_OT_cancel", text="Cancel") + + class FILEBROWSER_MT_view(Menu): bl_label = "View" @@ -250,7 +462,7 @@ class FILEBROWSER_MT_view(Menu): st = context.space_data params = st.params - layout.prop(st, "show_region_toolbar") + layout.prop(st, "show_region_toolbar", text="Source List") layout.prop(st, "show_region_ui", text="File Path") layout.separator() @@ -263,8 +475,46 @@ class FILEBROWSER_MT_view(Menu): layout.menu("INFO_MT_area") +class FILEBROWSER_MT_context_menu(Menu): + bl_label = "Files Context Menu" + + def draw(self, context): + layout = self.layout + st = context.space_data + params = st.params + + layout.operator("file.previous", text="Back") + layout.operator("file.next", text="Forward") + layout.operator("file.parent", text="Go to Parent") + layout.operator("file.refresh", text="Refresh") + + layout.separator() + + layout.operator("file.filenum", text="Increase Number", + icon='ADD').increment = 1 + layout.operator("file.filenum", text="Decrease Number", + icon='REMOVE').increment = -1 + + layout.separator() + + layout.operator("file.rename", text="Rename") + # layout.operator("file.delete") + layout.operator("file.directory_new", text="New Folder") + layout.operator("file.bookmark_add", text="Add Bookmark") + + layout.separator() + + layout.prop_menu_enum(params, "display_type") + if params.display_type == 'THUMBNAIL': + layout.prop_menu_enum(params, "display_size") + layout.prop_menu_enum(params, "recursion_level", text="Recursions") + layout.prop_menu_enum(params, "sort_method") + + classes = ( FILEBROWSER_HT_header, + FILEBROWSER_PT_display, + FILEBROWSER_PT_filter, FILEBROWSER_UL_dir, FILEBROWSER_PT_bookmarks_volumes, FILEBROWSER_PT_bookmarks_system, @@ -272,7 +522,11 @@ classes = ( FILEBROWSER_PT_bookmarks_favorites, FILEBROWSER_PT_bookmarks_recents, FILEBROWSER_PT_advanced_filter, + FILEBROWSER_PT_directory_path, + FILEBROWSER_PT_file_operation, + FILEBROWSER_PT_options_toggle, FILEBROWSER_MT_view, + FILEBROWSER_MT_context_menu, ) if __name__ == "__main__": # only for live edit. |