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:
authorJacques Lucke <jacques@blender.org>2021-04-15 09:57:10 +0300
committerJacques Lucke <jacques@blender.org>2021-04-15 10:00:47 +0300
commit3810bcc1604756f433b5b799b66d8b81645767ca (patch)
treede0ba2c5ca0cbadf3838959a19475d19cce994df
parent0bac7682239f2ee117a80ed3ce62a1877331c974 (diff)
Spreadsheet: breadcrumbs and node pinning
This introduces a context path to the spreadsheet editor, which contains information about what data is shown in the spreadsheet. The context path (breadcrumbs) can reference a specific node in a node group hierarchy. During object evaluation, the geometry nodes modifier checks what data is currently requested by visible spreadsheets and stores the corresponding geometry sets separately for later access. The context path can be updated by the user explicitely, by clicking on the new icon in the header of nodes. Under some circumstances, the context path is updated automatically based on Blender's context. This patch also consolidates the "Node" and "Final" object evaluation mode to just "Evaluated". Based on the current context path, either the final geometry set of an object will be displayed, or the data at a specific node. The new preview icon in geometry nodes now behaves more like a toggle. It can be clicked again to clear the context path in an open spreadsheet editor. Previously, only an object could be pinned in the spreadsheet editor. Now it is possible to pin the entire context path. That allows two different spreadsheets to display geometry data from two different nodes. The breadcrumbs in the spreadsheet header can be collapsed by clicking on the arrow icons. It's not ideal but works well for now. This might be changed again, if we get a data set region on the left. Differential Revision: https://developer.blender.org/D10931
-rw-r--r--release/scripts/startup/bl_operators/node.py57
-rw-r--r--release/scripts/startup/bl_operators/spreadsheet.py40
-rw-r--r--release/scripts/startup/bl_ui/space_spreadsheet.py66
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/intern/object.c22
-rw-r--r--source/blender/blenkernel/intern/screen.c54
-rw-r--r--source/blender/blenlib/BLI_multi_value_map.hh6
-rw-r--r--source/blender/blenloader/intern/readfile.c9
-rw-r--r--source/blender/blenloader/intern/versioning_290.c14
-rw-r--r--source/blender/editors/include/ED_spreadsheet.h43
-rw-r--r--source/blender/editors/space_node/node_draw.cc2
-rw-r--r--source/blender/editors/space_node/node_edit.c49
-rw-r--r--source/blender/editors/space_node/node_ops.c1
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc116
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.cc306
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.hh27
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc23
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/makesdna/DNA_object_types.h5
-rw-r--r--source/blender/makesdna/DNA_space_types.h51
-rw-r--r--source/blender/makesrna/RNA_access.h4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c216
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc183
25 files changed, 1101 insertions, 206 deletions
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 63da9c6af55..e0d0fc1e145 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -306,6 +306,62 @@ class NODE_OT_tree_path_parent(Operator):
return {'FINISHED'}
+class NODE_OT_active_preview_toggle(Operator):
+ '''Toggle active preview state of node'''
+ bl_idname = "node.active_preview_toggle"
+ bl_label = "Toggle Active Preview"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ space = context.space_data
+ if space.type != 'NODE_EDITOR':
+ return False
+ if space.edit_tree is None:
+ return False
+ if space.edit_tree.nodes.active is None:
+ return False
+ return True
+
+ def execute(self, context):
+ node_editor = context.space_data
+ ntree = node_editor.edit_tree
+ active_node = ntree.nodes.active
+
+ if active_node.active_preview:
+ self.disable_preview(context, ntree, active_node)
+ else:
+ self.enable_preview(context, node_editor, ntree, active_node)
+
+ return {'FINISHED'}
+
+ def enable_preview(self, context, node_editor, ntree, active_node):
+ spreadsheets = self.find_unpinned_spreadsheets(context)
+
+ for spreadsheet in spreadsheets:
+ spreadsheet.set_geometry_node_context(node_editor, active_node)
+
+ for node in ntree.nodes:
+ node.active_preview = False
+ active_node.active_preview = True
+
+ def disable_preview(self, context, ntree, active_node):
+ spreadsheets = self.find_unpinned_spreadsheets(context)
+ for spreadsheet in spreadsheets:
+ spreadsheet.context_path.clear()
+
+ active_node.active_preview = False
+
+ def find_unpinned_spreadsheets(self, context):
+ spreadsheets = []
+ for window in context.window_manager.windows:
+ for area in window.screen.areas:
+ space = area.spaces.active
+ if space.type == 'SPREADSHEET' and not space.is_pinned:
+ spreadsheets.append(space)
+ return spreadsheets
+
+
classes = (
NodeSetting,
@@ -314,4 +370,5 @@ classes = (
NODE_OT_add_search,
NODE_OT_collapse_hide_unused_toggle,
NODE_OT_tree_path_parent,
+ NODE_OT_active_preview_toggle,
)
diff --git a/release/scripts/startup/bl_operators/spreadsheet.py b/release/scripts/startup/bl_operators/spreadsheet.py
index 91fca883bb5..5cc83d4eddd 100644
--- a/release/scripts/startup/bl_operators/spreadsheet.py
+++ b/release/scripts/startup/bl_operators/spreadsheet.py
@@ -34,13 +34,45 @@ class SPREADSHEET_OT_toggle_pin(Operator):
def execute(self, context):
space = context.space_data
- if space.pinned_id:
- space.pinned_id = None
+ if space.is_pinned:
+ self.unpin(context)
else:
- space.pinned_id = context.active_object
-
+ self.pin(context)
return {'FINISHED'}
+ def pin(self, context):
+ space = context.space_data
+ space.is_pinned = True
+
+ def unpin(self, context):
+ space = context.space_data
+ space.is_pinned = False
+
+ space.context_path.clear()
+
+ # Try to find a node with an active preview in any open editor.
+ if space.object_eval_state == 'EVALUATED':
+ node_editors = self.find_geometry_node_editors(context)
+ for node_editor in node_editors:
+ ntree = node_editor.edit_tree
+ for node in ntree.nodes:
+ if node.active_preview:
+ space.set_geometry_node_context(node_editor, node)
+ return
+
+ def find_geometry_node_editors(self, context):
+ editors = []
+ for window in context.window_manager.windows:
+ for area in window.screen.areas:
+ space = area.spaces.active
+ if space.type != 'NODE_EDITOR':
+ continue
+ if space.edit_tree is None:
+ continue
+ if space.edit_tree.type == 'GEOMETRY':
+ editors.append(space)
+ return editors
+
classes = (
SPREADSHEET_OT_toggle_pin,
diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py
index 188eddbcce3..13e435a7350 100644
--- a/release/scripts/startup/bl_ui/space_spreadsheet.py
+++ b/release/scripts/startup/bl_ui/space_spreadsheet.py
@@ -28,8 +28,17 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.template_header()
- pinned_id = space.pinned_id
- used_id = pinned_id if pinned_id else context.active_object
+ if len(space.context_path) == 0:
+ self.draw_without_context_path(layout)
+ return
+ root_context = space.context_path[0]
+ if root_context.type != 'OBJECT':
+ self.draw_without_context_path(layout)
+ return
+ obj = root_context.object
+ if obj is None:
+ self.draw_without_context_path(layout)
+ return
layout.prop(space, "object_eval_state", text="")
if space.object_eval_state != 'ORIGINAL':
@@ -37,16 +46,61 @@ class SPREADSHEET_HT_header(bpy.types.Header):
if space.geometry_component_type != 'INSTANCES':
layout.prop(space, "attribute_domain", text="")
- if used_id:
- layout.label(text=used_id.name, icon='OBJECT_DATA')
+ context_path = space.context_path
+ if space.object_eval_state == 'ORIGINAL':
+ # Only show first context.
+ context_path = context_path[:1]
+ if space.display_context_path_collapsed:
+ self.draw_collapsed_context_path(context, layout, context_path)
+ else:
+ self.draw_full_context_path(context, layout, context_path)
- layout.operator("spreadsheet.toggle_pin", text="", icon='PINNED' if pinned_id else 'UNPINNED', emboss=False)
+ pin_icon = 'PINNED' if space.is_pinned else 'UNPINNED'
+ layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False)
layout.separator_spacer()
- if isinstance(used_id, bpy.types.Object) and used_id.mode == 'EDIT':
+ if isinstance(obj, bpy.types.Object) and obj.mode == 'EDIT':
layout.prop(space, "show_only_selected", text="Selected Only")
+ def draw_without_context_path(self, layout):
+ layout.label(text="No active context")
+
+ def draw_full_context_path(self, context, layout, context_path):
+ space = context.space_data
+ row = layout.row()
+ for ctx in context_path[:-1]:
+ subrow = row.row(align=True)
+ self.draw_spreadsheet_context(subrow, ctx)
+ self.draw_spreadsheet_context_path_icon(subrow, space)
+
+ self.draw_spreadsheet_context(row, context_path[-1])
+
+ def draw_collapsed_context_path(self, context, layout, context_path):
+ space = context.space_data
+ row = layout.row(align=True)
+ self.draw_spreadsheet_context(row, context_path[0])
+ if len(context_path) == 1:
+ return
+ self.draw_spreadsheet_context_path_icon(row, space)
+ if len(context_path) > 2:
+ self.draw_spreadsheet_context_path_icon(row, space, icon='DOT')
+ self.draw_spreadsheet_context_path_icon(row, space)
+ self.draw_spreadsheet_context(row, context_path[-1])
+
+ def draw_spreadsheet_context(self, layout, ctx):
+ if ctx.type == 'OBJECT':
+ if ctx.object is None:
+ layout.label(text="<no object>", icon='OBJECT_DATA')
+ else:
+ layout.label(text=ctx.object.name, icon='OBJECT_DATA')
+ elif ctx.type == 'MODIFIER':
+ layout.label(text=ctx.modifier_name, icon='MODIFIER')
+ elif ctx.type == 'NODE':
+ layout.label(text=ctx.node_name, icon='NODE')
+
+ def draw_spreadsheet_context_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
+ layout.prop(space, "display_context_path_collapsed", icon_only=True, emboss=False, icon=icon)
classes = (
SPREADSHEET_HT_header,
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 6d5638375d6..9fe286df36d 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -70,7 +70,9 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
-void BKE_object_set_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set);
+void BKE_object_preview_geometry_set_add(struct Object *ob,
+ const uint64_t key,
+ struct GeometrySet *geometry_set);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index d96942e47e7..5eb935f4651 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1761,9 +1761,9 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
ob->runtime.geometry_set_eval = NULL;
}
- if (ob->runtime.geometry_set_preview != NULL) {
- BKE_geometry_set_free(ob->runtime.geometry_set_preview);
- ob->runtime.geometry_set_preview = NULL;
+ if (ob->runtime.geometry_set_previews != NULL) {
+ BLI_ghash_free(ob->runtime.geometry_set_previews, NULL, (GHashValFreeFP)BKE_geometry_set_free);
+ ob->runtime.geometry_set_previews = NULL;
}
}
@@ -1816,14 +1816,20 @@ void BKE_object_free_caches(Object *object)
}
/* Can be called from multiple threads. */
-void BKE_object_set_preview_geometry_set(Object *ob, struct GeometrySet *geometry_set)
+void BKE_object_preview_geometry_set_add(Object *ob,
+ const uint64_t key,
+ struct GeometrySet *geometry_set)
{
static ThreadMutex mutex = BLI_MUTEX_INITIALIZER;
BLI_mutex_lock(&mutex);
- if (ob->runtime.geometry_set_preview != NULL) {
- BKE_geometry_set_free(ob->runtime.geometry_set_preview);
- }
- ob->runtime.geometry_set_preview = geometry_set;
+ if (ob->runtime.geometry_set_previews == NULL) {
+ ob->runtime.geometry_set_previews = BLI_ghash_int_new(__func__);
+ }
+ BLI_ghash_reinsert(ob->runtime.geometry_set_previews,
+ POINTER_FROM_UINT(key),
+ geometry_set,
+ NULL,
+ (GHashValFreeFP)BKE_geometry_set_free);
BLI_mutex_unlock(&mutex);
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index d5540a3cfd3..d0d63192ebf 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -227,7 +227,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
case SPACE_SPREADSHEET: {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- BKE_LIB_FOREACHID_PROCESS_ID(data, sspreadsheet->pinned_id, IDWALK_CB_NOP);
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
+ BKE_LIB_FOREACHID_PROCESS(
+ data, ((SpreadsheetContextObject *)context)->object, IDWALK_CB_NOP);
+ }
+ }
break;
}
default:
@@ -1357,6 +1362,27 @@ static void write_area(BlendWriter *writer, ScrArea *area)
BLO_write_struct(writer, SpreadsheetColumnID, column->id);
BLO_write_string(writer, column->id->name);
}
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ switch (context->type) {
+ case SPREADSHEET_CONTEXT_OBJECT: {
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+ BLO_write_struct(writer, SpreadsheetContextObject, object_context);
+ break;
+ }
+ case SPREADSHEET_CONTEXT_MODIFIER: {
+ SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context;
+ BLO_write_struct(writer, SpreadsheetContextModifier, modifier_context);
+ BLO_write_string(writer, modifier_context->modifier_name);
+ break;
+ }
+ case SPREADSHEET_CONTEXT_NODE: {
+ SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context;
+ BLO_write_struct(writer, SpreadsheetContextNode, node_context);
+ BLO_write_string(writer, node_context->node_name);
+ break;
+ }
+ }
+ }
}
}
}
@@ -1715,6 +1741,25 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
BLO_read_data_address(reader, &column->id);
BLO_read_data_address(reader, &column->id->name);
}
+
+ BLO_read_list(reader, &sspreadsheet->context_path);
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ switch (context->type) {
+ case SPREADSHEET_CONTEXT_NODE: {
+ SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context;
+ BLO_read_data_address(reader, &node_context->node_name);
+ break;
+ }
+ case SPREADSHEET_CONTEXT_MODIFIER: {
+ SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context;
+ BLO_read_data_address(reader, &modifier_context->modifier_name);
+ break;
+ }
+ case SPREADSHEET_CONTEXT_OBJECT: {
+ break;
+ }
+ }
+ }
}
}
@@ -1931,7 +1976,12 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr
}
case SPACE_SPREADSHEET: {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- BLO_read_id_address(reader, parent_id->lib, &sspreadsheet->pinned_id);
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
+ BLO_read_id_address(
+ reader, parent_id->lib, &((SpreadsheetContextObject *)context)->object);
+ }
+ }
break;
}
default:
diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh
index 98b55067a5c..fb52ac78243 100644
--- a/source/blender/blenlib/BLI_multi_value_map.hh
+++ b/source/blender/blenlib/BLI_multi_value_map.hh
@@ -73,6 +73,12 @@ template<typename Key, typename Value> class MultiValueMap {
vector.append(std::forward<ForwardValue>(value));
}
+ void add_non_duplicates(const Key &key, const Value &value)
+ {
+ Vector<Value> &vector = map_.lookup_or_add_default_as(key);
+ vector.append_non_duplicates(value);
+ }
+
/**
* Add all given values to the key.
*/
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b657cb8b2f9..85cf45bd868 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3010,8 +3010,13 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
else if (sl->spacetype == SPACE_SPREADSHEET) {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- sspreadsheet->pinned_id = restore_pointer_by_name(
- id_map, sspreadsheet->pinned_id, USER_IGNORE);
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+ object_context->object = restore_pointer_by_name(
+ id_map, (ID *)object_context->object, USER_IGNORE);
+ }
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 819d077bf0a..709e2e5af61 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -2054,5 +2054,19 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Consolidate node and final evaluation modes. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ if (sspreadsheet->object_eval_state == 2) {
+ sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED;
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/editors/include/ED_spreadsheet.h b/source/blender/editors/include/ED_spreadsheet.h
new file mode 100644
index 00000000000..3a07b1b9d4b
--- /dev/null
+++ b/source/blender/editors/include/ED_spreadsheet.h
@@ -0,0 +1,43 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+struct SpreadsheetContext;
+struct SpaceSpreadsheet;
+struct SpaceNode;
+struct ID;
+struct bNode;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SpreadsheetContext *ED_spreadsheet_context_new(int type);
+void ED_spreadsheet_context_free(struct SpreadsheetContext *context);
+void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet);
+void ED_spreadsheet_context_path_update_tag(struct SpaceSpreadsheet *sspreadsheet);
+uint64_t ED_spreadsheet_context_path_hash(struct SpaceSpreadsheet *sspreadsheet);
+
+struct ID *ED_spreadsheet_get_current_id(struct SpaceSpreadsheet *sspreadsheet);
+
+void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsheet,
+ struct SpaceNode *snode,
+ struct bNode *node);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 88234c861a0..fd9c0f42f2d 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -1422,7 +1422,7 @@ static void node_draw_basis(const bContext *C,
0,
0,
0,
- "Show this node's geometry output in the spreadsheet in Node mode");
+ "Show this node's geometry output in the spreadsheet");
UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_active_preview_toggle");
UI_block_emboss_set(node->block, UI_EMBOSS);
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 1cbd0fd607c..7282ed4b667 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -1694,55 +1694,6 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void disable_active_preview_on_all_nodes(bNodeTree *ntree)
-{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->flag &= ~NODE_ACTIVE_PREVIEW;
- }
-}
-
-static int node_active_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
- Main *bmain = CTX_data_main(C);
- bNodeTree *ntree = snode->edittree;
- disable_active_preview_on_all_nodes(ntree);
- bNode *active_node = nodeGetActive(ntree);
- active_node->flag |= NODE_ACTIVE_PREVIEW;
-
- /* Tag for update, so that dependent objects are reevaluated. This is necessary when a
- * spreadsheet editor displays data from a node. */
- LISTBASE_FOREACH (wmWindow *, window, &((wmWindowManager *)bmain->wm.first)->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- if (area->spacetype == SPACE_SPREADSHEET) {
- SpaceSpreadsheet *sspreadsheet = area->spacedata.first;
- if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
- DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
- ED_area_tag_redraw(area);
- }
- }
- }
- }
-
- return OPERATOR_FINISHED;
-}
-
-void NODE_OT_active_preview_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Active Preview";
- ot->description = "Toggle active preview state of node";
- ot->idname = "NODE_OT_active_preview_toggle";
-
- /* callbacks */
- ot->exec = node_active_preview_toggle_exec;
- ot->poll = ED_operator_node_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ****************** Mute operator *********************** */
static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 4168ff2922d..e35b444aa11 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -57,7 +57,6 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_preview_toggle);
WM_operatortype_append(NODE_OT_options_toggle);
WM_operatortype_append(NODE_OT_hide_socket_toggle);
- WM_operatortype_append(NODE_OT_active_preview_toggle);
WM_operatortype_append(NODE_OT_node_copy_color);
WM_operatortype_append(NODE_OT_duplicate);
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index ac879eaa5a2..056358edb78 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
set(SRC
space_spreadsheet.cc
+ spreadsheet_breadcrumb.cc
spreadsheet_column.cc
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
@@ -40,6 +41,7 @@ set(SRC
spreadsheet_layout.cc
spreadsheet_ops.cc
+ spreadsheet_breadcrumb.hh
spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 9d79e7abcc5..7122725ad45 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -22,6 +22,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_spreadsheet.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -44,6 +45,7 @@
#include "spreadsheet_intern.hh"
+#include "spreadsheet_breadcrumb.hh"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
@@ -91,6 +93,9 @@ static void spreadsheet_free(SpaceLink *sl)
LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
spreadsheet_column_free(column);
}
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ spreadsheet_context_free(context);
+ }
}
static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
@@ -100,10 +105,6 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN(
sizeof(SpaceSpreadsheet_Runtime), __func__);
}
- LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
- spreadsheet_column_free(column);
- }
- BLI_listbase_clear(&sspreadsheet->columns);
}
static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
@@ -118,6 +119,12 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
BLI_addtail(&sspreadsheet_new->columns, new_column);
}
+ BLI_listbase_clear(&sspreadsheet_new->context_path);
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, src_context, &sspreadsheet_old->context_path) {
+ SpreadsheetContext *new_context = spreadsheet_context_copy(src_context);
+ BLI_addtail(&sspreadsheet_new->context_path, new_context);
+ }
+
return (SpaceLink *)sspreadsheet_new;
}
@@ -125,6 +132,24 @@ static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
{
}
+static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+ if ((ID *)object_context->object == old_id) {
+ if (new_id && GS(new_id->name) == ID_OB) {
+ object_context->object = (Object *)new_id;
+ }
+ else {
+ object_context->object = nullptr;
+ }
+ }
+ }
+ }
+}
+
static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
{
region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM;
@@ -139,20 +164,90 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
WM_event_add_keymap_handler(&region->handlers, keymap);
}
-static ID *get_used_id(const bContext *C)
+ID *ED_spreadsheet_get_current_id(struct SpaceSpreadsheet *sspreadsheet)
+{
+ if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
+ return nullptr;
+ }
+ SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first;
+ if (root_context->type != SPREADSHEET_CONTEXT_OBJECT) {
+ return nullptr;
+ }
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context;
+ return (ID *)object_context->object;
+}
+
+/* Check if the pinned context still exists. If it doesn't try to find a new context. */
+static void update_pinned_context_path_if_outdated(const bContext *C)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- if (sspreadsheet->pinned_id != nullptr) {
- return sspreadsheet->pinned_id;
+
+ /* Currently, this only checks if the object has been deleted. In the future we can have a more
+ * sophisticated check for the entire context (including modifier and nodes). */
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+ if (object_context->object == nullptr) {
+ ED_spreadsheet_context_path_clear(sspreadsheet);
+ break;
+ }
+ }
+ }
+ if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
+ Object *active_object = CTX_data_active_object(C);
+ if (active_object != nullptr) {
+ SpreadsheetContext *new_context = spreadsheet_context_new(SPREADSHEET_CONTEXT_OBJECT);
+ ((SpreadsheetContextObject *)new_context)->object = active_object;
+ BLI_addtail(&sspreadsheet->context_path, new_context);
+ }
}
+
+ if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
+ /* Don't pin empty context_path, that could be annoying. */
+ sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
+ }
+}
+
+static void update_context_path_from_context(const bContext *C)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
Object *active_object = CTX_data_active_object(C);
- return (ID *)active_object;
+ if (active_object == nullptr) {
+ ED_spreadsheet_context_path_clear(sspreadsheet);
+ return;
+ }
+ if (!BLI_listbase_is_empty(&sspreadsheet->context_path)) {
+ SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first;
+ if (root_context->type == SPREADSHEET_CONTEXT_OBJECT) {
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context;
+ if (object_context->object != active_object) {
+ ED_spreadsheet_context_path_clear(sspreadsheet);
+ }
+ }
+ }
+ if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
+ SpreadsheetContext *new_context = spreadsheet_context_new(SPREADSHEET_CONTEXT_OBJECT);
+ ((SpreadsheetContextObject *)new_context)->object = active_object;
+ BLI_addtail(&sspreadsheet->context_path, new_context);
+ }
+}
+
+static void update_context_path(const bContext *C)
+{
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
+ update_pinned_context_path_if_outdated(C);
+ }
+ else {
+ update_context_path_from_context(C);
+ }
}
static std::unique_ptr<DataSource> get_data_source(const bContext *C)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- ID *used_id = get_used_id(C);
+ SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ ID *used_id = ED_spreadsheet_get_current_id(sspreadsheet);
if (used_id == nullptr) {
return {};
}
@@ -227,6 +322,7 @@ static void update_visible_columns(ListBase &columns, DataSource &data_source)
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ update_context_path(C);
std::unique_ptr<DataSource> data_source = get_data_source(C);
if (!data_source) {
@@ -317,6 +413,7 @@ static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion
static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
{
+ update_context_path(C);
ED_region_header(C, region);
}
@@ -422,6 +519,7 @@ void ED_spacetype_spreadsheet(void)
st->duplicate = spreadsheet_duplicate;
st->operatortypes = spreadsheet_operatortypes;
st->keymap = spreadsheet_keymap;
+ st->id_remap = spreadsheet_id_remap;
/* regions: main window */
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.cc b/source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.cc
new file mode 100644
index 00000000000..7e23cd5c0f5
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.cc
@@ -0,0 +1,306 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_hash.h"
+#include "BLI_hash.hh"
+#include "BLI_hash_mm2a.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
+
+#include "ED_spreadsheet.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "spreadsheet_breadcrumb.hh"
+
+namespace blender::ed::spreadsheet {
+
+static SpreadsheetContextObject *spreadsheet_context_object_new()
+{
+ SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN(
+ sizeof(SpreadsheetContextObject), __func__);
+ context->base.type = SPREADSHEET_CONTEXT_OBJECT;
+ return context;
+}
+
+static SpreadsheetContextObject *spreadsheet_context_object_copy(
+ const SpreadsheetContextObject *src_context)
+{
+ SpreadsheetContextObject *new_context = spreadsheet_context_object_new();
+ new_context->object = src_context->object;
+ return new_context;
+}
+
+static void spreadsheet_context_object_hash(const SpreadsheetContextObject *context,
+ BLI_HashMurmur2A *mm2)
+{
+ BLI_hash_mm2a_add(mm2, (const uchar *)&context->object, sizeof(Object *));
+}
+
+static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
+{
+ MEM_freeN(context);
+}
+
+static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
+{
+ SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN(
+ sizeof(SpreadsheetContextModifier), __func__);
+ context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
+ return context;
+}
+
+static SpreadsheetContextModifier *spreadsheet_context_modifier_copy(
+ const SpreadsheetContextModifier *src_context)
+{
+ SpreadsheetContextModifier *new_context = spreadsheet_context_modifier_new();
+ if (src_context->modifier_name) {
+ new_context->modifier_name = BLI_strdup(src_context->modifier_name);
+ }
+ return new_context;
+}
+
+static void spreadsheet_context_modifier_hash(const SpreadsheetContextModifier *context,
+ BLI_HashMurmur2A *mm2)
+{
+ if (context->modifier_name) {
+ BLI_hash_mm2a_add(mm2, (const uchar *)context->modifier_name, strlen(context->modifier_name));
+ }
+}
+
+static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *context)
+{
+ if (context->modifier_name) {
+ MEM_freeN(context->modifier_name);
+ }
+ MEM_freeN(context);
+}
+
+static SpreadsheetContextNode *spreadsheet_context_node_new()
+{
+ SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN(
+ sizeof(SpreadsheetContextNode), __func__);
+ context->base.type = SPREADSHEET_CONTEXT_NODE;
+ return context;
+}
+
+static SpreadsheetContextNode *spreadsheet_context_node_copy(
+ const SpreadsheetContextNode *src_context)
+{
+ SpreadsheetContextNode *new_context = spreadsheet_context_node_new();
+ if (src_context->node_name) {
+ new_context->node_name = BLI_strdup(src_context->node_name);
+ }
+ return new_context;
+}
+
+static void spreadsheet_context_node_hash(const SpreadsheetContextNode *context,
+ BLI_HashMurmur2A *mm2)
+{
+ if (context->node_name) {
+ BLI_hash_mm2a_add(mm2, (const uchar *)context->node_name, strlen(context->node_name));
+ }
+}
+
+static void spreadsheet_context_node_free(SpreadsheetContextNode *context)
+{
+ if (context->node_name) {
+ MEM_freeN(context->node_name);
+ }
+ MEM_freeN(context);
+}
+
+SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type)
+{
+ switch (type) {
+ case SPREADSHEET_CONTEXT_OBJECT: {
+ return (SpreadsheetContext *)spreadsheet_context_object_new();
+ }
+ case SPREADSHEET_CONTEXT_MODIFIER: {
+ return (SpreadsheetContext *)spreadsheet_context_modifier_new();
+ }
+ case SPREADSHEET_CONTEXT_NODE: {
+ return (SpreadsheetContext *)spreadsheet_context_node_new();
+ }
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context)
+{
+ switch (old_context->type) {
+ case SPREADSHEET_CONTEXT_OBJECT: {
+ return (SpreadsheetContext *)spreadsheet_context_object_copy(
+ (const SpreadsheetContextObject *)old_context);
+ }
+ case SPREADSHEET_CONTEXT_MODIFIER: {
+ return (SpreadsheetContext *)spreadsheet_context_modifier_copy(
+ (const SpreadsheetContextModifier *)old_context);
+ }
+ case SPREADSHEET_CONTEXT_NODE: {
+ return (SpreadsheetContext *)spreadsheet_context_node_copy(
+ (const SpreadsheetContextNode *)old_context);
+ }
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void spreadsheet_context_hash(const SpreadsheetContext *context, BLI_HashMurmur2A *mm2)
+{
+ BLI_hash_mm2a_add_int(mm2, context->type);
+ switch (context->type) {
+ case SPREADSHEET_CONTEXT_OBJECT: {
+ spreadsheet_context_object_hash((const SpreadsheetContextObject *)context, mm2);
+ break;
+ }
+ case SPREADSHEET_CONTEXT_MODIFIER: {
+ spreadsheet_context_modifier_hash((const SpreadsheetContextModifier *)context, mm2);
+ break;
+ }
+ case SPREADSHEET_CONTEXT_NODE: {
+ spreadsheet_context_node_hash((const SpreadsheetContextNode *)context, mm2);
+ break;
+ }
+ }
+}
+
+void spreadsheet_context_free(SpreadsheetContext *context)
+{
+ switch (context->type) {
+ case SPREADSHEET_CONTEXT_OBJECT: {
+ return spreadsheet_context_object_free((SpreadsheetContextObject *)context);
+ }
+ case SPREADSHEET_CONTEXT_MODIFIER: {
+ return spreadsheet_context_modifier_free((SpreadsheetContextModifier *)context);
+ }
+ case SPREADSHEET_CONTEXT_NODE: {
+ return spreadsheet_context_node_free((SpreadsheetContextNode *)context);
+ }
+ }
+ BLI_assert_unreachable();
+}
+
+/**
+ * Tag any data relevant to the spreadsheet's context for recalculation in order to collect
+ * information to display in the editor, which may be cached during evaluation.
+ */
+static void spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet)
+{
+ using namespace blender;
+ Vector<const SpreadsheetContext *> context_path = sspreadsheet->context_path;
+ if (context_path.is_empty()) {
+ return;
+ }
+ if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
+ return;
+ }
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
+ Object *object = object_context->object;
+ if (object == nullptr) {
+ return;
+ }
+ if (context_path.size() == 1) {
+ /* No need to reevaluate, when the final or original object is viewed. */
+ return;
+ }
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+}
+
+} // namespace blender::ed::spreadsheet
+
+SpreadsheetContext *ED_spreadsheet_context_new(int type)
+{
+ return blender::ed::spreadsheet::spreadsheet_context_new((eSpaceSpreadsheet_ContextType)type);
+}
+
+void ED_spreadsheet_context_free(struct SpreadsheetContext *context)
+{
+ blender::ed::spreadsheet::spreadsheet_context_free(context);
+}
+
+void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet)
+{
+ LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ ED_spreadsheet_context_free(context);
+ }
+ BLI_listbase_clear(&sspreadsheet->context_path);
+}
+
+void ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet)
+{
+ blender::ed::spreadsheet::spreadsheet_context_update_tag(sspreadsheet);
+}
+
+uint64_t ED_spreadsheet_context_path_hash(SpaceSpreadsheet *sspreadsheet)
+{
+ BLI_HashMurmur2A mm2;
+ BLI_hash_mm2a_init(&mm2, 1234);
+ LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
+ blender::ed::spreadsheet::spreadsheet_context_hash(context, &mm2);
+ }
+ return BLI_hash_mm2a_end(&mm2);
+}
+
+void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsheet,
+ struct SpaceNode *snode,
+ struct bNode *node)
+{
+ using namespace blender::ed::spreadsheet;
+ ED_spreadsheet_context_path_clear(sspreadsheet);
+
+ Object *object = (Object *)snode->id;
+ ModifierData *modifier = BKE_object_active_modifier(object);
+
+ {
+ SpreadsheetContextObject *context = spreadsheet_context_object_new();
+ context->object = object;
+ BLI_addtail(&sspreadsheet->context_path, context);
+ }
+ {
+ SpreadsheetContextModifier *context = spreadsheet_context_modifier_new();
+ context->modifier_name = BLI_strdup(modifier->name);
+ BLI_addtail(&sspreadsheet->context_path, context);
+ }
+ {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
+ if (i == 0) {
+ continue;
+ }
+ SpreadsheetContextNode *context = spreadsheet_context_node_new();
+ context->node_name = BLI_strdup(path->node_name);
+ BLI_addtail(&sspreadsheet->context_path, context);
+ }
+ }
+ {
+ SpreadsheetContextNode *context = spreadsheet_context_node_new();
+ context->node_name = BLI_strdup(node->name);
+ BLI_addtail(&sspreadsheet->context_path, context);
+ }
+
+ sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED;
+}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.hh b/source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.hh
new file mode 100644
index 00000000000..d71769e42b3
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_breadcrumb.hh
@@ -0,0 +1,27 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "DNA_space_types.h"
+
+namespace blender::ed::spreadsheet {
+
+SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type);
+SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context);
+void spreadsheet_context_free(SpreadsheetContext *context);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index f33a6473d45..dc85d86e776 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -29,6 +29,8 @@
#include "DEG_depsgraph_query.h"
+#include "ED_spreadsheet.h"
+
#include "bmesh.h"
#include "spreadsheet_data_source_geometry.hh"
@@ -396,7 +398,7 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
}
}
- else {
+ else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED) {
if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
if (mesh == nullptr) {
@@ -408,16 +410,23 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
mesh_component.copy_vertex_group_names_from_object(*object_eval);
}
else {
- if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
- if (object_eval->runtime.geometry_set_preview != nullptr) {
- geometry_set = *object_eval->runtime.geometry_set_preview;
- }
- }
- else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
+ if (BLI_listbase_count(&sspreadsheet->context_path) == 1) {
+ /* Use final evaluated object. */
if (object_eval->runtime.geometry_set_eval != nullptr) {
geometry_set = *object_eval->runtime.geometry_set_eval;
}
}
+ else {
+ if (object_eval->runtime.geometry_set_previews != nullptr) {
+ GHash *ghash = (GHash *)object_eval->runtime.geometry_set_previews;
+ const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
+ GeometrySet *geometry_set_preview = (GeometrySet *)BLI_ghash_lookup_default(
+ ghash, POINTER_FROM_UINT(key), nullptr);
+ if (geometry_set_preview != nullptr) {
+ geometry_set = *geometry_set_preview;
+ }
+ }
+ }
}
}
return geometry_set;
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index cf2b6ee19d5..54ec6b22e70 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -86,6 +86,7 @@ set(SRC
../include/ED_sequencer.h
../include/ED_sound.h
../include/ED_space_api.h
+ ../include/ED_spreadsheet.h
../include/ED_text.h
../include/ED_time_scrub_ui.h
../include/ED_transform.h
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 9822aa4f7e4..aa1178fb139 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -169,9 +169,10 @@ typedef struct Object_Runtime {
struct GeometrySet *geometry_set_eval;
/**
- * Data from this geometry set is previewed in the spreadsheet editor.
+ * A GHash that contains geometry sets for intermediate stages of evaluation. The keys are just a
+ * hash and are not owned by the map. The geometry sets are owned.
*/
- struct GeometrySet *geometry_set_preview;
+ void *geometry_set_previews;
/**
* Mesh structure created during object evaluation.
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 747e392b529..ab74282eb64 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1870,6 +1870,32 @@ typedef struct SpreadsheetColumn {
SpreadsheetColumnID *id;
} SpreadsheetColumn;
+/**
+ * An item in SpaceSpreadsheet.context_path.
+ * This is a bases struct for the structs below.
+ */
+typedef struct SpreadsheetContext {
+ struct SpreadsheetContext *next, *prev;
+ /* eSpaceSpreadsheet_ContextType. */
+ int type;
+ char _pad[4];
+} SpreadsheetContext;
+
+typedef struct SpreadsheetContextObject {
+ SpreadsheetContext base;
+ struct Object *object;
+} SpreadsheetContextObject;
+
+typedef struct SpreadsheetContextModifier {
+ SpreadsheetContext base;
+ char *modifier_name;
+} SpreadsheetContextModifier;
+
+typedef struct SpreadsheetContextNode {
+ SpreadsheetContext base;
+ char *node_name;
+} SpreadsheetContextNode;
+
typedef struct SpaceSpreadsheet {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1882,7 +1908,13 @@ typedef struct SpaceSpreadsheet {
/* List of #SpreadsheetColumn. */
ListBase columns;
- struct ID *pinned_id;
+ /**
+ * List of #SpreadsheetContext.
+ * This is a path to the data that is displayed in the spreadsheet.
+ * It can be set explicitely by an action of the user (e.g. clicking the preview icon in a
+ * geometry node) or it can be derived from context automatically based on some heuristic.
+ */
+ ListBase context_path;
/* eSpaceSpreadsheet_FilterFlag. */
uint8_t filter_flag;
@@ -1894,21 +1926,32 @@ typedef struct SpaceSpreadsheet {
/* eSpaceSpreadsheet_ObjectContext. */
uint8_t object_eval_state;
- char _pad1[4];
+ /* eSpaceSpreadsheet_Flag. */
+ uint32_t flag;
SpaceSpreadsheet_Runtime *runtime;
} SpaceSpreadsheet;
+typedef enum eSpaceSpreadsheet_Flag {
+ SPREADSHEET_FLAG_PINNED = (1 << 0),
+ SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED = (1 << 1),
+} eSpaceSpreadsheet_Flag;
+
typedef enum eSpaceSpreadsheet_FilterFlag {
SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
} eSpaceSpreadsheet_FilterFlag;
typedef enum eSpaceSpreadsheet_ObjectEvalState {
- SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0,
+ SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED = 0,
SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
- SPREADSHEET_OBJECT_EVAL_STATE_NODE = 2,
} eSpaceSpreadsheet_Context;
+typedef enum eSpaceSpreadsheet_ContextType {
+ SPREADSHEET_CONTEXT_OBJECT = 0,
+ SPREADSHEET_CONTEXT_MODIFIER = 1,
+ SPREADSHEET_CONTEXT_NODE = 2,
+} eSpaceSpreadsheet_ContextType;
+
/**
* We can't just use UI_UNIT_X, because it does not take `widget.points` into account, which
* modifies the width of text as well.
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index ba67cedfdbe..54e077c624c 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -614,6 +614,10 @@ extern StructRNA RNA_Spline;
extern StructRNA RNA_SplineIKConstraint;
extern StructRNA RNA_SplinePoint;
extern StructRNA RNA_SpotLight;
+extern StructRNA RNA_SpreadsheetContext;
+extern StructRNA RNA_SpreadsheetContextObject;
+extern StructRNA RNA_SpreadsheetContextModifier;
+extern StructRNA RNA_SpreadsheetContextNode;
extern StructRNA RNA_Stereo3dDisplay;
extern StructRNA RNA_StretchToConstraint;
extern StructRNA RNA_StringAttribute;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 21460607e38..b0254ce2ef3 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -10829,6 +10829,12 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Texture", "Display node in viewport textured shading mode");
RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "active_preview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_ACTIVE_PREVIEW);
+ RNA_def_property_ui_text(prop, "Active Preview", "Node is previewed in other editor");
+ RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
+ RNA_def_property_update(prop, NC_NODE, NULL);
+
/* generic property update function */
func = RNA_def_function(srna, "socket_value_update", "rna_Node_socket_value_update");
RNA_def_function_ui_description(func, "Update after property changes");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 2af8a58c137..2a513691762 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -34,6 +34,7 @@
#include "BKE_node.h"
#include "BKE_studiolight.h"
+#include "ED_spreadsheet.h"
#include "ED_text.h"
#include "BLI_listbase.h"
@@ -3037,14 +3038,6 @@ static void rna_SpaceFileBrowser_browse_mode_update(Main *UNUSED(bmain),
ED_area_tag_refresh(area);
}
-static void rna_SpaceSpreadsheet_pinned_id_set(PointerRNA *ptr,
- PointerRNA value,
- struct ReportList *UNUSED(reports))
-{
- SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
- sspreadsheet->pinned_id = value.data;
-}
-
static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -3055,7 +3048,7 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma
}
}
-const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
+const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
bool *r_free)
@@ -3063,16 +3056,16 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
GeometryComponentType component_type = sspreadsheet->geometry_component_type;
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
- Object *active_object = CTX_data_active_object(C);
- Object *used_object = (sspreadsheet->pinned_id && GS(sspreadsheet->pinned_id->name) == ID_OB) ?
- (Object *)sspreadsheet->pinned_id :
- active_object;
- if (used_object != NULL) {
- if (used_object->type == OB_POINTCLOUD) {
- component_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
- }
- else {
- component_type = GEO_COMPONENT_TYPE_MESH;
+ ID *used_id = ED_spreadsheet_get_current_id(sspreadsheet);
+ if (used_id != NULL) {
+ if (GS(used_id->name) == ID_OB) {
+ Object *used_object = (Object *)used_id;
+ if (used_object->type == OB_POINTCLOUD) {
+ component_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
+ }
+ else {
+ component_type = GEO_COMPONENT_TYPE_MESH;
+ }
}
}
}
@@ -3111,6 +3104,61 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
return item_array;
}
+static SpreadsheetContext *rna_SpaceSpreadsheet_context_path_append(SpaceSpreadsheet *sspreadsheet,
+ int type)
+{
+ SpreadsheetContext *context = ED_spreadsheet_context_new(type);
+ BLI_addtail(&sspreadsheet->context_path, context);
+ ED_spreadsheet_context_path_update_tag(sspreadsheet);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ return context;
+}
+
+static void rna_SpaceSpreadsheet_context_path_clear(SpaceSpreadsheet *sspreadsheet)
+{
+ ED_spreadsheet_context_path_clear(sspreadsheet);
+ ED_spreadsheet_context_path_update_tag(sspreadsheet);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+}
+
+static StructRNA *rna_spreadsheet_context_refine(PointerRNA *ptr)
+{
+ SpreadsheetContext *context = ptr->data;
+ switch (context->type) {
+ case SPREADSHEET_CONTEXT_OBJECT:
+ return &RNA_SpreadsheetContextObject;
+ case SPREADSHEET_CONTEXT_MODIFIER:
+ return &RNA_SpreadsheetContextModifier;
+ case SPREADSHEET_CONTEXT_NODE:
+ return &RNA_SpreadsheetContextNode;
+ }
+ BLI_assert_unreachable();
+ return NULL;
+}
+
+static void rna_spreadsheet_context_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ bScreen *screen = (bScreen *)ptr->owner_id;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ SpaceLink *sl = area->spacedata.first;
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
+ ED_spreadsheet_context_path_update_tag(sspreadsheet);
+ }
+ }
+}
+
+static void rna_spreadsheet_set_geometry_node_context(SpaceSpreadsheet *sspreadsheet,
+ SpaceNode *snode,
+ bNode *node)
+{
+ ED_spreadsheet_set_geometry_node_context(sspreadsheet, snode, node);
+ ED_spreadsheet_context_path_update_tag(sspreadsheet);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+}
+
#else
static const EnumPropertyItem dt_uv_items[] = {
@@ -7338,10 +7386,93 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
}
-static void rna_def_space_spreadsheet(BlenderRNA *brna)
+static const EnumPropertyItem spreadsheet_context_type_items[] = {
+ {SPREADSHEET_CONTEXT_OBJECT, "OBJECT", ICON_NONE, "Object", ""},
+ {SPREADSHEET_CONTEXT_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
+ {SPREADSHEET_CONTEXT_NODE, "NODE", ICON_NONE, "Node", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void rna_def_space_spreadsheet_context(BlenderRNA *brna)
{
+ StructRNA *srna;
PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SpreadsheetContext", NULL);
+ RNA_def_struct_ui_text(srna, "Spreadsheet Context", "Element of spreadsheet context path");
+ RNA_def_struct_refine_func(srna, "rna_spreadsheet_context_refine");
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, spreadsheet_context_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of the context");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
+static void rna_def_space_spreadsheet_context_object(BlenderRNA *brna)
+{
StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SpreadsheetContextObject", "SpreadsheetContext");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
+}
+
+static void rna_def_space_spreadsheet_context_modifier(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SpreadsheetContextModifier", "SpreadsheetContext");
+
+ prop = RNA_def_property(srna, "modifier_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Modifier Name", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
+}
+
+static void rna_def_space_spreadsheet_context_node(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SpreadsheetContextNode", "SpreadsheetContext");
+
+ prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Node Name", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
+}
+
+static void rna_def_space_spreadsheet_context_path(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *parm;
+ FunctionRNA *func;
+
+ RNA_def_property_srna(cprop, "SpreadsheetContextPath");
+ srna = RNA_def_struct(brna, "SpreadsheetContextPath", NULL);
+ RNA_def_struct_sdna(srna, "SpaceSpreadsheet");
+
+ func = RNA_def_function(srna, "append", "rna_SpaceSpreadsheet_context_path_append");
+ RNA_def_function_ui_description(func, "Append a context path element");
+ parm = RNA_def_property(func, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_enum_items(parm, spreadsheet_context_type_items);
+ parm = RNA_def_pointer(
+ func, "context", "SpreadsheetContext", "", "Newly created context path element");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "clear", "rna_SpaceSpreadsheet_context_path_clear");
+ RNA_def_function_ui_description(func, "Clear entire context path");
+}
+
+static void rna_def_space_spreadsheet(BlenderRNA *brna)
+{
+ PropertyRNA *prop, *parm;
+ StructRNA *srna;
+ FunctionRNA *func;
static const EnumPropertyItem geometry_component_type_items[] = {
{GEO_COMPONENT_TYPE_MESH,
@@ -7363,35 +7494,44 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
};
static const EnumPropertyItem object_eval_state_items[] = {
- {SPREADSHEET_OBJECT_EVAL_STATE_FINAL,
- "FINAL",
+ {SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED,
+ "EVALUATED",
ICON_NONE,
- "Final",
- "Use data from object with all modifiers applied"},
+ "Evaluated",
+ "Use data from fully or partially evaluated object"},
{SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL,
"ORIGINAL",
ICON_NONE,
"Original",
"Use data from original object without any modifiers applied"},
- {SPREADSHEET_OBJECT_EVAL_STATE_NODE,
- "NODE",
- ICON_NONE,
- "Node",
- "Use data from the first geometry output of the node tagged for preview"},
{0, NULL, 0, NULL, NULL},
};
+ rna_def_space_spreadsheet_context(brna);
+ rna_def_space_spreadsheet_context_object(brna);
+ rna_def_space_spreadsheet_context_modifier(brna);
+ rna_def_space_spreadsheet_context_node(brna);
+
srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_FOOTER));
- prop = RNA_def_property(srna, "pinned_id", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceSpreadsheet_pinned_id_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Pinned ID", "Data-block whose values are displayed");
+ prop = RNA_def_property(srna, "is_pinned", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_PINNED);
+ RNA_def_property_ui_text(prop, "Is Pinned", "Context path is pinned");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ prop = RNA_def_property(srna, "display_context_path_collapsed", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED);
+ RNA_def_property_ui_text(prop, "Display Context Path Collapsed", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ prop = RNA_def_property(srna, "context_path", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SpreadsheetContext");
+ RNA_def_property_ui_text(prop, "Context Path", "Context path to the data being displayed");
+ rna_def_space_spreadsheet_context_path(brna, prop);
+
prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
RNA_def_property_ui_text(
@@ -7416,6 +7556,16 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_enum_items(prop, object_eval_state_items);
RNA_def_property_ui_text(prop, "Object Evaluation State", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
+ func = RNA_def_function(
+ srna, "set_geometry_node_context", "rna_spreadsheet_set_geometry_node_context");
+ RNA_def_function_ui_description(
+ func, "Update context_path to point to a specific node in a node editor");
+ parm = RNA_def_pointer(
+ func, "node_editor", "SpaceNodeEditor", "", "Editor to take the context from");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "node", "Node", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_def_space(BlenderRNA *brna)
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 49f2d66e54a..fd798b743c9 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -29,6 +29,7 @@
#include "BLI_float3.hh"
#include "BLI_listbase.h"
+#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -76,6 +77,8 @@
#include "MOD_nodes.h"
#include "MOD_ui_common.h"
+#include "ED_spreadsheet.h"
+
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry.h"
#include "NOD_geometry_exec.hh"
@@ -1101,108 +1104,129 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
}
}
-static const DTreeContext *find_derived_tree_context_that_matches_tree_path(
- const SpaceNode &snode, const DerivedNodeTree &tree)
+static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
{
- const DTreeContext &root_context = tree.root_context();
- bNodeTree *root_tree_eval = root_context.tree().btree();
- bNodeTree *root_tree_orig = (bNodeTree *)DEG_get_original_id(&root_tree_eval->id);
- if (snode.nodetree != root_tree_orig) {
- return nullptr;
- }
-
- const DTreeContext *current_context = &root_context;
- bool is_first = true;
- LISTBASE_FOREACH (const bNodeTreePath *, path, &snode.treepath) {
- if (is_first) {
- is_first = false;
- continue;
- }
- StringRef parent_node_name = path->node_name;
- const NodeTreeRef &tree_ref = current_context->tree();
- const NodeRef *parent_node_ref = nullptr;
- for (const NodeRef *node_ref : tree_ref.nodes()) {
- if (node_ref->name() == parent_node_name) {
- parent_node_ref = node_ref;
- break;
+ Vector<SpaceSpreadsheet *> spreadsheets;
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
+ LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
+ bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ SpaceLink *sl = (SpaceLink *)area->spacedata.first;
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ spreadsheets.append((SpaceSpreadsheet *)sl);
}
}
- if (parent_node_ref == nullptr) {
- return nullptr;
- }
- current_context = current_context->child_context(*parent_node_ref);
- if (current_context == nullptr) {
- return nullptr;
- }
}
- return current_context;
+ return spreadsheets;
}
-static DNode find_active_preview_node_in_node_editor(const SpaceNode &snode,
- const DerivedNodeTree &tree)
+using PreviewSocketMap = blender::MultiValueMap<DSocket, uint64_t>;
+
+static DSocket try_find_preview_socket_in_node(const DNode node)
{
- const DTreeContext *context = find_derived_tree_context_that_matches_tree_path(snode, tree);
- if (context == nullptr) {
- return {};
+ for (const SocketRef *socket : node->outputs()) {
+ if (socket->bsocket()->type == SOCK_GEOMETRY) {
+ return {node.context(), socket};
+ }
}
- const NodeTreeRef &tree_ref = context->tree();
- for (const NodeRef *node_ref : tree_ref.nodes()) {
- if (node_ref->bnode()->flag & NODE_ACTIVE_PREVIEW) {
- return {context, node_ref};
+ for (const SocketRef *socket : node->inputs()) {
+ if (socket->bsocket()->type == SOCK_GEOMETRY &&
+ (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) {
+ return {node.context(), socket};
}
}
return {};
}
-static DNode find_active_preview_node_in_all_node_editors(Depsgraph *depsgraph,
- const DerivedNodeTree &tree)
+static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
+ NodesModifierData *nmd,
+ const ModifierEvalContext *ctx,
+ const DerivedNodeTree &tree)
{
- Main *bmain = DEG_get_bmain(depsgraph);
- wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
- LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = (SpaceLink *)area->spacedata.first;
- if (sl->spacetype != SPACE_NODE) {
- continue;
- }
- SpaceNode *snode = (SpaceNode *)sl;
- DNode preview_node = find_active_preview_node_in_node_editor(*snode, tree);
- if (!preview_node) {
- continue;
+ Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
+ if (context_path.size() < 3) {
+ return {};
+ }
+ if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
+ return {};
+ }
+ if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
+ return {};
+ }
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
+ if (object_context->object != DEG_get_original_object(ctx->object)) {
+ return {};
+ }
+ SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
+ if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) {
+ return {};
+ }
+ for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
+ if (context->type != SPREADSHEET_CONTEXT_NODE) {
+ return {};
+ }
+ }
+
+ Span<SpreadsheetContextNode *> nested_group_contexts =
+ context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>();
+ SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last();
+
+ const DTreeContext *context = &tree.root_context();
+ for (SpreadsheetContextNode *node_context : nested_group_contexts) {
+ const NodeTreeRef &tree_ref = context->tree();
+ const NodeRef *found_node = nullptr;
+ for (const NodeRef *node_ref : tree_ref.nodes()) {
+ if (node_ref->name() == node_context->node_name) {
+ found_node = node_ref;
+ break;
}
- return preview_node;
+ }
+ if (found_node == nullptr) {
+ return {};
+ }
+ context = context->child_context(*found_node);
+ if (context == nullptr) {
+ return {};
+ }
+ }
+
+ const NodeTreeRef &tree_ref = context->tree();
+ for (const NodeRef *node_ref : tree_ref.nodes()) {
+ if (node_ref->name() == last_context->node_name) {
+ return try_find_preview_socket_in_node({context, node_ref});
}
}
return {};
}
-static DSocket find_preview_socket_in_all_node_editors(Depsgraph *depsgraph,
- const DerivedNodeTree &tree)
+static void find_sockets_to_preview(NodesModifierData *nmd,
+ const ModifierEvalContext *ctx,
+ const DerivedNodeTree &tree,
+ PreviewSocketMap &r_sockets_to_preview)
{
- DNode preview_node = find_active_preview_node_in_all_node_editors(depsgraph, tree);
- if (!preview_node) {
- return {};
- }
- for (const SocketRef *socket : preview_node->outputs()) {
- if (socket->bsocket()->type == SOCK_GEOMETRY) {
- return {preview_node.context(), socket};
- }
- }
- for (const SocketRef *socket : preview_node->inputs()) {
- if (socket->bsocket()->type == SOCK_GEOMETRY &&
- (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) {
- return {preview_node.context(), socket};
+ Main *bmain = DEG_get_bmain(ctx->depsgraph);
+
+ /* Based on every visible spreadsheet context path, get a list of sockets that need to have their
+ * intermediate geometries cached for display. */
+ Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain);
+ for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
+ const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree);
+ if (socket) {
+ const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
+ r_sockets_to_preview.add_non_duplicates(socket, key);
}
}
- return {};
}
-static void log_preview_socket_value(const Span<GPointer> values, Object *object)
+static void log_preview_socket_value(const Span<GPointer> values,
+ Object *object,
+ Span<uint64_t> keys)
{
GeometrySet geometry_set = *(const GeometrySet *)values[0].get();
geometry_set.ensure_owns_direct_data();
- BKE_object_set_preview_geometry_set(object, new GeometrySet(std::move(geometry_set)));
+ for (uint64_t key : keys) {
+ BKE_object_preview_geometry_set_add(object, key, new GeometrySet(geometry_set));
+ }
}
/**
@@ -1260,11 +1284,16 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
Vector<DInputSocket> group_outputs;
group_outputs.append({root_context, &socket_to_compute});
- const DSocket preview_socket = find_preview_socket_in_all_node_editors(ctx->depsgraph, tree);
+ PreviewSocketMap preview_sockets;
+ find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) {
- if (socket == preview_socket && nmd->modifier.flag & eModifierFlag_Active) {
- log_preview_socket_value(values, ctx->object);
+ if (!DEG_is_active(ctx->depsgraph)) {
+ return;
+ }
+ Span<uint64_t> keys = preview_sockets.lookup(socket);
+ if (!keys.is_empty()) {
+ log_preview_socket_value(values, ctx->object, keys);
}
};