diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_workspace.py | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/workspace.c | 11 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 3 | ||||
-rw-r--r-- | source/blender/editors/screen/workspace_edit.c | 77 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_windowmanager_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_workspace_types.h | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_workspace.c | 7 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 8 |
8 files changed, 114 insertions, 2 deletions
diff --git a/release/scripts/startup/bl_ui/properties_workspace.py b/release/scripts/startup/bl_ui/properties_workspace.py index 542d770c062..1a245b33cd2 100644 --- a/release/scripts/startup/bl_ui/properties_workspace.py +++ b/release/scripts/startup/bl_ui/properties_workspace.py @@ -28,6 +28,8 @@ class WORKSPACE_PT_main(WorkSpaceButtonsPanel, Panel): layout = self.layout layout.use_property_split = True layout.use_property_decorate = False + + layout.prop(workspace, "use_pin_scene") layout.prop(workspace, "object_mode", text="Mode") diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index ef0a3069815..0265dd037b1 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -67,6 +67,8 @@ static void workspace_foreach_id(ID *id, LibraryForeachIDData *data) { WorkSpace *workspace = (WorkSpace *)id; + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, workspace->pin_scene, IDWALK_CB_NOP); + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, layout->screen, IDWALK_CB_USER); } @@ -120,6 +122,15 @@ static void workspace_blend_read_lib(BlendLibReader *reader, ID *id) WorkSpace *workspace = (WorkSpace *)id; Main *bmain = BLO_read_lib_get_main(reader); + /* Do not keep the scene reference when appending a workspace. Setting a scene for a workspace is + * a convenience feature, but the workspace should never truly depend on scene data. */ + if (ID_IS_LINKED(id)) { + workspace->pin_scene = NULL; + } + else { + BLO_read_id_address(reader, NULL, &workspace->pin_scene); + } + /* Restore proper 'parent' pointers to relevant data, and clean up unused/invalid entries. */ LISTBASE_FOREACH_MUTABLE (WorkSpaceDataRelation *, relation, &workspace->hook_layout_relations) { relation->parent = NULL; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 973965ada50..f0d390677bb 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2732,6 +2732,8 @@ void blo_lib_link_restore(Main *oldmain, LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { lib_link_workspace_layout_restore(id_map, newmain, layout); } + workspace->pin_scene = restore_pointer_by_name( + id_map, (ID *)workspace->pin_scene, USER_IGNORE); } LISTBASE_FOREACH (wmWindow *, win, &curwm->windows) { @@ -2745,6 +2747,7 @@ void blo_lib_link_restore(Main *oldmain, if (win->scene == NULL) { win->scene = curscene; } + win->unpinned_scene = restore_pointer_by_name(id_map, (ID *)win->unpinned_scene, USER_IGNORE); if (BKE_view_layer_find(win->scene, win->view_layer_name) == NULL) { STRNCPY(win->view_layer_name, cur_view_layer->name); } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 01417650b3d..0535a270176 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -54,17 +54,87 @@ WorkSpace *ED_workspace_add(Main *bmain, const char *name) return BKE_workspace_add(bmain, name); } +static void workspace_exit(WorkSpace *workspace, wmWindow *win) +{ + /* Scene pinning: Store whatever scene was active when leaving the workspace. It's reactivated + * when the workspace gets reactivated as well. */ + if (workspace->flags & WORKSPACE_USE_PIN_SCENE) { + workspace->pin_scene = WM_window_get_active_scene(win); + } + else { + /* The active scene may have been changed. So also always update the unpinned scene to the + * latest when leaving a workspace that has no scene pinning. */ + win->unpinned_scene = WM_window_get_active_scene(win); + } +} + +/** + * State changes (old workspace to new workspace): + * 1) unpinned -> pinned + * * Store current scene as the unpinned one (done in #workspace_exit()). + * * Change the current scene to the pinned one. + * 2) pinned -> pinned + * * Change the current scene to the new pinned one. + * 3) pinned -> unpinned + * * Change current scene back to the unpinned one + * 4) unpinned -> unpinned + * * Make sure the unpinned scene is active. + * + * Note that the pin scene must also be updated when leaving a workspace with a pinned scene. + * That's done separately via workspace_exit() above. + */ +static void workspace_scene_pinning_update(WorkSpace *workspace_new, + const WorkSpace *workspace_old, + bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + Main *bmain = CTX_data_main(C); + Scene *active_scene = WM_window_get_active_scene(win); + + const bool is_new_pinned = (workspace_new->flags & WORKSPACE_USE_PIN_SCENE); + const bool is_old_pinned = (workspace_old->flags & WORKSPACE_USE_PIN_SCENE); + + /* State changes 1 and 2. */ + if (is_new_pinned) { + if (workspace_new->pin_scene && (workspace_new->pin_scene != active_scene)) { + WM_window_set_active_scene(bmain, C, win, workspace_new->pin_scene); + workspace_new->pin_scene = NULL; + } + } + /* State change 3 - Changing from workspace with pinned scene to unpinned scene. */ + else if (is_old_pinned) { + if (win->unpinned_scene) { + WM_window_set_active_scene(bmain, C, win, win->unpinned_scene); + } + else { + /* When leaving a workspace where the pinning was just enabled, the unpinned scene wasn't set + * yet. */ + win->unpinned_scene = active_scene; + } + } + else { + /* When leaving a workspace where the pinning was just disabled, we still want to restore the + * unpinned scene. */ + if (win->unpinned_scene) { + WM_window_set_active_scene(bmain, C, win, win->unpinned_scene); + } + } + + BLI_assert(WM_window_get_active_scene(win)); +} + /** * Changes the object mode (if needed) to the one set in \a workspace_new. * Object mode is still stored on object level. In future it should all be workspace level instead. */ static void workspace_change_update(WorkSpace *workspace_new, - const WorkSpace *workspace_old, + WorkSpace *workspace_old, bContext *C, wmWindowManager *wm) { + workspace_scene_pinning_update(workspace_new, workspace_old, C); /* needs to be done before changing mode! (to ensure right context) */ - UNUSED_VARS(workspace_old, workspace_new, C, wm); + UNUSED_VARS(wm); #if 0 Object *ob_act = CTX_data_active_object(C) eObjectMode mode_old = workspace_old->object_mode; eObjectMode mode_new = workspace_new->object_mode; @@ -113,6 +183,8 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager return false; } + workspace_exit(workspace_old, win); + screen_change_prepare(screen_old, screen_new, bmain, C, win); if (screen_new == NULL) { @@ -143,6 +215,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2); workspace_new->flags = workspace_old->flags; + workspace_new->pin_scene = workspace_old->pin_scene; workspace_new->object_mode = workspace_old->object_mode; workspace_new->order = workspace_old->order; BLI_duplicatelist(&workspace_new->owner_ids, &workspace_old->owner_ids); diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index f7aaa1186db..5e741508603 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -239,6 +239,9 @@ typedef struct wmWindow { struct Scene *new_scene; /** Active view layer displayed in this window. */ char view_layer_name[64]; + /** The workspace may temporarily override the window's scene with scene pinning. This is the + * "overriden" or "default" scene to restore when entering a workspace with no scene pinned. */ + struct Scene *unpinned_scene; struct WorkSpaceInstanceHook *workspace_hook; diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index b8ed39bfd5d..a72689badb1 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -123,6 +123,10 @@ typedef struct WorkSpace { /** List of #bToolRef */ ListBase tools; + /** Optional, scene to switch to when enabling this workspace (NULL to disable). Cleared on + * link/append. */ + struct Scene *pin_scene; + char _pad[4]; int object_mode; @@ -195,6 +199,7 @@ typedef struct WorkSpaceInstanceHook { typedef enum eWorkSpaceFlags { WORKSPACE_USE_FILTER_BY_ORIGIN = (1 << 1), + WORKSPACE_USE_PIN_SCENE = (1 << 2), } eWorkSpaceFlags; #ifdef __cplusplus diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 0b6c3934985..4873831abce 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -413,6 +413,13 @@ static void rna_def_workspace(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Object Mode", "Switch to this object mode when activating the workspace"); + prop = RNA_def_property(srna, "use_pin_scene", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", WORKSPACE_USE_PIN_SCENE); + RNA_def_property_ui_text(prop, + "Pin Scene", + "Remember the last used scene for the workspace and switch to it " + "whenever this workspace is activated again"); + /* Flags */ prop = RNA_def_property(srna, "use_filter_by_owner", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 40d9b0b9a35..32cec8f779c 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -81,6 +81,8 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data) if (BKE_lib_query_foreachid_iter_stop(data)) { return; } + + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, win->unpinned_scene, IDWALK_CB_NOP); } if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { @@ -224,6 +226,7 @@ static void lib_link_workspace_instance_hook(BlendLibReader *reader, { WorkSpace *workspace = BKE_workspace_active_get(hook); BLO_read_id_address(reader, id->lib, &workspace); + BKE_workspace_active_set(hook, workspace); } @@ -239,6 +242,11 @@ static void window_manager_blend_read_lib(BlendLibReader *reader, ID *id) /* deprecated, but needed for versioning (will be NULL'ed then) */ BLO_read_id_address(reader, NULL, &win->screen); + /* The unpinned scene is a UI->Scene-data pointer, and should be NULL'ed on linking (like + * WorkSpace.pin_scene). But the WindowManager ID (owning the window) is never linked. */ + BLI_assert(!ID_IS_LINKED(id)); + BLO_read_id_address(reader, id->lib, &win->unpinned_scene); + LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { BKE_screen_area_blend_read_lib(reader, &wm->id, area); } |