diff options
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(®ion->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); } }; |