Update preference using compact, add compact mode switch in menu

This commit is contained in:
Francesco Bellini 2024-09-08 18:27:02 +02:00
parent a61b819400
commit cddbef9f62
10 changed files with 168 additions and 153 deletions

View File

@ -14,20 +14,20 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import bpy
from .classes.funcs import select_all, draw_workspace_menu
from .classes.ops import SW_OT_workspace, SW_OT_link_workspace, SW_OT_move, SW_OT_link_all, SW_OT_remove, SW_OT_switch, SW_OT_rename, SW_OT_copy_from_scene
from .classes.topbar import TOPBAR_HT_upper_bar
from .classes.panel import SW_PT_select_scene_workspaces
from .classes.menu import SW_MT_missing_workspaces, SW_MT_copy_from
from .classes.prefs import SWPreferences
from .sw.funcs import select_all, workspace_menu
from .sw.ops import SW_OT_workspace, SW_OT_link_workspace, SW_OT_move, SW_OT_link_all, SW_OT_remove, SW_OT_switch, SW_OT_rename, SW_OT_copy_from_scene
from .sw.topbar import TOPBAR_HT_upper_bar
from .sw.panel import SW_PT_select_scene_workspaces
from .sw.menu import SW_MT_missing_workspaces, SW_MT_copy_from
from .sw.prefs import SW_Preferences
bl_info = {
"id": "scene_workspaces",
"name": "Scene Workspaces",
"tagline": "Filter and rearrange workspaces individually for each scene",
"tagline": "Filter and sort your workspaces for each scene independently",
"blender": (4, 2, 0),
"location": "Workspaces topbar, Properties > Scene",
"category": ["System", "User Interface", "Scene"],
"category": ["Scene", "System", "User Interface"],
"support": "COMMUNITY",
"blender_manifest": "blender_manifest.toml"
}
@ -37,14 +37,14 @@ classes = [
SW_OT_switch,
SW_OT_move,
SW_OT_remove,
SW_OT_link_all,
SW_OT_link_workspace,
SW_OT_rename,
SW_OT_link_workspace,
SW_OT_link_all,
SW_OT_copy_from_scene,
SW_MT_missing_workspaces,
SW_MT_copy_from,
SW_MT_missing_workspaces,
SW_PT_select_scene_workspaces,
SWPreferences,
SW_Preferences,
TOPBAR_HT_upper_bar
]
@ -55,13 +55,13 @@ def register():
og_header = bpy.types.TOPBAR_HT_upper_bar;
for c in classes:
bpy.utils.register_class(c)
bpy.types.TOPBAR_MT_workspace_menu.prepend(draw_workspace_menu)
bpy.types.TOPBAR_MT_workspace_menu.prepend(workspace_menu)
def unregister():
for c in reversed(classes):
bpy.utils.unregister_class(c)
bpy.utils.register_class(og_header)
bpy.types.TOPBAR_MT_workspace_menu.remove(draw_workspace_menu)
bpy.types.TOPBAR_MT_workspace_menu.remove(workspace_menu)
if __name__ == "__main__":
register()

View File

@ -2,7 +2,7 @@ schema_version = "1.0.0"
id = "scene_workspaces"
version = "1.0.0"
name = "Scene Workspaces"
tagline = "Filter and rearrange workspaces individually for each scene"
tagline = "Filter and sort your workspaces for each scene independently"
maintainer = "Francesco Bellini <doc.open.dev@gmail.com>"
type = "add-on"
website = "https://projects.blender.org/Francesco-Bellini/scene_workspaces_addon"

View File

