diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2018-04-20 18:14:03 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2018-04-20 18:14:52 +0300 |
commit | 5f6c45498c92b91a710a1317f6d41f73fbe83477 (patch) | |
tree | 93b136fb49c656c2c2a5463c91e8a6a38d518354 /release | |
parent | 4bfb6d21df96688187f6f1a5d95dd62bcbf85116 (diff) |
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/startup/bl_ui/__init__.py | 1 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_topbar.py | 401 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_userpref.py | 3 |
3 files changed, 405 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 5c50cb74fdb..2c0b1ab12be 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -84,6 +84,7 @@ _modules = [ "space_sequencer", "space_text", "space_time", + "space_topbar", "space_userpref", "space_view3d", "space_view3d_toolbar", diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py new file mode 100644 index 00000000000..7ce512ebb2a --- /dev/null +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -0,0 +1,401 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import bpy +from bpy.types import Header, Menu, Panel + + +class TOPBAR_HT_upper_bar(Header): + bl_space_type = 'TOPBAR' + + def draw(self, context): + region = context.region + + if region.alignment == 'RIGHT': + self.draw_right(context) + else: + self.draw_left(context) + + def draw_left(self, context): + layout = self.layout + + window = context.window + screen = context.screen + + layout.operator("wm.splash", text="", icon='BLENDER', emboss=False) + + TOPBAR_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator() + + if not screen.show_fullscreen: + layout.template_ID_tabs(window, "workspace", new="workspace.workspace_add_menu", unlink="workspace.workspace_delete") + + layout.separator() + + layout.template_running_jobs() + + layout.template_reports_banner() + + row = layout.row(align=True) + + if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False: + row.label("Auto-run disabled", icon='ERROR') + if bpy.data.is_saved: + props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted") + props.use_scripts = True + + row.operator("script.autoexec_warn_clear", text="Ignore") + + # include last so text doesn't push buttons out of the header + row.label(bpy.app.autoexec_fail_message) + return + + def draw_right(self, context): + layout = self.layout + + window = context.window + + layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete") + + +class TOPBAR_HT_lower_bar(Header): + bl_space_type = 'TOPBAR' + bl_region_type = 'WINDOW' + + def draw(self, context): + layout = self.layout + region = context.region + + if region.alignment == 'LEFT': + self.draw_left(context) + elif region.alignment == 'RIGHT': + self.draw_right(context) + else: + # WITH_REDO_REGION_REMOVAL: + # layout.template_operator_redo_props() + pass + + def draw_left(self, context): + layout = self.layout + layer = context.view_layer + + act_mode_item = bpy.types.Object.bl_rna.properties['mode'].enum_items[layer.objects.active.mode] + layout.operator_menu_enum("object.mode_set", "mode", text=act_mode_item.name, icon=act_mode_item.icon) + + + def draw_right(self, context): + layout = self.layout + + window = context.window + workspace = context.workspace + scene = context.scene + screen = context.screen + + if screen.show_fullscreen: + layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous") + else: + layout.template_search_preview(window, "screen", workspace, "screens", new="screen.new", unlink="screen.delete", rows=2, cols=6) + # Active workspace view-layer is retrieved through window, not through workspace. + layout.template_search(window, "view_layer", scene, "view_layers") + + +class TOPBAR_MT_editor_menus(Menu): + bl_idname = "TOPBAR_MT_editor_menus" + bl_label = "" + + def draw(self, context): + self.draw_menus(self.layout, context) + + @staticmethod + def draw_menus(layout, context): + layout.menu("TOPBAR_MT_file") + + layout.menu("TOPBAR_MT_render") + + layout.menu("TOPBAR_MT_window") + layout.menu("TOPBAR_MT_help") + + +class TOPBAR_MT_file(Menu): + bl_label = "File" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.read_homefile", text="New", icon='NEW') + layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER') + layout.menu("TOPBAR_MT_file_open_recent", icon='OPEN_RECENT') + layout.operator("wm.revert_mainfile", icon='FILE_REFRESH') + layout.operator("wm.recover_last_session", icon='RECOVER_LAST') + layout.operator("wm.recover_auto_save", text="Recover Auto Save...", icon='RECOVER_AUTO') + + layout.separator() + + layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA' + layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK') + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.save_as_mainfile", text="Save As...", icon='SAVE_AS') + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.save_as_mainfile", text="Save Copy...", icon='SAVE_COPY').copy = True + + layout.separator() + + layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES') + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.save_homefile", icon='SAVE_PREFS') + layout.operator("wm.read_factory_settings", icon='LOAD_FACTORY') + + layout.separator() + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.link", text="Link", icon='LINK_BLEND') + layout.operator("wm.append", text="Append", icon='APPEND_BLEND') + layout.menu("TOPBAR_MT_file_previews") + + layout.separator() + + layout.menu("TOPBAR_MT_file_import", icon='IMPORT') + layout.menu("TOPBAR_MT_file_export", icon='EXPORT') + + layout.separator() + + layout.menu("TOPBAR_MT_file_external_data", icon='EXTERNAL_DATA') + + layout.separator() + + layout.operator_context = 'EXEC_AREA' + if bpy.data.is_dirty and context.user_preferences.view.use_quit_dialog: + layout.operator_context = 'INVOKE_SCREEN' # quit dialog + layout.operator("wm.quit_blender", text="Quit", icon='QUIT') + + +class TOPBAR_MT_file_import(Menu): + bl_idname = "TOPBAR_MT_file_import" + bl_label = "Import" + + def draw(self, context): + if bpy.app.build_options.collada: + self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)") + if bpy.app.build_options.alembic: + self.layout.operator("wm.alembic_import", text="Alembic (.abc)") + + +class TOPBAR_MT_file_export(Menu): + bl_idname = "TOPBAR_MT_file_export" + bl_label = "Export" + + def draw(self, context): + if bpy.app.build_options.collada: + self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") + if bpy.app.build_options.alembic: + self.layout.operator("wm.alembic_export", text="Alembic (.abc)") + + +class TOPBAR_MT_file_external_data(Menu): + bl_label = "External Data" + + def draw(self, context): + layout = self.layout + + icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT' + layout.operator("file.autopack_toggle", icon=icon) + + layout.separator() + + pack_all = layout.row() + pack_all.operator("file.pack_all") + pack_all.active = not bpy.data.use_autopack + + unpack_all = layout.row() + unpack_all.operator("file.unpack_all") + unpack_all.active = not bpy.data.use_autopack + + layout.separator() + + layout.operator("file.make_paths_relative") + layout.operator("file.make_paths_absolute") + layout.operator("file.report_missing_files") + layout.operator("file.find_missing_files") + + +class TOPBAR_MT_file_previews(Menu): + bl_label = "Data Previews" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.previews_ensure") + layout.operator("wm.previews_batch_generate") + + layout.separator() + + layout.operator("wm.previews_clear") + layout.operator("wm.previews_batch_clear") + + +class TOPBAR_MT_game(Menu): + bl_label = "Game" + + def draw(self, context): + layout = self.layout + + gs = context.scene.game_settings + + layout.operator("view3d.game_start") + + layout.separator() + + layout.prop(gs, "show_debug_properties") + layout.prop(gs, "show_framerate_profile") + layout.prop(gs, "show_physics_visualization") + layout.prop(gs, "use_deprecation_warnings") + layout.prop(gs, "use_animation_record") + layout.separator() + layout.prop(gs, "use_auto_start") + + +class TOPBAR_MT_render(Menu): + bl_label = "Render" + + def draw(self, context): + layout = self.layout + + layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True + props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION') + props.animation = True + props.use_viewport = True + + layout.separator() + + layout.operator("render.opengl", text="OpenGL Render Image") + layout.operator("render.opengl", text="OpenGL Render Animation").animation = True + layout.menu("TOPBAR_MT_opengl_render") + + layout.separator() + + layout.operator("render.view_show") + layout.operator("render.play_rendered_anim", icon='PLAY') + + +class TOPBAR_MT_opengl_render(Menu): + bl_label = "OpenGL Render Options" + + def draw(self, context): + layout = self.layout + + rd = context.scene.render + layout.prop(rd, "use_antialiasing") + layout.prop(rd, "use_full_sample") + + layout.prop_menu_enum(rd, "antialiasing_samples") + layout.prop_menu_enum(rd, "alpha_mode") + + +class TOPBAR_MT_window(Menu): + bl_label = "Window" + + def draw(self, context): + import sys + + layout = self.layout + + layout.operator("wm.window_new") + layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER') + + layout.separator() + + layout.operator("screen.screenshot") + layout.operator("screen.screencast") + + if sys.platform[:3] == "win": + layout.separator() + layout.operator("wm.console_toggle", icon='CONSOLE') + + if context.scene.render.use_multiview: + layout.separator() + layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO') + + +class TOPBAR_MT_help(Menu): + bl_label = "Help" + + def draw(self, context): + layout = self.layout + + layout.operator( + "wm.url_open", text="Manual", icon='HELP', + ).url = "https://docs.blender.org/manual/en/dev/" + layout.operator( + "wm.url_open", text="Release Log", icon='URL', + ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2] + layout.separator() + + layout.operator( + "wm.url_open", text="Blender Website", icon='URL', + ).url = "https://www.blender.org" + layout.operator( + "wm.url_open", text="Blender Store", icon='URL', + ).url = "https://store.blender.org" + layout.operator( + "wm.url_open", text="Developer Community", icon='URL', + ).url = "https://www.blender.org/get-involved/" + layout.operator( + "wm.url_open", text="User Community", icon='URL', + ).url = "https://www.blender.org/support/user-community" + layout.separator() + layout.operator( + "wm.url_open", text="Report a Bug", icon='URL', + ).url = "https://developer.blender.org/maniphest/task/edit/form/1" + layout.separator() + + layout.operator( + "wm.url_open", text="Python API Reference", icon='URL', + ).url = bpy.types.WM_OT_doc_view._prefix + + layout.operator("wm.operator_cheat_sheet", icon='TEXT') + layout.operator("wm.sysinfo", icon='TEXT') + layout.separator() + + layout.operator("wm.splash", icon='BLENDER') + + +classes = ( + TOPBAR_HT_upper_bar, + TOPBAR_HT_lower_bar, + TOPBAR_MT_editor_menus, + TOPBAR_MT_file, + TOPBAR_MT_file_import, + TOPBAR_MT_file_export, + TOPBAR_MT_file_external_data, + TOPBAR_MT_file_previews, + TOPBAR_MT_game, + TOPBAR_MT_render, + TOPBAR_MT_opengl_render, + TOPBAR_MT_window, + TOPBAR_MT_help, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 953ebba54ca..9afda6b77bf 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -853,6 +853,9 @@ class USERPREF_PT_theme(Panel): col.label(text="List Item:") self._theme_widget_style(col, ui.wcol_list_item) + col.label(text="Tab:") + self._theme_widget_style(col, ui.wcol_tab) + ui_state = theme.user_interface.wcol_state col.label(text="State:") |