From 41960910ee5285f3ca21dc75e7478f9857c6fb37 Mon Sep 17 00:00:00 2001 From: doc-code Date: Sat, 7 Sep 2024 18:34:41 +0200 Subject: [PATCH] Refactor, Add UI preferences, UI updates --- addon/__init__.py | 2 +- addon/classes/funcs.py | 14 +++++++++++++- addon/classes/menu.py | 2 +- addon/classes/ops.py | 11 +++++++---- addon/classes/panel.py | 2 ++ addon/classes/prefs.py | 9 +++++++++ addon/classes/topbar.py | 39 ++++++++++++++++++++++++++------------- 7 files changed, 59 insertions(+), 20 deletions(-) diff --git a/addon/__init__.py b/addon/__init__.py index 22b9dcd..f50e4dd 100644 --- a/addon/__init__.py +++ b/addon/__init__.py @@ -26,7 +26,7 @@ bl_info = { "name": "Scene Workspaces", "tagline": "Filter and reorder workspaces independently for each scene", "blender": (4, 2, 0), - "location": "Workspaces", + "location": "Workspaces topbar, Properties > Scene", "category": ["System", "User Interface", "Scene"], "support": "COMMUNITY", "blender_manifest": "blender_manifest.toml" diff --git a/addon/classes/funcs.py b/addon/classes/funcs.py index c07dc13..c8c6842 100644 --- a/addon/classes/funcs.py +++ b/addon/classes/funcs.py @@ -10,8 +10,20 @@ def get_scene_workspaces(scene = None): else: return [] +def prefs(): + return bpy.context.preferences.addons[base_package].preferences + def get_use_global(): - return bpy.context.preferences.addons[base_package].preferences.use_global + return prefs().use_global + +def get_show_switch(): + return prefs().show_switch + +def get_active_spacing(): + return prefs().active_spacing + +def get_quick_unlink(): + return prefs().quick_unlink def set_scene_workspaces(workspaces): bpy.data.scenes[bpy.context.scene.name]['scene_workspaces'] = workspaces diff --git a/addon/classes/menu.py b/addon/classes/menu.py index 3de9c46..89c9e0e 100644 --- a/addon/classes/menu.py +++ b/addon/classes/menu.py @@ -9,7 +9,7 @@ class SW_MT_copy_from(Menu): layout = self.layout for s in bpy.data.scenes: if s.name != bpy.context.scene.name: - layout.operator("sw.copy_from_scene", text=s.name, icon="SCENE").scene = s.name + layout.operator("sw.copy_from_scene", text=s.name, icon="SCENE_DATA").scene = s.name class SW_MT_missing_workspaces(Menu): bl_label = "Link other workspaces to this scene" diff --git a/addon/classes/ops.py b/addon/classes/ops.py index 04759e5..a3ec9dd 100644 --- a/addon/classes/ops.py +++ b/addon/classes/ops.py @@ -3,15 +3,15 @@ import time import bpy from bpy.types import Operator from bpy.props import StringProperty, BoolProperty, IntProperty -from .funcs import select_all, get_scene_workspaces, set_scene_workspaces, get_use_global, has_data +from .funcs import select_all, get_scene_workspaces, set_scene_workspaces, get_use_global, has_data, prefs class SW_OT_switch(Operator): bl_idname = "sw.switch" - bl_label = "Scene Workspaces On/Off" + bl_label = "Show/Hide Scene Workspaces" bl_description = "Switch workspaces topbar between Scene Workspaces and default" def execute(self, context): - context.preferences.addons[base_package].preferences.use_global = not get_use_global() + prefs().use_global = not get_use_global() context.preferences.is_dirty = True return {'FINISHED'} @@ -113,10 +113,13 @@ class SW_OT_copy_from_scene(Operator): class SW_OT_link_workspace(Operator): bl_idname = "sw.link_workspace" bl_label = "Link Workspace" - bl_description = "Link this workspace to this Scene" workspace: StringProperty(name="workspace") + @classmethod + def description(cls, context, props): + return "This is the active workspace, but it's not linked to this scene. Click to link" if props.workspace == bpy.context.window.workspace.name else "Link this workspace to this Scene" + def execute(self, context): if not has_data(): set_scene_workspaces([]) diff --git a/addon/classes/panel.py b/addon/classes/panel.py index e709b62..310aa37 100644 --- a/addon/classes/panel.py +++ b/addon/classes/panel.py @@ -8,6 +8,7 @@ class SW_PT_select_scene_workspaces(Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = "scene" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout @@ -17,6 +18,7 @@ class SW_PT_select_scene_workspaces(Panel): box = layout.box() if not sw: box.label(text="There are no workspaces linked right now...") + box.operator("sw.link_all") else: i = 0 for w in sw: diff --git a/addon/classes/prefs.py b/addon/classes/prefs.py index 1b321fb..59be653 100644 --- a/addon/classes/prefs.py +++ b/addon/classes/prefs.py @@ -7,8 +7,17 @@ class SWPreferences(AddonPreferences): bl_idname = base_package use_global: BoolProperty(name="Use default workspaces", description="Switch the workspace topbar between Scene Workspaces and the default one", default=False) + show_switch: BoolProperty(name="Show Switch", description="Show/Hide the switch button next to the workspaces topbar. Useful for quickly lookup the original workspaces topbar", default=True) + active_spacing: BoolProperty(name="Active workspace spacing", description="Add space around the active workspace", default=True) + quick_unlink: BoolProperty(name="Show Quick Unlink", description="Show/Hide the unlink button at left of the active workspace", default=True) def draw(self, context): layout = self.layout layout.prop(self, "use_global") + layout.prop(self, "show_switch") + + box = layout.box() + box.label("UI Options") + box.prop(self, "quick_unlink") + box.prop(self, "active_spacing") \ No newline at end of file diff --git a/addon/classes/topbar.py b/addon/classes/topbar.py index f4e0b89..41a7ddb 100644 --- a/addon/classes/topbar.py +++ b/addon/classes/topbar.py @@ -1,7 +1,7 @@ from .. import __package__ as base_package import bpy from bpy.types import Header, Panel -from .funcs import get_scene_workspaces, get_use_global +from .funcs import get_scene_workspaces, get_use_global, get_show_switch, get_quick_unlink, get_active_spacing # Ref TOPBAR_HT_upper_bar https://projects.blender.org/blender/blender/src/commit/2204157a2c9fc926643b0e39968602c750d9b5e6/scripts/startup/bl_ui/space_topbar.py#L14 class TOPBAR_HT_upper_bar(Header): @@ -29,6 +29,8 @@ class TOPBAR_HT_upper_bar(Header): # Edited use_global = get_use_global() + quick_unlink = get_quick_unlink() + active_spacing = get_active_spacing() if not screen.show_fullscreen: main_col = layout.column() @@ -36,10 +38,11 @@ class TOPBAR_HT_upper_bar(Header): spacer_row.scale_y = .33 main_row = main_col.row() sy = 1.18 - sx = 1.1 - col = main_row.column() - col.scale_y = sy - col.operator("sw.switch", text="", emboss=False, icon="RADIOBUT_OFF" if use_global else "RADIOBUT_ON") + sx = 1.12 + if get_show_switch(): + col = main_row.column() + # Show/Hide Custom Topbar + col.operator("sw.switch", text="", emboss=False, icon="CHECKBOX_DEHLT" if use_global else "CHECKBOX_HLT") if use_global: # Original layout.template_ID_tabs(window, "workspace", new="workspace.add", menu="TOPBAR_MT_workspace_menu") @@ -48,6 +51,7 @@ class TOPBAR_HT_upper_bar(Header): r.scale_x = 0.87 r.scale_y = sy ws = get_scene_workspaces() + # Link all (with no linked workspaces) if not ws and bpy.data.workspaces: c = r.column() c.scale_x = 1.4 @@ -56,42 +60,51 @@ class TOPBAR_HT_upper_bar(Header): for w in ws: i = ws.index(w) active = bpy.context.window.workspace.name == w - if active and i > 0: + if active and i > 0 and active_spacing: r.separator() ab = r.box() ab = ab.row(align=True) - if active: + # Workspace unlink + if active and quick_unlink: col = ab.column() col.scale_x = sx col.operator("sw.remove", text="", icon="X", emboss=False).index = i exist = w in [x.name for x in bpy.data.workspaces] + # Workspace ab.operator("sw.workspace", text=w, icon="NONE" if exist else "ERROR", emboss=active, depress=active).workspace = w + # Active workspace options if active: col = ab.column() col.scale_x = sx col.menu("TOPBAR_MT_workspace_menu", text="", icon="OPTIONS") active_not_here = False - r.separator() + if active_spacing: + r.separator() + # Link other workspaces if [x for x in bpy.data.workspaces if x.name not in get_scene_workspaces()]: c = r.column() c.scale_x = sx - c.menu("SW_MT_missing_workspaces", text="", icon="THREE_DOTS") - c = r.column() - c.scale_x = sx - c.operator("workspace.add", text="", icon="ADD") + c.menu("SW_MT_missing_workspaces", text="", icon="WORKSPACE") + # Duplicate linked workspaces from other scenes if len(bpy.data.scenes) > 1: c = r.column() c.scale_x = sx c.menu("SW_MT_copy_from", text="", icon="DUPLICATE") + # Original Add Workspace menu + c = r.column() + c.scale_x = sx + c.operator("workspace.add", text="", icon="ADD") + # Active (but not linked) workspace if active_not_here: r.separator() r = r.box() r = r.row(align=True) b = r.box() b.scale_x = sx - b.operator("sw.link_workspace", text=f"{bpy.context.window.workspace.name} (not linked)", icon="ADD", emboss=True, depress=True).workspace = bpy.context.window.workspace.name + b.operator("sw.link_workspace", text=f"{bpy.context.window.workspace.name} (link)", icon="LINKED", emboss=True, depress=True).workspace = bpy.context.window.workspace.name + # Active workspace options col = r.box() col.scale_x = sx col.menu("TOPBAR_MT_workspace_menu", text="", icon="OPTIONS")