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:
-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);
}
};