@ -1,74 +0,0 @@
import bpy
from .. import __package__ as base_package
def has_data():
return 'scene_workspaces' in bpy.data.scenes[bpy.context.scene.name]
def get_scene_workspaces(scene = None):
if has_data():
return bpy.data.scenes[scene if scene else bpy.context.scene.name]['scene_workspaces']
else:
return []
def prefs():
return bpy.context.preferences.addons[base_package].preferences
def get_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
def select_all():
workspaces = []
for w in bpy.data.workspaces:
workspaces.append(w.name)
set_scene_workspaces(workspaces)
def get_other_scene_names():
return [s.name for s in bpy.data.scenes if s.name != bpy.context.scene.name]
def draw_workspace_ops(layout, i, text=False, name=None):
layout.separator()
remove = layout.operator(
"sw.remove", text="Unlink workspace from scene" if text else "", icon='X')
remove.index = i
layout.separator()
rename = layout.operator(
"sw.rename", text="Rename" if text else "", icon="TEXT")
rename.current_name = name if name else bpy.context.window.workspace.name
rename.new_name = rename.current_name
layout.separator()
top = layout.operator("sw.move", text="Reorder to Front" if text else "",
icon='TRIA_LEFT_BAR' if text else 'TRIA_UP_BAR')
top.index = i
top.top = True
up = layout.operator("sw.move", text="Move Left" if text else "",
icon='TRIA_LEFT' if text else 'TRIA_UP')
up.index = i
up.up = 1
down = layout.operator("sw.move", text="Move Right" if text else "",
icon='TRIA_RIGHT' if text else 'TRIA_DOWN')
down.index = i
down.up = -1
bottom = layout.operator("sw.move", text="Reorder to Back" if text else "",
icon='TRIA_RIGHT_BAR' if text else 'TRIA_DOWN_BAR')
bottom.index = i
bottom.top = False
def draw_workspace_menu(self, context):
layout = self.layout
use_global = get_use_global()
if not use_global and has_data():
draw_workspace_ops(layout, get_scene_workspaces().index(
context.window.workspace.name), True)
layout.separator()

View File

@ -1,23 +0,0 @@
import bpy
from bpy.types import AddonPreferences
from bpy.props import BoolProperty
from .. import __package__ as base_package
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(text="UI Options")
box.prop(self, "quick_unlink")
box.prop(self, "active_spacing")

80
addon/sw/funcs.py Normal file
View File

@ -0,0 +1,80 @@
from .. import __package__ as base_package
import bpy
def has_data():
return 'scene_workspaces' in bpy.data.scenes[bpy.context.scene.name]
def get_scene_workspaces(scene = None):
if has_data():
return bpy.data.scenes[scene if scene else bpy.context.scene.name]['scene_workspaces']
else:
return []
def prefs():
return bpy.context.preferences.addons[base_package].preferences
def get_use_topbar():
return prefs().use_topbar
def get_switch():
return prefs().switch
def get_compact():
return prefs().compact
def set_scene_workspaces(workspaces, scene = None):
bpy.data.scenes[scene if scene else bpy.context.scene.name]['scene_workspaces'] = workspaces
def select_all():
workspaces = []
for w in bpy.data.workspaces:
workspaces.append(w.name)
set_scene_workspaces(workspaces)
def get_other_scene_names():
return [s.name for s in bpy.data.scenes if s.name != bpy.context.scene.name]
def workspace_ops(layout, i, menu_mode=False, name=None):
layout.separator()
if menu_mode:
layout.prop(prefs(), "compact", text="Compact Mode")
layout.separator()
def remove(l):
remove = l.operator(
"sw.remove", text="Unlink workspace from scene" if menu_mode else "", icon='X')
remove.index = i
if menu_mode:
remove(layout)
layout.separator()
rename = layout.operator(
"sw.rename", text="Rename" if menu_mode else "", icon="TEXT")
rename.current_name = name if name else bpy.context.window.workspace.name
rename.new_name = rename.current_name
layout.separator()
top = layout.operator("sw.move", text="Reorder to Front" if menu_mode else "",
icon='TRIA_LEFT_BAR' if menu_mode else 'TRIA_UP_BAR')
top.index = i
top.top = True
up = layout.operator("sw.move", text="Move Left" if menu_mode else "",
icon='TRIA_LEFT' if menu_mode else 'TRIA_UP')
up.index = i
up.up = 1
down = layout.operator("sw.move", text="Move Right" if menu_mode else "",
icon='TRIA_RIGHT' if menu_mode else 'TRIA_DOWN')
down.index = i
down.up = -1
bottom = layout.operator("sw.move", text="Reorder to Back" if menu_mode else "",
icon='TRIA_RIGHT_BAR' if menu_mode else 'TRIA_DOWN_BAR')
bottom.index = i
bottom.top = False
if not menu_mode:
layout.separator()
remove(layout)
def workspace_menu(self, context):
layout = self.layout
use_topbar = get_use_topbar()
if use_topbar and has_data():
workspace_ops(layout, get_scene_workspaces().index(
context.window.workspace.name), True)
layout.separator()

