diff options
Diffstat (limited to 'source/blender/editors/space_spreadsheet')
5 files changed, 458 insertions, 16 deletions
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; |