Refactor, UI fixes, fix move op

This commit is contained in:
Francesco Bellini 2024-09-08 22:45:58 +02:00
parent e55c8901cf
commit f7af3d5c2c
5 changed files with 132 additions and 45 deletions

View File

@ -14,8 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import bpy import bpy
from .sw.funcs import select_all, workspace_menu from .sw.funcs import select_all, workspace_menu, assign_shortcuts, remove_shortcuts
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.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, SW_OT_activate
from .sw.topbar import TOPBAR_HT_upper_bar from .sw.topbar import TOPBAR_HT_upper_bar
from .sw.panel import SW_PT_select_scene_workspaces from .sw.panel import SW_PT_select_scene_workspaces
from .sw.menu import SW_MT_missing_workspaces, SW_MT_copy_from from .sw.menu import SW_MT_missing_workspaces, SW_MT_copy_from
@ -38,6 +38,7 @@ classes = [
SW_OT_move, SW_OT_move,
SW_OT_remove, SW_OT_remove,
SW_OT_rename, SW_OT_rename,
SW_OT_activate,
SW_OT_link_workspace, SW_OT_link_workspace,
SW_OT_link_all, SW_OT_link_all,
SW_OT_copy_from_scene, SW_OT_copy_from_scene,
@ -57,11 +58,15 @@ def register():
bpy.utils.register_class(c) bpy.utils.register_class(c)
bpy.types.TOPBAR_MT_workspace_menu.prepend(workspace_menu) bpy.types.TOPBAR_MT_workspace_menu.prepend(workspace_menu)
assign_shortcuts()
def unregister(): def unregister():
for c in reversed(classes): for c in reversed(classes):
bpy.utils.unregister_class(c) bpy.utils.unregister_class(c)
bpy.utils.register_class(og_header) bpy.utils.register_class(og_header)
bpy.types.TOPBAR_MT_workspace_menu.remove(workspace_menu) bpy.types.TOPBAR_MT_workspace_menu.remove(workspace_menu)
remove_shortcuts()
if __name__ == "__main__": if __name__ == "__main__":
register() register()

View File

@ -34,6 +34,29 @@ def select_all():
def get_other_scene_names(): def get_other_scene_names():
return [s.name for s in bpy.data.scenes if s.name != bpy.context.scene.name] return [s.name for s in bpy.data.scenes if s.name != bpy.context.scene.name]
def tag_redraw_topbar():
for area in bpy.context.window.screen.areas:
if area.type == 'TOPBAR':
area.tag_redraw()
break
def assign_shortcuts():
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY')
prev = km.keymap_items.new('sw.activate', 'PAGE_UP', 'PRESS', ctrl=True, shift=True)
prev.properties.next = False
next = km.keymap_items.new('sw.activate', 'PAGE_DOWN', 'PRESS', ctrl=True, shift=True)
next.properties.next = True
def remove_shortcuts():
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY')
for kmi in km.keymap_items:
if kmi.idname in ['sw.activate', 'sw.move'] :
km.keymap_items.remove(kmi)
def workspace_ops(layout, i, menu_mode=False, name=None): def workspace_ops(layout, i, menu_mode=False, name=None):
layout.separator() layout.separator()
if menu_mode: if menu_mode:
@ -51,24 +74,28 @@ def workspace_ops(layout, i, menu_mode=False, name=None):
rename.current_name = name if name else bpy.context.window.workspace.name rename.current_name = name if name else bpy.context.window.workspace.name
rename.new_name = rename.current_name rename.new_name = rename.current_name
layout.separator() layout.separator()
top = layout.operator("sw.move", text="Reorder to Front" if menu_mode else "", top = layout.operator("sw.move", text="Reorder to Front (scene only)" if menu_mode else "",
icon='TRIA_LEFT_BAR' if menu_mode else 'TRIA_UP_BAR') icon='TRIA_LEFT_BAR' if menu_mode else 'TRIA_UP_BAR')
top.index = i top.index = i
top.top = True top.top = True
up = layout.operator("sw.move", text="Move Left" if menu_mode else "", up = layout.operator("sw.move", text="Move Left (scene only)" if menu_mode else "",
icon='TRIA_LEFT' if menu_mode else 'TRIA_UP') icon='TRIA_LEFT' if menu_mode else 'TRIA_UP')
up.index = i up.index = i
up.up = 1 up.up = 1
down = layout.operator("sw.move", text="Move Right" if menu_mode else "", down = layout.operator("sw.move", text="Move Right (scene only)" if menu_mode else "",
icon='TRIA_RIGHT' if menu_mode else 'TRIA_DOWN') icon='TRIA_RIGHT' if menu_mode else 'TRIA_DOWN')
down.index = i down.index = i
down.up = -1 down.up = -1
bottom = layout.operator("sw.move", text="Reorder to Back" if menu_mode else "", bottom = layout.operator("sw.move", text="Reorder to Back (scene only)" if menu_mode else "",
icon='TRIA_RIGHT_BAR' if menu_mode else 'TRIA_DOWN_BAR') icon='TRIA_RIGHT_BAR' if menu_mode else 'TRIA_DOWN_BAR')
bottom.index = i bottom.index = i
bottom.top = False bottom.top = False
if not menu_mode:
layout.separator() layout.separator()
if menu_mode and bpy.context.window.workspace.name in get_scene_workspaces():
layout.separator()
layout.operator("sw.activate", text="Previous Workspace (scene)" if menu_mode else "").next = False
layout.operator("sw.activate", text="Next Workspace (scene)" if menu_mode else "").next = True
else:
remove(layout) remove(layout)
def workspace_menu(self, context): def workspace_menu(self, context):

View File

@ -7,6 +7,8 @@ class SW_MT_copy_from(Menu):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
layout.label(text="Copy workspaces from scene")
layout.separator()
for s in bpy.data.scenes: for s in bpy.data.scenes:
if s.name != bpy.context.scene.name: if s.name != bpy.context.scene.name:
layout.operator("sw.copy_from_scene", text=s.name, icon="SCENE_DATA").scene = s.name layout.operator("sw.copy_from_scene", text=s.name, icon="SCENE_DATA").scene = s.name

View File

@ -2,7 +2,8 @@ from .. import __package__ as base_package
import bpy import bpy
from bpy.types import Operator from bpy.types import Operator
from bpy.props import StringProperty, BoolProperty, IntProperty from bpy.props import StringProperty, BoolProperty, IntProperty
from .funcs import select_all, get_scene_workspaces, set_scene_workspaces, get_use_topbar, has_data, prefs from .funcs import select_all, get_scene_workspaces, set_scene_workspaces, get_use_topbar, has_data, prefs, tag_redraw_topbar
class SW_OT_switch(Operator): class SW_OT_switch(Operator):
bl_idname = "sw.switch" bl_idname = "sw.switch"
@ -14,6 +15,7 @@ class SW_OT_switch(Operator):
context.preferences.is_dirty = True context.preferences.is_dirty = True
return {'FINISHED'} return {'FINISHED'}
class SW_OT_workspace(Operator): class SW_OT_workspace(Operator):
bl_idname = "sw.workspace" bl_idname = "sw.workspace"
bl_label = "Workspace" bl_label = "Workspace"
@ -30,6 +32,7 @@ class SW_OT_workspace(Operator):
set_scene_workspaces(l) set_scene_workspaces(l)
return {'FINISHED'} return {'FINISHED'}
class SW_OT_link_all(Operator): class SW_OT_link_all(Operator):
bl_idname = "sw.link_all" bl_idname = "sw.link_all"
bl_label = "Link all workspaces to this Scene" bl_label = "Link all workspaces to this Scene"
@ -39,28 +42,73 @@ class SW_OT_link_all(Operator):
select_all() select_all()
return {'FINISHED'} return {'FINISHED'}
class SW_OT_move(Operator): class SW_OT_move(Operator):
bl_idname = "sw.move" bl_idname = "sw.move"
bl_label = "Reorder Workspace" bl_label = "Reorder Workspace"
bl_description = "Reorder this workspace in the desired location (only for this Scene)" bl_description = "Reorder this workspace in the desired location (only for this Scene)"
up: IntProperty(name="up", default=0) # 0 means using `top` for reorder back/front # 0 means using `top` for reorder back/front
up: IntProperty(name="up", default=0)
index: IntProperty(name="index", default=-1) index: IntProperty(name="index", default=-1)
top: BoolProperty(name="top", default=False) top: BoolProperty(name="top", default=False)
def valid(self, context):
l = get_scene_workspaces()
i = self.index if self.index != -1 else l.index(bpy.context.window.workspace.name)
max_i = len(l) - 1
return (self.up == 1 and i > 0) or (self.up == -1 and i < max_i) or (self.up == 0 and ((self.top and i > 0) or (not self.top and i < max_i)))
def execute(self, context): def execute(self, context):
l = get_scene_workspaces() l = get_scene_workspaces()
if (self.up > 0 and self.index > 0) or (self.up < 0 and self.index < len(get_scene_workspaces()) - 1): if self.valid(context):
l.insert(self.index-self.up, l.pop(self.index)) try:
set_scene_workspaces(l) i = self.index if self.index != -1 else l.index(bpy.context.window.workspace.name)
elif self.up == 0: if self.up == 0:
l.insert(0 if self.top else len(l)-1, l.pop(self.index)) l.insert(0 if self.top else len(l)-1, l.pop(i))
set_scene_workspaces(l) else:
l.insert(i-self.up, l.pop(i))
set_scene_workspaces(l)
self.up = 0 self.up = 0
self.top = False self.top = False
except:
pass
return {'FINISHED'} return {'FINISHED'}
class SW_OT_activate(Operator):
bl_idname = "sw.activate"
bl_label = "Activate Next/Previous Workspace"
next: BoolProperty(name="next")
@classmethod
def description(cls, context, props):
return f"Activate {'the next' if props.next else 'the previous'} workspace"
def execute(self, context):
l = get_scene_workspaces()
ws = bpy.data.workspaces
try:
active_i = l.index(bpy.context.window.workspace.name)
w = None
if self.next:
if active_i < len(l)-1:
w = ws[l[active_i+1]]
else:
w = ws[l[0]]
else:
if active_i == 0:
w = ws[l[len(l)-1]]
else:
w = ws[l[active_i-1]]
bpy.context.window.workspace = w
except:
pass
return {'FINISHED'}
class SW_OT_rename(Operator): class SW_OT_rename(Operator):
bl_idname = "sw.rename" bl_idname = "sw.rename"
bl_label = "Rename workspace" bl_label = "Rename workspace"
@ -83,13 +131,14 @@ class SW_OT_rename(Operator):
l.pop(i) l.pop(i)
l.insert(i, self.new_name) l.insert(i, self.new_name)
set_scene_workspaces(l, s.name) set_scene_workspaces(l, s.name)
finally: except:
continue pass
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self, title=f"Rename Workspace '{self.current_name}'") return context.window_manager.invoke_props_dialog(self, title=f"Rename Workspace '{self.current_name}'")
class SW_OT_remove(Operator): class SW_OT_remove(Operator):
bl_idname = "sw.remove" bl_idname = "sw.remove"
bl_label = "Unlink Workspace" bl_label = "Unlink Workspace"
@ -103,6 +152,7 @@ class SW_OT_remove(Operator):
set_scene_workspaces(l) set_scene_workspaces(l)
return {'FINISHED'} return {'FINISHED'}
class SW_OT_copy_from_scene(Operator): class SW_OT_copy_from_scene(Operator):
bl_idname = "sw.copy_from_scene" bl_idname = "sw.copy_from_scene"
bl_label = "Copy from another Scene" bl_label = "Copy from another Scene"
@ -115,6 +165,7 @@ class SW_OT_copy_from_scene(Operator):
set_scene_workspaces(l) set_scene_workspaces(l)
return {'FINISHED'} return {'FINISHED'}
class SW_OT_link_workspace(Operator): class SW_OT_link_workspace(Operator):
bl_idname = "sw.link_workspace" bl_idname = "sw.link_workspace"
bl_label = "Link Workspace" bl_label = "Link Workspace"
@ -129,7 +180,8 @@ class SW_OT_link_workspace(Operator):
if not has_data(): if not has_data():
set_scene_workspaces([]) set_scene_workspaces([])
if self.workspace in get_scene_workspaces(): if self.workspace in get_scene_workspaces():
set_scene_workspaces([x for x in get_scene_workspaces() if x != self.workspace]) set_scene_workspaces(
[x for x in get_scene_workspaces() if x != self.workspace])
else: else:
set_scene_workspaces([*get_scene_workspaces(), self.workspace]) set_scene_workspaces([*get_scene_workspaces(), self.workspace])
return {'FINISHED'} return {'FINISHED'}

View File

@ -99,7 +99,8 @@ class TOPBAR_HT_upper_bar(Header):
# Original Add Workspace menu # Original Add Workspace menu
c = r.column() c = r.column()
c.scale_x = size c.scale_x = size
c.operator("workspace.add", text="", icon="ADD") c = c.box()
c.operator("workspace.add", text="", icon="ADD", emboss=False)
if not compact: if not compact:
r.separator() r.separator()