Commit: e0cc86978c0f72f57240214ccb6bc7fe71428827
Author: Julian Eisel
Date:   Thu Jul 7 17:51:18 2022 +0200
Branches: master
https://developer.blender.org/rBe0cc86978c0f72f57240214ccb6bc7fe71428827

Workspaces: Option to pin scene to a workspace

Adds a "Pin Scene" option to the workspace. When activated, the workspace will
remember the scene that was last activated in it, so that when switching back
to this workspace, the same scene will be reactivated. This is important for a
VSE workflow, so that users can switch between different workspaces displaying
a scene and thus a timeline for a specific task.

The option can be found in the Properties, Workspace tab. D11890 additionally
adds an icon for this to the scene switcher in the topbar.

The workspace data contains a pointer to the scene which is a UI to scene data
relation. When appending a workspace, the pointer is cleared.

Differential Revision: https://developer.blender.org/D9140

Reviewed by: Brecht Van Lommel, Bastien Montagne (no final accept, but was fine
with the general design earlier)

===================================================================

M       release/scripts/startup/bl_ui/properties_workspace.py
M       source/blender/blenkernel/intern/workspace.c
M       source/blender/blenloader/intern/readfile.c
M       source/blender/editors/screen/workspace_edit.c
M       source/blender/makesdna/DNA_windowmanager_types.h
M       source/blender/makesdna/DNA_workspace_types.h
M       source/blender/makesrna/intern/rna_workspace.c
M       source/blender/windowmanager/intern/wm.c

===================================================================

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/windowmanag

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to