View File

@ -22,4 +22,4 @@ class SW_MT_missing_workspaces(Menu):
layout.separator()
for w in bpy.data.workspaces:
if w.name not in get_scene_workspaces():
layout.operator("sw.link_workspace", text=w.name, icon="ADD").workspace = w.name
layout.operator("sw.link_workspace", text=w.name, icon="LINKED").workspace = w.name

View File

@ -1,9 +1,8 @@
from .. import __package__ as base_package
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, prefs
from .funcs import select_all, get_scene_workspaces, set_scene_workspaces, get_use_topbar, has_data, prefs
class SW_OT_switch(Operator):
bl_idname = "sw.switch"
@ -11,7 +10,7 @@ class SW_OT_switch(Operator):
bl_description = "Switch workspaces topbar between Scene Workspaces and default"
def execute(self, context):
prefs().use_global = not get_use_global()
prefs().use_topbar = not get_use_topbar()
context.preferences.is_dirty = True
return {'FINISHED'}
@ -65,7 +64,7 @@ class SW_OT_move(Operator):
class SW_OT_rename(Operator):
bl_idname = "sw.rename"
bl_label = "Rename workspace"
bl_description = "Rename the current workspace (this rename both the global workspace and the Scene workspace)"
bl_description = "Rename the current workspace (this rename both the global workspace as the scene workspace)"
current_name: StringProperty(name="Current Name", options={'HIDDEN'})
new_name: StringProperty(
@ -74,12 +73,18 @@ class SW_OT_rename(Operator):
def execute(self, context):
w = bpy.data.workspaces[self.current_name]
# Update global workspace name
w.name = self.new_name
l = get_scene_workspaces()
i = l.index(self.current_name)
l.pop(i)
l.insert(i, self.new_name)
set_scene_workspaces(l)
# Update name in all scenes, if present, to avoid missing workspace
for s in bpy.data.scenes:
l = get_scene_workspaces(s.name)
try:
i = l.index(self.current_name)
l.pop(i)
l.insert(i, self.new_name)
set_scene_workspaces(l, s.name)
finally:
continue
return {'FINISHED'}
def invoke(self, context, event):

View File

@ -1,6 +1,6 @@
import bpy
from bpy.types import Panel
from .funcs import get_scene_workspaces, draw_workspace_ops
from .funcs import get_scene_workspaces, workspace_ops
class SW_PT_select_scene_workspaces(Panel):
bl_idname = "sw.select_scene_workspaces"
@ -12,10 +12,10 @@ class SW_PT_select_scene_workspaces(Panel):
def draw(self, context):
layout = self.layout
layout.label(text="Workspaces linked to this Scene:")
sw = get_scene_workspaces()
layout.label(text="Workspaces linked to this Scene:")
box = layout.box()
sw = get_scene_workspaces()
if not sw:
box.label(text="There are no workspaces linked right now...")
box.operator("sw.link_all")
@ -27,17 +27,17 @@ class SW_PT_select_scene_workspaces(Panel):
row = box2.row(align=True)
row.scale_y = 2.1
row.label(text=f"{w}")
draw_workspace_ops(row, i, False, w)
workspace_ops(row, i, False, w)
i += 1
box.separator()
layout.separator()
layout.label(text="Link other workspaces")
l = [x for x in bpy.data.workspaces if x.name not in sw]
layout.label(text="Link other workspaces")
box2 = layout.box()
row = box2.row()
row_count = 0
l = [x for x in bpy.data.workspaces if x.name not in sw]
for w in l:
if row_count > 0 and row_count % 4 == 0:
row = box2.row()

20
addon/sw/prefs.py Normal file
View File

@ -0,0 +1,20 @@
from .. import __package__ as base_package
import bpy
from bpy.types import AddonPreferences
from bpy.props import BoolProperty
class SW_Preferences(AddonPreferences):
bl_idname = base_package
use_topbar: BoolProperty(name="Use Scene Workspaces topbar", description="Switch the workspace topbar between Scene Workspaces and the default one", default=True)
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)
compact: BoolProperty(name="Use Compact Mode (for active workspace)", description="If disabled, adds spacing around the active workspace and a quick unlink button", default=True)
def draw(self, context):
layout = self.layout
layout.prop(self, "use_topbar")
layout.prop(self, "switch")
box = layout.box()
box.label(text="UI Options")
box.prop(self, "compact")

