Update preference using compact, add compact mode switch in menu
This commit is contained in:
parent
a61b819400
commit
cddbef9f62
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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()
|
@ -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
80
addon/sw/funcs.py
Normal 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()
|
@ -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
|
@ -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):
|
@ -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
20
addon/sw/prefs.py
Normal 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")
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user