Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <eiseljulian@gmail.com>2017-06-01 20:56:58 +0300
committerJulian Eisel <eiseljulian@gmail.com>2017-06-01 20:59:37 +0300
commit7f564d74f9edaaa41ce27c6e854869096f70b4da (patch)
tree4574418151f198fa0bab327ec58fa36819c2028e /source/blender/blenloader
parent0af93cf1ac276456619fc2e903c52a97fd09b9fb (diff)
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup) Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know! (Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.) == Main Changes/Features * Introduces the new Workspaces as data-blocks. * Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces. * Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces). * Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead. * Store screen-layouts (`bScreen`) per workspace. * Store an active screen-layout per workspace. Changing the workspace will enable this layout. * Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.) * Store an active render layer per workspace. * Moved mode switch from 3D View header to Info Editor header. * Store active scene in window (not directly workspace related, but overlaps quite a bit). * Removed 'Use Global Scene' User Preference option. * Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well. * Default .blend only contains one workspace ("General"). * Support appending workspaces. Opening files without UI and commandline rendering should work fine. Note that the UI is temporary! We plan to introduce a new global topbar that contains the workspace options and tabs for switching workspaces. == Technical Notes * Workspaces are data-blocks. * Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now. * A workspace can be active in multiple windows at the same time. * The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned). * The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that). * Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs. * `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those. * Added scene operators `SCENE_OT_`. Was previously done through screen operators. == BPY API Changes * Removed `Screen.scene`, added `Window.scene` * Removed `UserPreferencesView.use_global_scene` * Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces` * Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer` * Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name) == What's left? * There are a few open design questions (T50521). We should find the needed answers and implement them. * Allow adding and removing individual workspaces from workspace configuration (needs UI design). * Get the override system ready and support overrides per workspace. * Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc). * Allow enabling add-ons per workspace. * Support custom workspace keymaps. * Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later. * Get the topbar done. * Workspaces need a proper icon, current one is just a placeholder :) Reviewed By: campbellbarton, mont29 Tags: #user_interface, #bf_blender_2.8 Maniphest Tasks: T50521 Differential Revision: https://developer.blender.org/D2451
Diffstat (limited to 'source/blender/blenloader')
-rw-r--r--source/blender/blenloader/BLO_readfile.h20
-rw-r--r--source/blender/blenloader/intern/readfile.c286
-rw-r--r--source/blender/blenloader/intern/versioning_280.c133
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c40
-rw-r--r--source/blender/blenloader/intern/writefile.c53
5 files changed, 421 insertions, 111 deletions
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 0213a4ee997..fe38fc86c84 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -39,6 +39,7 @@ extern "C" {
struct BlendThumbnail;
struct bScreen;
struct LinkNode;
+struct ListBase;
struct Main;
struct MemFile;
struct ReportList;
@@ -49,6 +50,7 @@ struct View3D;
struct bContext;
struct BHead;
struct FileData;
+struct wmWindowManager;
typedef struct BlendHandle BlendHandle;
@@ -65,13 +67,20 @@ typedef struct BlendFileData {
int fileflags;
int globalf;
char filename[1024]; /* 1024 = FILE_MAX */
-
- struct bScreen *curscreen;
+
+ struct bScreen *curscreen; /* TODO think this isn't needed anymore? */
struct Scene *curscene;
-
+ struct SceneLayer *cur_render_layer; /* layer to activate in workspaces when reading without UI */
+
BlenFileType type;
} BlendFileData;
+typedef struct WorkspaceConfigFileData {
+ struct Main *main; /* has to be freed when done reading file data */
+
+ struct ListBase workspaces;
+} WorkspaceConfigFileData;
+
/* skip reading some data-block types (may want to skip screen data too). */
typedef enum eBLOReadSkip {
@@ -100,6 +109,7 @@ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize);
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names);
struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev);
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
+struct LinkNode *BLO_blendhandle_get_appendable_groups(BlendHandle *bh);
void BLO_blendhandle_close(BlendHandle *bh);
@@ -126,7 +136,9 @@ void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char
BlendFileData *blo_read_blendafterruntime(int file, const char *name, int actualsize, struct ReportList *reports);
/* internal function but we need to expose it */
-void blo_lib_link_screen_restore(struct Main *newmain, struct bScreen *curscreen, struct Scene *curscene);
+void blo_lib_link_restore(
+ struct Main *newmain, struct wmWindowManager *curwm,
+ struct Scene *curscene, struct SceneLayer *cur_render_layer);
typedef void (*BLOExpandDoitCallback) (void *fdhandle, struct Main *mainvar, void *idv);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d22af275469..966cbce62db 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -53,6 +53,10 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+/* Allow using DNA struct members that are marked as private for read/write.
+ * Note: Each header that uses this needs to define its own way of handling
+ * it. There's no generic implementation, direct use does nothing. */
+#define DNA_PRIVATE_READ_WRITE_ALLOW
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -99,10 +103,13 @@
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
+#include "RNA_access.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
@@ -149,6 +156,7 @@
#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
#include "BKE_colortools.h"
+#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
@@ -2774,6 +2782,78 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
direct_link_animdata(fd, cache_file->adt);
}
+/* ************ READ WORKSPACES *************** */
+
+static void lib_link_workspaces(FileData *fd, Main *bmain)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+ ID *id = (ID *)workspace;
+
+ if ((id->tag & LIB_TAG_NEED_LINK) == 0) {
+ continue;
+ }
+ IDP_LibLinkProperty(id->properties, fd);
+ id_us_ensure_real(id);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = newlibadr(fd, id->lib, BKE_workspace_layout_screen_get(layout));
+
+ if (screen) {
+ BKE_workspace_layout_screen_set(layout, screen);
+
+ if (ID_IS_LINKED_DATABLOCK(id)) {
+ screen->winid = 0;
+ if (screen->temp) {
+ /* delete temp layouts when appending */
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ }
+ }
+ }
+
+ id->tag &= ~LIB_TAG_NEED_LINK;
+ }
+}
+
+static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main)
+{
+ link_list(fd, BKE_workspace_layouts_get(workspace));
+ link_list(fd, &workspace->hook_layout_relations);
+
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first;
+ relation;
+ relation = relation->next)
+ {
+ relation->parent = newglobadr(fd, relation->parent); /* data from window - need to access through global oldnew-map */
+ relation->value = newdataadr(fd, relation->value);
+ }
+
+ if (ID_IS_LINKED_DATABLOCK(&workspace->id)) {
+ /* Appending workspace so render layer is likely from a different scene. Unset
+ * now, when activating workspace later we set a valid one from current scene. */
+ BKE_workspace_render_layer_set(workspace, NULL);
+ }
+
+ /* Same issue/fix as in direct_link_scene_update_screen_data: Can't read workspace data
+ * when reading windows, so have to update windows after/when reading workspaces. */
+ for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpaceLayout *act_layout = newdataadr(fd, BKE_workspace_active_layout_get(win->workspace_hook));
+ if (act_layout) {
+ BKE_workspace_active_layout_set(win->workspace_hook, act_layout);
+ }
+ }
+ }
+}
+
+static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id)
+{
+ WorkSpace *workspace = BKE_workspace_active_get(hook);
+ BKE_workspace_active_set(hook, newlibadr(fd, id->lib, workspace));
+}
+
+
/* ************ READ MOTION PATHS *************** */
/* direct data for cache */
@@ -5977,7 +6057,19 @@ static void direct_link_layer_collections(FileData *fd, ListBase *lb)
}
}
-static void direct_link_scene(FileData *fd, Scene *sce)
+static void direct_link_scene_update_screen_data(
+ FileData *fd, const Scene *scene, const ListBase *workspaces)
+{
+ for (WorkSpace *workspace = workspaces->first; workspace; workspace = workspace->id.next) {
+ SceneLayer *layer = newdataadr(fd, BKE_workspace_render_layer_get(workspace));
+ /* only set when layer is from the scene we read */
+ if (layer && (BLI_findindex(&scene->render_layers, layer) != -1)) {
+ BKE_workspace_render_layer_set(workspace, layer);
+ }
+ }
+}
+
+static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
{
Editing *ed;
Sequence *seq;
@@ -6250,7 +6342,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_scene_collection(fd, sce->collection);
}
- link_list(fd, &sce->render_layers);
+ /* insert into global old-new map for reading without UI (link_global accesses it again) */
+ link_glob_list(fd, &sce->render_layers);
for (sl = sce->render_layers.first; sl; sl = sl->next) {
sl->stats = NULL;
link_list(fd, &sl->object_bases);
@@ -6277,6 +6370,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
BKE_layer_collection_engine_settings_validate_scene(sce);
BKE_scene_layer_engine_settings_validate_scene(sce);
+
+ direct_link_scene_update_screen_data(fd, sce, &bmain->workspaces);
}
/* ************ READ WM ***************** */
@@ -6289,6 +6384,12 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
link_list(fd, &wm->windows);
for (win = wm->windows.first; win; win = win->next) {
+ WorkSpaceInstanceHook *hook = win->workspace_hook;
+
+ win->workspace_hook = newdataadr(fd, hook);
+ /* we need to restore a pointer to this later when reading workspaces, so store in global oldnew-map */
+ oldnewmap_insert(fd->globmap, hook, win->workspace_hook, 0);
+
win->ghostwin = NULL;
win->eventstate = NULL;
win->curswin = NULL;
@@ -6353,6 +6454,11 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
if (wm->id.tag & LIB_TAG_NEED_LINK) {
/* Note: WM IDProperties are never written to file, hence no need to read/link them here. */
for (win = wm->windows.first; win; win = win->next) {
+ if (win->workspace_hook) { /* NULL for old files */
+ lib_link_workspace_instance_hook(fd, win->workspace_hook, &wm->id);
+ }
+ win->scene = newlibadr(fd, wm->id.lib, win->scene);
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
win->screen = newlibadr(fd, NULL, win->screen);
}
@@ -6438,13 +6544,9 @@ static void lib_link_screen(FileData *fd, Main *main)
IDP_LibLinkProperty(sc->id.properties, fd);
id_us_ensure_real(&sc->id);
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
- /* this should not happen, but apparently it does somehow. Until we figure out the cause,
- * just assign first available scene */
- if (!sc->scene)
- sc->scene = main->scene.first;
-
sc->animtimer = NULL; /* saved in rare cases */
sc->scrubbing = false;
@@ -6752,56 +6854,59 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
-/* called from kernel/blender.c */
-/* used to link a file (without UI) to the current UI */
-/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */
-void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene)
+static void lib_link_workspace_scene_data_restore(wmWindow *win, Scene *scene)
{
- wmWindow *win;
- wmWindowManager *wm;
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
- /* first windowmanager */
- for (wm = newmain->wm.first; wm; wm = wm->id.next) {
- for (win= wm->windows.first; win; win= win->next) {
- win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
-
- if (win->screen == NULL)
- win->screen = curscreen;
-
- win->screen->winid = win->winid;
+ if (v3d->camera == NULL || v3d->scenelock) {
+ v3d->camera = scene->camera;
+ }
+
+ if (v3d->localvd) {
+ /*Base *base;*/
+
+ v3d->localvd->camera = scene->camera;
+
+ /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
+#if 0 /* XXX regionlocalview ? */
+ for (base= sc->scene->base.first; base; base= base->next) {
+ if (base->lay & v3d->lay) break;
+ }
+ if (base==NULL) {
+ v3d->lay= v3d->localvd->lay;
+ v3d->layact= v3d->localvd->layact;
+ MEM_freeN(v3d->localvd);
+ v3d->localvd= NULL;
+ }
+#endif
+ }
+ else if (v3d->scenelock) {
+ v3d->lay = scene->lay;
+ }
+ }
}
}
-
-
- for (sc = newmain->screen.first; sc; sc = sc->id.next) {
- Scene *oldscene = sc->scene;
-
- sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
- if (sc->scene == NULL)
- sc->scene = curscene;
-
- /* keep cursor location through undo */
- copy_v3_v3(sc->scene->cursor, oldscene->cursor);
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+}
+
+static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout)
+{
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* avoid conflicts with 2.8x branch */
+ {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
BGpic *bgpic;
ARegion *ar;
- if (v3d->scenelock)
- v3d->camera = NULL; /* always get from scene */
- else
- v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
- if (v3d->camera == NULL)
- v3d->camera = sc->scene->camera;
+ v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
@@ -6812,27 +6917,6 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
id_us_plus((ID *)bgpic->clip);
}
}
- if (v3d->localvd) {
- /*Base *base;*/
-
- v3d->localvd->camera = sc->scene->camera;
-
- /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
-#if 0 /* XXX regionlocalview ? */
- for (base= sc->scene->base.first; base; base= base->next) {
- if (base->lay & v3d->lay) break;
- }
- if (base==NULL) {
- v3d->lay= v3d->localvd->lay;
- v3d->layact= v3d->localvd->layact;
- MEM_freeN(v3d->localvd);
- v3d->localvd= NULL;
- }
-#endif
- }
- else if (v3d->scenelock) {
- v3d->lay = sc->scene->lay;
- }
/* not very nice, but could help */
if ((v3d->layact & v3d->lay) == 0) v3d->layact = v3d->lay;
@@ -7035,6 +7119,44 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
}
}
+}
+
+/**
+ * Used to link a file (without UI) to the current UI.
+ * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
+ */
+void blo_lib_link_restore(Main *newmain, wmWindowManager *curwm, Scene *curscene, SceneLayer *cur_render_layer)
+{
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+
+ for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ lib_link_workspace_layout_restore(id_map, newmain, layout);
+ }
+ BKE_workspace_render_layer_set(workspace, cur_render_layer);
+ }
+
+ for (wmWindow *win = curwm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ ID *workspace_id = (ID *)workspace;
+ Scene *oldscene = win->scene;
+
+ workspace = restore_pointer_by_name(id_map, workspace_id, USER_REAL);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ win->scene = restore_pointer_by_name(id_map, (ID *)win->scene, USER_REAL);
+ if (win->scene == NULL) {
+ win->scene = curscene;
+ }
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+
+ /* keep cursor location through undo */
+ copy_v3_v3(win->scene->cursor, oldscene->cursor);
+ lib_link_workspace_scene_data_restore(win, win->scene);
+
+ BLI_assert(win->screen == NULL);
+ }
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
@@ -8146,6 +8268,7 @@ static const char *dataname(short id_code)
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
case ID_CF: return "Data from CF";
+ case ID_WS: return "Data from WS";
}
return "Data from Lib Block";
@@ -8309,7 +8432,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
wrong_id = direct_link_screen(fd, (bScreen *)id);
break;
case ID_SCE:
- direct_link_scene(fd, (Scene *)id);
+ direct_link_scene(fd, (Scene *)id, main);
break;
case ID_OB:
direct_link_object(fd, (Object *)id);
@@ -8404,6 +8527,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
case ID_CF:
direct_link_cachefile(fd, (CacheFile *)id);
break;
+ case ID_WS:
+ direct_link_workspace(fd, (WorkSpace *)id, main);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -8449,7 +8575,8 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->curscreen = fg->curscreen;
bfd->curscene = fg->curscene;
-
+ bfd->cur_render_layer = fg->cur_render_layer;
+
MEM_freeN(fg);
fd->globalf = bfd->globalf;
@@ -8461,6 +8588,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
/* note, this has to be kept for reading older files... */
static void link_global(FileData *fd, BlendFileData *bfd)
{
+ bfd->cur_render_layer = newglobadr(fd, bfd->cur_render_layer);
bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
// this happens in files older than 2.35
@@ -8580,6 +8708,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
lib_link_cachefiles(fd, main);
+ lib_link_workspaces(fd, main);
lib_link_library(fd, main); /* only init users */
}
@@ -8966,6 +9095,11 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
}
}
else {
+ /* in 2.50+ file identifier for screens is patched, forward compatibility */
+ if (bhead->code == ID_SCRN) {
+ bhead->code = ID_SCR;
+ }
+
id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
read_libblock(fd, mainvar, bhead, LIB_TAG_TESTIND, NULL);
@@ -9817,6 +9951,15 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
+static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout));
+ }
+}
+
/**
* Set the callback func used over all ID data found by \a BLO_expand_main func.
*
@@ -9931,6 +10074,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_CF:
expand_cachefile(fd, mainvar, (CacheFile *)id);
break;
+ case ID_WS:
+ expand_workspace(fd, mainvar, (WorkSpace *)id);
+ break;
}
do_it = true;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 3eeb0fc78e4..2d14238eb6f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -45,6 +45,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
@@ -55,6 +56,83 @@
#include "MEM_guardedalloc.h"
+
+static bScreen *screen_parent_find(const bScreen *screen)
+{
+ /* can avoid lookup if screen state isn't maximized/full (parent and child store the same state) */
+ if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->full && sa->full != screen) {
+ BLI_assert(sa->full->state == screen->state);
+ return sa->full;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void do_version_workspaces_create_from_screens(Main *bmain)
+{
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ const bScreen *screen_parent = screen_parent_find(screen);
+ WorkSpace *workspace;
+
+ if (screen_parent) {
+ /* fullscreen with "Back to Previous" option, don't create
+ * a new workspace, add layout workspace containing parent */
+ workspace = BLI_findstring(
+ &bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2);
+ }
+ else {
+ workspace = BKE_workspace_add(bmain, screen->id.name + 2);
+ }
+ BKE_workspace_layout_add(workspace, screen, screen->id.name + 2);
+ BKE_workspace_render_layer_set(workspace, screen->scene->render_layers.first);
+ }
+}
+
+/**
+ * \brief After lib-link versioning for new workspace design.
+ *
+ * * Adds a workspace for (almost) each screen of the old file
+ * and adds the needed workspace-layout to wrap the screen.
+ * * Active screen isn't stored directly in window anymore, but in the active workspace.
+ * * Active scene isn't stored in screen anymore, but in window.
+ * * Create workspace instance hook for each window.
+ *
+ * \note Some of the created workspaces might be deleted again in case of reading the default startup.blend.
+ */
+static void do_version_workspaces_after_lib_link(Main *bmain)
+{
+ BLI_assert(BLI_listbase_is_empty(&bmain->workspaces));
+
+ do_version_workspaces_create_from_screens(bmain);
+
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen_parent = screen_parent_find(win->screen);
+ bScreen *screen = screen_parent ? screen_parent : win->screen;
+ WorkSpace *workspace = BLI_findstring(&bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2);
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
+
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ BKE_workspace_active_layout_set(win->workspace_hook, layouts->first);
+
+ win->scene = screen->scene;
+ /* Deprecated from now on! */
+ win->screen = NULL;
+ }
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ /* Deprecated from now on! */
+ screen->scene = NULL;
+ }
+}
+
void do_versions_after_linking_280(Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
@@ -183,13 +261,18 @@ void do_versions_after_linking_280(Main *main)
scene->basact = NULL;
}
}
+ }
+ if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ /* same render-layer as do_version_workspaces_after_lib_link will activate,
+ * so same layer as BKE_scene_layer_context_active would return */
+ SceneLayer *layer = screen->scene->render_layers.first;
+
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *soutliner = (SpaceOops *)sl;
- SceneLayer *layer = BKE_scene_layer_context_active(screen->scene);
soutliner->outlinevis = SO_ACT_LAYER;
@@ -213,6 +296,11 @@ void do_versions_after_linking_280(Main *main)
}
}
}
+
+ /* New workspace design */
+ if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
+ do_version_workspaces_after_lib_link(main);
+ }
}
static void do_version_layer_collections_idproperties(ListBase *lb)
@@ -254,34 +342,35 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
-
}
- if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
- for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
- ca->gpu_dof.ratio = 1.0f;
+ if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
+ for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
+ ca->gpu_dof.ratio = 1.0f;
+ }
}
- }
- if (!DNA_struct_elem_find(fd->filesdna, "SceneLayer", "IDProperty", "*properties")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
- for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
- IDPropertyTemplate val = {0};
- sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
- BKE_scene_layer_engine_settings_create(sl->properties);
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneLayer", "IDProperty", "*properties")) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) {
+ IDPropertyTemplate val = {0};
+ sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ BKE_scene_layer_engine_settings_create(sl->properties);
+ }
}
}
- }
- /* MTexPoly now removed. */
- if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
- const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
- for (Mesh *me = main->mesh.first; me; me = me->id.next) {
- /* If we have UV's, so this file will have MTexPoly layers too! */
- if (me->mloopuv != NULL) {
- CustomData_update_typemap(&me->pdata);
- CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly);
- BKE_mesh_update_customdata_pointers(me, false);
+ /* MTexPoly now removed. */
+ if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
+ const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
+ for (Mesh *me = main->mesh.first; me; me = me->id.next) {
+ /* If we have UV's, so this file will have MTexPoly layers too! */
+ if (me->mloopuv != NULL) {
+ CustomData_update_typemap(&me->pdata);
+ CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly);
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index a38f122ec56..002af20bc3a 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -40,10 +40,12 @@
#include "DNA_mesh_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_brush.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
@@ -84,6 +86,32 @@ void BLO_update_defaults_userpref_blend(void)
}
/**
+ * New workspace design: Remove all screens/workspaces except of "Default" one and rename the workspace to "General".
+ * For compatibility, a new workspace has been created for each screen of old files,
+ * we only want one workspace and one screen in the default startup file however.
+ */
+static void update_defaults_startup_workspaces(Main *bmain)
+{
+ WorkSpace *workspace_default = NULL;
+
+ for (WorkSpace *workspace = bmain->workspaces.first, *workspace_next; workspace; workspace = workspace_next) {
+ workspace_next = workspace->id.next;
+
+ if (STREQ(workspace->id.name + 2, "Default")) {
+ /* don't rename within iterator, renaming causes listbase to be re-sorted */
+ workspace_default = workspace;
+ }
+ else {
+ BKE_workspace_remove(bmain, workspace);
+ }
+ }
+
+ /* rename "Default" workspace to "General" */
+ BKE_libblock_rename(bmain, (ID *)workspace_default, "General");
+ BLI_assert(BLI_listbase_count(BKE_workspace_layouts_get(workspace_default)) == 1);
+}
+
+/**
* Update defaults in startup.blend, without having to save and embed the file.
* This function can be emptied each time the startup.blend is updated. */
void BLO_update_defaults_startup_blend(Main *bmain)
@@ -181,20 +209,18 @@ void BLO_update_defaults_startup_blend(Main *bmain)
linestyle->chain_count = 10;
}
- for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- ARegion *ar;
+ update_defaults_startup_workspaces(bmain);
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *space_link = area->spacedata.first; space_link; space_link = space_link->next) {
if (space_link->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *) space_link;
space_clip->flag &= ~SC_MANUAL_CALIBRATION;
}
}
- for (ar = area->regionbase.first; ar; ar = ar->next) {
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
/* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
BLI_freelistN(&ar->panels);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 19f6b9f370d..82d2e37dce0 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -102,6 +102,10 @@
/* allow writefile to use deprecated functionality (for forward compatibility code) */
#define DNA_DEPRECATED_ALLOW
+/* Allow using DNA struct members that are marked as private for read/write.
+ * Note: Each header that uses this needs to define its own way of handling
+ * it. There's no generic implementation, direct use does nothing. */
+#define DNA_PRIVATE_READ_WRITE_ALLOW
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -147,6 +151,7 @@
#include "DNA_vfont_types.h"
#include "DNA_world_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
@@ -173,6 +178,7 @@
#include "BKE_fcurve.h"
#include "BKE_pointcache.h"
#include "BKE_mesh.h"
+#include "BKE_workspace.h"
#ifdef USE_NODE_COMPAT_CUSTOMNODES
#include "NOD_socket.h" /* for sock->default_value data */
@@ -1077,10 +1083,13 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
* Take care using 'use_active_win', since we wont want the currently active window
* to change which scene renders (currently only used for undo).
*/
-static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_active_win)
+static void current_screen_compat(
+ Main *mainvar, bool use_active_win,
+ bScreen **r_screen, Scene **r_scene, SceneLayer **r_render_layer)
{
wmWindowManager *wm;
wmWindow *window = NULL;
+ WorkSpace *workspace;
/* find a global current screen in the first open window, to have
* a reasonable default for reading in older versions */
@@ -1104,8 +1113,11 @@ static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_ac
window = wm->windows.first;
}
}
+ workspace = (window) ? BKE_workspace_active_get(window->workspace_hook) : NULL;
- *r_screen = (window) ? window->screen : NULL;
+ *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL;
+ *r_scene = (window) ? window->scene : NULL;
+ *r_render_layer = (window) ? BKE_workspace_render_layer_get(workspace) : NULL;
}
typedef struct RenderInfo {
@@ -1121,13 +1133,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
{
bScreen *curscreen;
Scene *sce, *curscene = NULL;
+ SceneLayer *render_layer;
RenderInfo data;
/* XXX in future, handle multiple windows with multiple screens? */
- current_screen_compat(mainvar, &curscreen, false);
- if (curscreen) {
- curscene = curscreen->scene;
- }
+ current_screen_compat(mainvar, false, &curscreen, &curscene, &render_layer);
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
@@ -2842,8 +2852,19 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
write_iddata(wd, &wm->id);
for (wmWindow *win = wm->windows.first; win; win = win->next) {
+
+ /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
+ win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ if (win->screen) {
+ BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
+ }
+
writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook);
writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
+
+ /* data is written, clear deprecated data again */
+ win->screen = NULL;
}
}
@@ -2984,6 +3005,7 @@ static void write_screen(WriteData *wd, bScreen *sc)
View3D *v3d = (View3D *)sl;
BGpic *bgpic;
writestruct(wd, DATA, View3D, 1, v3d);
+
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
writestruct(wd, DATA, BGpic, 1, bgpic);
}
@@ -3729,6 +3751,15 @@ static void write_cachefile(WriteData *wd, CacheFile *cache_file)
}
}
+static void write_workspace(WriteData *wd, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ writestruct(wd, ID_WS, WorkSpace, 1, workspace);
+ writelist(wd, DATA, WorkSpaceLayout, layouts);
+ writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations);
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -3798,6 +3829,8 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
const bool is_undo = (wd->current != NULL);
FileGlobal fg;
bScreen *screen;
+ Scene *scene;
+ SceneLayer *render_layer;
char subvstr[8];
/* prevent mem checkers from complaining */
@@ -3805,11 +3838,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
memset(fg.filename, 0, sizeof(fg.filename));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
- current_screen_compat(mainvar, &screen, is_undo);
+ current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer);
/* XXX still remap G */
fg.curscreen = screen;
- fg.curscene = screen ? screen->scene : NULL;
+ fg.curscene = scene;
+ fg.cur_render_layer = render_layer;
/* prevent to save this, is not good convention, and feature with concerns... */
fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME);
@@ -3905,6 +3939,9 @@ static bool write_file_handle(
case ID_WM:
write_windowmanager(wd, (wmWindowManager *)id);
break;
+ case ID_WS:
+ write_workspace(wd, (WorkSpace *)id);
+ break;
case ID_SCR:
write_screen(wd, (bScreen *)id);
break;