View File

@ -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, get_show_switch, get_quick_unlink, get_active_spacing
from .funcs import get_scene_workspaces, get_use_topbar, get_switch, get_compact
# 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):
@ -16,7 +16,6 @@ class TOPBAR_HT_upper_bar(Header):
self.draw_left(context)
def draw_left(self, context):
global workspace_order
layout = self.layout
window = context.window
@ -26,46 +25,45 @@ class TOPBAR_HT_upper_bar(Header):
layout.separator()
# Edited
use_global = get_use_global()
quick_unlink = get_quick_unlink()
active_spacing = get_active_spacing()
# Edit start
use_topbar = get_use_topbar()
compact = get_compact()
switch= get_switch()
if not screen.show_fullscreen:
main_col = layout.column()
spacer_row = main_col.row()
spacer_row.scale_y = .33
spacer_row.scale_y = 1
main_row = main_col.row()
sy = 1.18
sx = 1.12
if get_show_switch():
sx = 1.18
if 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:
col.operator("sw.switch", text="", emboss=False, icon="CHECKBOX_HLT" if use_topbar else "CHECKBOX_DEHLT")
if not use_topbar:
# Original
layout.template_ID_tabs(window, "workspace", new="workspace.add", menu="TOPBAR_MT_workspace_menu")
else:
r = main_row.row(align=True)
r.scale_x = 0.87
r.scale_y = sy
ws = get_scene_workspaces()
sw = get_scene_workspaces()
# Link all (with no linked workspaces)
if not ws and bpy.data.workspaces:
if not sw and bpy.data.workspaces:
c = r.column()
c.scale_x = 1.4
c.operator("sw.link_all", text="Link all workspaces", icon="LINKED")
active_not_here = True
for w in ws:
i = ws.index(w)
for w in sw:
i = sw.index(w)
active = bpy.context.window.workspace.name == w
if active and i > 0 and active_spacing:
if active and i > 0 and not compact:
r.separator()
ab = r.box()
ab = ab.row(align=True)
# Workspace unlink
if active and quick_unlink:
if active and not compact:
col = ab.column()
col.scale_x = sx
col.operator("sw.remove", text="", icon="X", emboss=False).index = i
@ -78,23 +76,32 @@ class TOPBAR_HT_upper_bar(Header):
col.scale_x = sx
col.menu("TOPBAR_MT_workspace_menu", text="", icon="OPTIONS")
active_not_here = False
if active_spacing:
if not compact:
r.separator()
if not compact:
r.separator()
size = sx if compact else sx * 1.25
# Link other workspaces
if [x for x in bpy.data.workspaces if x.name not in get_scene_workspaces()]:
if len(bpy.data.workspaces) > len(sw):
c = r.column()
c.scale_x = sx
c.scale_x = size
c.menu("SW_MT_missing_workspaces", text="", icon="WORKSPACE")
if not compact:
r.separator()
# Duplicate linked workspaces from other scenes
if len(bpy.data.scenes) > 1:
c = r.column()
c.scale_x = sx
c.scale_x = size
c.menu("SW_MT_copy_from", text="", icon="DUPLICATE")
if not compact:
r.separator()
# Original Add Workspace menu
c = r.column()
c.scale_x = sx
c.scale_x = size
c.operator("workspace.add", text="", icon="ADD")
if not compact:
r.separator()
# Active (but not linked) workspace
if active_not_here:
@ -108,7 +115,7 @@ class TOPBAR_HT_upper_bar(Header):
col = r.box()
col.scale_x = sx
col.menu("TOPBAR_MT_workspace_menu", text="", icon="OPTIONS")
# End Edited
# Edit - End
else:
layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous")