From 6ca21e337f28afd1e2fc015bb73120a69ed936d5 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 12:21:50 +0200 Subject: [PATCH 01/17] initial instances --- .../editors/space_node/node_relationships.cc | 2 +- .../space_spreadsheet/space_spreadsheet.cc | 8 ++++++ .../spreadsheet_dataset_draw.cc | 26 ++++++++++++++++--- source/blender/makesdna/DNA_space_types.h | 8 +++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 469291c83db..d9f721d38da 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -1212,7 +1212,7 @@ static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag) } /* Before actually adding the link let nodes perform special link insertion handling. */ - bNodeLink *new_link = MEM_new(__func__, link); + bNodeLink *new_link = MEM_cnew(__func__, link); if (link.fromnode->typeinfo->insert_link) { if (!link.fromnode->typeinfo->insert_link(&ntree, link.fromnode, new_link)) { MEM_freeN(new_link); diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 64f69d9b95f..6f250619946 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -107,6 +107,7 @@ static void spreadsheet_free(SpaceLink *sl) LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) { spreadsheet_column_free(column); } + MEM_SAFE_FREE(sspreadsheet->instance_ids); BKE_viewer_path_clear(&sspreadsheet->viewer_path); } @@ -141,6 +142,8 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) BLI_addtail(&sspreadsheet_new->columns, new_column); } + sspreadsheet_new->instance_ids = static_cast( + MEM_dupallocN(sspreadsheet_old->instance_ids)); BKE_viewer_path_copy(&sspreadsheet_new->viewer_path, &sspreadsheet_old->viewer_path); return (SpaceLink *)sspreadsheet_new; @@ -688,6 +691,9 @@ static void spreadsheet_blend_read_data(BlendDataReader *reader, SpaceLink *sl) BLO_read_string(reader, &column->display_name); } + BLO_read_struct_array( + reader, SpreadsheetInstanceID, sspreadsheet->instance_ids_num, &sspreadsheet->instance_ids); + BKE_viewer_path_blend_read_data(reader, &sspreadsheet->viewer_path); } @@ -711,6 +717,8 @@ static void spreadsheet_blend_write(BlendWriter *writer, SpaceLink *sl) BLO_write_string(writer, column->display_name); } + BLO_write_struct_array( + writer, SpreadsheetInstanceID, sspreadsheet->instance_ids_num, sspreadsheet->instance_ids); BKE_viewer_path_blend_write(writer, &sspreadsheet->viewer_path); } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 9465aaa70b9..74709db7dbd 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -10,6 +10,7 @@ #include "BKE_context.hh" #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "BKE_instances.hh" #include "BKE_volume.hh" #include "RNA_access.hh" @@ -119,6 +120,26 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView { } } + void build_instances() + { + GeometryDataSetTreeViewItem &instances_item = this->add_tree_item( + bke::GeometryComponent::Type::Instance, + bke::AttrDomain::Instance, + IFACE_("Instances"), + ICON_EMPTY_AXIS); + + if (!geometry_set_.has_instances()) { + return; + } + const bke::Instances &instances = *geometry_set_.get_instances(); + const Span references = instances.references(); + for (const int reference_i : references.index_range()) { + const bke::InstanceReference &reference = references[reference_i]; + instances_item.add_tree_item( + bke::GeometryComponent::Type::Mesh, "test", ICON_MESH_CAPSULE); + } + } + void build_tree() override { GeometryDataSetTreeViewItem &mesh = this->add_tree_item( @@ -162,10 +183,7 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView { this->add_tree_item( bke::GeometryComponent::Type::Volume, IFACE_("Volume Grids"), ICON_VOLUME_DATA); - this->add_tree_item(bke::GeometryComponent::Type::Instance, - bke::AttrDomain::Instance, - IFACE_("Instances"), - ICON_EMPTY_AXIS); + this->build_instances(); } }; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index f7b884145cc..7e2541d4eda 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1953,6 +1953,10 @@ typedef struct SpreadsheetColumn { char *display_name; } SpreadsheetColumn; +typedef struct SpreadsheetInstanceID { + int reference_index; +} SpreadsheetInstanceID; + typedef struct SpaceSpreadsheet { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1975,6 +1979,9 @@ typedef struct SpaceSpreadsheet { */ ViewerPath viewer_path; + SpreadsheetInstanceID *instance_ids; + int instance_ids_num; + /* eSpaceSpreadsheet_FilterFlag. */ uint8_t filter_flag; @@ -1989,7 +1996,6 @@ typedef struct SpaceSpreadsheet { /* eSpaceSpreadsheet_Flag. */ uint32_t flag; - char _pad1[4]; SpaceSpreadsheet_Runtime *runtime; } SpaceSpreadsheet; -- 2.30.2 From a9db8b54bd42c3deeaff25a49ad67c15563e02da Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 17:22:07 +0200 Subject: [PATCH 02/17] refactor tree view --- .../spreadsheet_dataset_draw.cc | 764 ++++++++++++------ 1 file changed, 525 insertions(+), 239 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 74709db7dbd..da0ef15f3a7 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -4,6 +4,9 @@ #include "BLI_string.h" +#include "DNA_curves_types.h" +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" @@ -30,288 +33,571 @@ namespace blender::ed::spreadsheet { class GeometryDataSetTreeView; -class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { - bke::GeometryComponent::Type component_type_; - std::optional layer_index_; - std::optional domain_; - BIFIconID icon_; +struct GeometryDataIdentifier { + bke::GeometryComponent::Type component_type; + std::optional layer_index; + std::optional domain; +}; - public: - GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, - StringRef label, - BIFIconID icon); - GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, - int layer_index, - StringRef label, - BIFIconID icon); - GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, - bke::AttrDomain domain, - StringRef label, - BIFIconID icon); - GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, - int layer_index, - bke::AttrDomain domain, - StringRef label, - BIFIconID icon); +static void draw_count(ui::AbstractTreeViewItem &view_item, const int count) +{ + /* Using the tree row button instead of a separate right aligned button gives padding + * to the right side of the number, which it didn't have with the button. */ + char element_count[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE]; + BLI_str_format_decimal_unit(element_count, count); + UI_but_hint_drawstr_set(reinterpret_cast(view_item.view_item_button()), element_count); +} + +static StringRefNull mesh_domain_to_label(const bke::AttrDomain domain) +{ + switch (domain) { + case bke::AttrDomain::Point: + return IFACE_("Vertex"); + case bke::AttrDomain::Edge: + return IFACE_("Edge"); + case bke::AttrDomain::Face: + return IFACE_("Face"); + case bke::AttrDomain::Corner: + return IFACE_("Face Corner"); + default: + BLI_assert_unreachable(); + return ""; + } +} + +static StringRefNull curves_domain_to_label(const bke::AttrDomain domain) +{ + switch (domain) { + case bke::AttrDomain::Point: + return IFACE_("Control Point"); + case bke::AttrDomain::Curve: + return IFACE_("Spline"); + default: + BLI_assert_unreachable(); + return ""; + } +} + +static BIFIconID mesh_domain_to_icon(const bke::AttrDomain domain) +{ + switch (domain) { + case bke::AttrDomain::Point: + return ICON_VERTEXSEL; + case bke::AttrDomain::Edge: + return ICON_EDGESEL; + case bke::AttrDomain::Face: + return ICON_FACESEL; + case bke::AttrDomain::Corner: + return ICON_FACE_CORNER; + default: + BLI_assert_unreachable(); + return ICON_NONE; + } +} + +static BIFIconID curves_domain_to_icon(const bke::AttrDomain domain) +{ + switch (domain) { + case bke::AttrDomain::Point: + return ICON_CURVE_BEZCIRCLE; + case bke::AttrDomain::Curve: + return ICON_CURVE_PATH; + default: + BLI_assert_unreachable(); + return ICON_NONE; + } +} + +class DataSetViewItem : public ui::AbstractTreeViewItem { + private: + GeometryDataSetTreeView &get_tree() const; + + void get_parent_instance_ids(Vector &r_instance_ids) const; void on_activate(bContext &C) override; - void build_row(uiLayout &row) override; - - protected: std::optional should_be_active() const override; - bool supports_collapsing() const override; + virtual std::optional get_exact_data_id() const + { + return std::nullopt; + } + + virtual std::optional get_data_id_to_activate() const + { + return this->get_exact_data_id(); + } +}; + +class MeshViewItem : public DataSetViewItem { + public: + MeshViewItem() + { + label_ = IFACE_("Mesh"); + } + + std::optional get_data_id_to_activate() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::Mesh, std::nullopt, bke::AttrDomain::Point}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_MESH_DATA); + } +}; + +class MeshDomainViewItem : public DataSetViewItem { private: - GeometryDataSetTreeView &get_tree() const; - std::optional count() const; + const Mesh *mesh_; + bke::AttrDomain domain_; + + public: + MeshDomainViewItem(const Mesh *mesh, const bke::AttrDomain domain) : mesh_(mesh), domain_(domain) + { + label_ = mesh_domain_to_label(domain); + } + + std::optional get_exact_data_id() const override + { + return GeometryDataIdentifier{bke::GeometryComponent::Type::Mesh, std::nullopt, domain_}; + } + + void build_row(uiLayout &row) + { + const BIFIconID icon = mesh_domain_to_icon(domain_); + uiItemL(&row, label_.c_str(), icon); + + const int count = mesh_ ? mesh_->attributes().domain_size(domain_) : 0; + draw_count(*this, count); + } +}; + +class CurvesViewItem : public DataSetViewItem { + public: + CurvesViewItem() + { + label_ = IFACE_("Curve"); + } + + std::optional get_data_id_to_activate() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::Curve, std::nullopt, bke::AttrDomain::Point}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_CURVE_DATA); + } +}; + +class CurvesDomainViewItem : public DataSetViewItem { + private: + const Curves *curves_; + bke::AttrDomain domain_; + + public: + CurvesDomainViewItem(const Curves *curves, const bke::AttrDomain domain) + : curves_(curves), domain_(domain) + { + label_ = curves_domain_to_label(domain); + } + + std::optional get_exact_data_id() const override + { + return GeometryDataIdentifier{bke::GeometryComponent::Type::Curve, std::nullopt, domain_}; + } + + void build_row(uiLayout &row) + { + const BIFIconID icon = curves_domain_to_icon(domain_); + uiItemL(&row, label_.c_str(), icon); + + const int count = curves_ ? curves_->geometry.wrap().attributes().domain_size(domain_) : 0; + draw_count(*this, count); + } +}; + +class GreasePencilViewItem : public DataSetViewItem { + public: + GreasePencilViewItem() + { + label_ = IFACE_("Grease Pencil"); + } + + std::optional get_data_id_to_activate() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::GreasePencil, std::nullopt, bke::AttrDomain::Layer}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_OUTLINER_DATA_GREASEPENCIL); + } +}; + +class GreasePencilLayersViewItem : public DataSetViewItem { + private: + const GreasePencil *grease_pencil_; + + public: + GreasePencilLayersViewItem(const GreasePencil *grease_pencil) : grease_pencil_(grease_pencil) + { + label_ = IFACE_("Layer"); + } + + std::optional get_exact_data_id() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::GreasePencil, std::nullopt, bke::AttrDomain::Layer}; + } + + void build_row(uiLayout &row) override + { + const int count = grease_pencil_ ? grease_pencil_->layers().size() : 0; + uiItemL(&row, label_.c_str(), ICON_OUTLINER_DATA_GP_LAYER); + draw_count(*this, count); + } +}; + +class GreasePencilLayerViewItem : public DataSetViewItem { + private: + const bke::greasepencil::Layer &layer_; + int layer_index_; + + public: + GreasePencilLayerViewItem(const bke::greasepencil::Layer &layer, const int layer_index) + : layer_(layer), layer_index_(layer_index) + { + label_ = layer_.name(); + } + + std::optional get_data_id_to_activate() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::GreasePencil, layer_index_, bke::AttrDomain::Point}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_CURVE_DATA); + } +}; + +class GreasePencilLayerCurvesDomainViewItem : public DataSetViewItem { + private: + const GreasePencil &grease_pencil_; + int layer_index_; + bke::AttrDomain domain_; + + public: + GreasePencilLayerCurvesDomainViewItem(const GreasePencil &grease_pencil, + const int layer_index, + const bke::AttrDomain domain) + : grease_pencil_(grease_pencil), layer_index_(layer_index), domain_(domain) + { + label_ = curves_domain_to_label(domain); + } + + std::optional get_exact_data_id() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::GreasePencil, layer_index_, domain_}; + } + + void build_row(uiLayout &row) + { + const BIFIconID icon = curves_domain_to_icon(domain_); + uiItemL(&row, label_.c_str(), icon); + + const bke::greasepencil::Drawing *drawing = grease_pencil_.get_eval_drawing( + *grease_pencil_.layer(layer_index_)); + const int count = drawing ? drawing->strokes().attributes().domain_size(domain_) : 0; + draw_count(*this, count); + } +}; + +class PointCloudViewItem : public DataSetViewItem { + public: + PointCloudViewItem() + { + label_ = IFACE_("Point Cloud"); + } + + std::optional get_data_id_to_activate() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::PointCloud, std::nullopt, bke::AttrDomain::Point}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_POINTCLOUD_DATA); + } +}; + +class PointsViewItem : public DataSetViewItem { + private: + const PointCloud *pointcloud_; + + public: + PointsViewItem(const PointCloud *pointcloud) : pointcloud_(pointcloud) + { + label_ = IFACE_("Point"); + } + + std::optional get_exact_data_id() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::PointCloud, std::nullopt, bke::AttrDomain::Point}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_POINTCLOUD_POINT); + const int count = pointcloud_ ? pointcloud_->totpoint : 0; + draw_count(*this, count); + } +}; + +class VolumeGridsViewItem : public DataSetViewItem { + private: + const Volume *volume_; + + public: + VolumeGridsViewItem(const Volume *volume) : volume_(volume) + { + label_ = IFACE_("Volume Grids"); + } + + std::optional get_exact_data_id() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::Volume, std::nullopt, std::nullopt}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_VOLUME_DATA); + const int count = volume_ ? BKE_volume_num_grids(volume_) : 0; + draw_count(*this, count); + } +}; + +class InstancesViewItem : public DataSetViewItem { + private: + const bke::Instances *instances_; + + public: + InstancesViewItem(const bke::Instances *instances) : instances_(instances) + { + label_ = IFACE_("Instances"); + } + + std::optional get_data_id_to_activate() const override + { + return GeometryDataIdentifier{ + bke::GeometryComponent::Type::Instance, std::nullopt, bke::AttrDomain::Instance}; + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, label_.c_str(), ICON_EMPTY_AXIS); + const int count = instances_ ? instances_->instances_num() : 0; + draw_count(*this, count); + } }; class GeometryDataSetTreeView : public ui::AbstractTreeView { - bke::GeometrySet geometry_set_; + private: + bke::GeometrySet root_geometry_set_; SpaceSpreadsheet &sspreadsheet_; bScreen &screen_; - friend class GeometryDataSetTreeViewItem; + friend class DataSetViewItem; public: GeometryDataSetTreeView(bke::GeometrySet geometry_set, const bContext &C) - : geometry_set_(std::move(geometry_set)), + : root_geometry_set_(std::move(geometry_set)), sspreadsheet_(*CTX_wm_space_spreadsheet(&C)), screen_(*CTX_wm_screen(&C)) { } - void build_grease_pencil() - { - GeometryDataSetTreeViewItem &grease_pencil = this->add_tree_item( - bke::GeometryComponent::Type::GreasePencil, - IFACE_("Grease Pencil"), - ICON_OUTLINER_DATA_GREASEPENCIL); - grease_pencil.uncollapse_by_default(); - GeometryDataSetTreeViewItem &grease_pencil_layers = - grease_pencil.add_tree_item( - bke::GeometryComponent::Type::GreasePencil, - bke::AttrDomain::Layer, - IFACE_("Layer"), - ICON_OUTLINER_DATA_GP_LAYER); - - if (!geometry_set_.has_grease_pencil()) { - return; - } - - const Span layers = - geometry_set_.get_grease_pencil()->layers(); - for (const int layer_i : layers.index_range()) { - const bke::greasepencil::Layer *layer = layers[layer_i]; - GeometryDataSetTreeViewItem &curve = - grease_pencil_layers.add_tree_item( - bke::GeometryComponent::Type::GreasePencil, layer_i, layer->name(), ICON_CURVE_DATA); - curve.add_tree_item(bke::GeometryComponent::Type::GreasePencil, - layer_i, - bke::AttrDomain::Point, - IFACE_("Control Point"), - ICON_CURVE_BEZCIRCLE); - curve.add_tree_item(bke::GeometryComponent::Type::GreasePencil, - layer_i, - bke::AttrDomain::Curve, - IFACE_("Spline"), - ICON_CURVE_PATH); - } - } - - void build_instances() - { - GeometryDataSetTreeViewItem &instances_item = this->add_tree_item( - bke::GeometryComponent::Type::Instance, - bke::AttrDomain::Instance, - IFACE_("Instances"), - ICON_EMPTY_AXIS); - - if (!geometry_set_.has_instances()) { - return; - } - const bke::Instances &instances = *geometry_set_.get_instances(); - const Span references = instances.references(); - for (const int reference_i : references.index_range()) { - const bke::InstanceReference &reference = references[reference_i]; - instances_item.add_tree_item( - bke::GeometryComponent::Type::Mesh, "test", ICON_MESH_CAPSULE); - } - } - void build_tree() override { - GeometryDataSetTreeViewItem &mesh = this->add_tree_item( - bke::GeometryComponent::Type::Mesh, IFACE_("Mesh"), ICON_MESH_DATA); - mesh.uncollapse_by_default(); - mesh.add_tree_item(bke::GeometryComponent::Type::Mesh, - bke::AttrDomain::Point, - IFACE_("Vertex"), - ICON_VERTEXSEL); - mesh.add_tree_item( - bke::GeometryComponent::Type::Mesh, bke::AttrDomain::Edge, IFACE_("Edge"), ICON_EDGESEL); - mesh.add_tree_item( - bke::GeometryComponent::Type::Mesh, bke::AttrDomain::Face, IFACE_("Face"), ICON_FACESEL); - mesh.add_tree_item(bke::GeometryComponent::Type::Mesh, - bke::AttrDomain::Corner, - IFACE_("Face Corner"), - ICON_FACE_CORNER); + this->build_tree_for_geometry(root_geometry_set_, *this, true); + } - GeometryDataSetTreeViewItem &curve = this->add_tree_item( - bke::GeometryComponent::Type::Curve, IFACE_("Curve"), ICON_CURVE_DATA); - curve.uncollapse_by_default(); - curve.add_tree_item(bke::GeometryComponent::Type::Curve, - bke::AttrDomain::Point, - IFACE_("Control Point"), - ICON_CURVE_BEZCIRCLE); - curve.add_tree_item(bke::GeometryComponent::Type::Curve, - bke::AttrDomain::Curve, - IFACE_("Spline"), - ICON_CURVE_PATH); + void build_tree_for_geometry(const bke::GeometrySet &geometry, + ui::TreeViewItemContainer &parent, + const bool all_components) + { + const Mesh *mesh = geometry.get_mesh(); + if (mesh || all_components) { + this->build_tree_for_mesh(mesh, parent); + } + const Curves *curves = geometry.get_curves(); + if (curves || all_components) { + this->build_tree_for_curves(curves, parent); + } + const GreasePencil *grease_pencil = geometry.get_grease_pencil(); + if (grease_pencil || all_components) { + this->build_tree_for_grease_pencil(grease_pencil, parent); + } + const PointCloud *pointcloud = geometry.get_pointcloud(); + if (pointcloud || all_components) { + this->build_tree_for_pointcloud(pointcloud, parent); + } + const Volume *volume = geometry.get_volume(); + if (volume || all_components) { + this->build_tree_for_volume(volume, parent); + } + const bke::Instances *instances = geometry.get_instances(); + if (instances || all_components) { + this->build_tree_for_instances(instances, parent); + } + } - this->build_grease_pencil(); + void build_tree_for_mesh(const Mesh *mesh, ui::TreeViewItemContainer &parent) + { + auto &mesh_item = parent.add_tree_item(); + mesh_item.uncollapse_by_default(); + mesh_item.add_tree_item(mesh, bke::AttrDomain::Point); + mesh_item.add_tree_item(mesh, bke::AttrDomain::Edge); + mesh_item.add_tree_item(mesh, bke::AttrDomain::Face); + mesh_item.add_tree_item(mesh, bke::AttrDomain::Corner); + } - GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item( - bke::GeometryComponent::Type::PointCloud, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA); - pointcloud.uncollapse_by_default(); - pointcloud.add_tree_item(bke::GeometryComponent::Type::PointCloud, - bke::AttrDomain::Point, - IFACE_("Point"), - ICON_POINTCLOUD_POINT); + void build_tree_for_curves(const Curves *curves, ui::TreeViewItemContainer &parent) + { + auto &curves_item = parent.add_tree_item(); + curves_item.uncollapse_by_default(); + curves_item.add_tree_item(curves, bke::AttrDomain::Point); + curves_item.add_tree_item(curves, bke::AttrDomain::Curve); + } - this->add_tree_item( - bke::GeometryComponent::Type::Volume, IFACE_("Volume Grids"), ICON_VOLUME_DATA); + void build_tree_for_grease_pencil(const GreasePencil *grease_pencil, + ui::TreeViewItemContainer &parent) + { + auto &grease_pencil_item = parent.add_tree_item(); + grease_pencil_item.uncollapse_by_default(); + auto &layers_item = grease_pencil_item.add_tree_item( + grease_pencil); + if (!grease_pencil) { + return; + } + const Span layers = grease_pencil->layers(); + for (const int layer_i : layers.index_range()) { + const bke::greasepencil::Layer &layer = *layers[layer_i]; + auto &layer_item = layers_item.add_tree_item(layer, layer_i); + layer_item.add_tree_item( + *grease_pencil, layer_i, bke::AttrDomain::Point); + layer_item.add_tree_item( + *grease_pencil, layer_i, bke::AttrDomain::Curve); + } + } - this->build_instances(); + void build_tree_for_pointcloud(const PointCloud *pointcloud, ui::TreeViewItemContainer &parent) + { + auto &pointcloud_item = parent.add_tree_item(); + pointcloud_item.uncollapse_by_default(); + pointcloud_item.add_tree_item(pointcloud); + } + + void build_tree_for_volume(const Volume *volume, ui::TreeViewItemContainer &parent) + { + parent.add_tree_item(volume); + } + + void build_tree_for_instances(const bke::Instances *instances, ui::TreeViewItemContainer &parent) + { + parent.add_tree_item(instances); } }; -GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( - bke::GeometryComponent::Type component_type, StringRef label, BIFIconID icon) - : component_type_(component_type), domain_(std::nullopt), icon_(icon) -{ - label_ = label; -} -GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( - bke::GeometryComponent::Type component_type, int layer_index, StringRef label, BIFIconID icon) - : component_type_(component_type), layer_index_(layer_index), icon_(icon) -{ - label_ = label; -} -GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( - bke::GeometryComponent::Type component_type, - bke::AttrDomain domain, - StringRef label, - BIFIconID icon) - : component_type_(component_type), domain_(domain), icon_(icon) -{ - label_ = label; -} -GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( - bke::GeometryComponent::Type component_type, - int layer_index, - bke::AttrDomain domain, - StringRef label, - BIFIconID icon) - : component_type_(component_type), layer_index_(layer_index), domain_(domain), icon_(icon) -{ - label_ = label; -} - -void GeometryDataSetTreeViewItem::on_activate(bContext &C) -{ - GeometryDataSetTreeView &tree_view = this->get_tree(); - SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - tree_view.sspreadsheet_.geometry_component_type = uint8_t(component_type_); - if (domain_) { - tree_view.sspreadsheet_.attribute_domain = uint8_t(*domain_); - } - if (layer_index_) { - tree_view.sspreadsheet_.active_layer_index = *layer_index_; - } - PointerRNA ptr = RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet); - RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain")); - RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type")); -} - -void GeometryDataSetTreeViewItem::build_row(uiLayout &row) -{ - uiItemL(&row, label_.c_str(), icon_); - - if (const std::optional count = this->count()) { - /* Using the tree row button instead of a separate right aligned button gives padding - * to the right side of the number, which it didn't have with the button. */ - char element_count[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE]; - BLI_str_format_decimal_unit(element_count, *count); - UI_but_hint_drawstr_set((uiBut *)this->view_item_button(), element_count); - } -} - -std::optional GeometryDataSetTreeViewItem::should_be_active() const -{ - GeometryDataSetTreeView &tree_view = this->get_tree(); - SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - - if (component_type_ == bke::GeometryComponent::Type::Volume) { - return sspreadsheet.geometry_component_type == uint8_t(component_type_); - } - - if (!domain_) { - return false; - } - - if (!layer_index_) { - return sspreadsheet.geometry_component_type == uint8_t(component_type_) && - sspreadsheet.attribute_domain == uint8_t(*domain_); - } - - return sspreadsheet.geometry_component_type == uint8_t(component_type_) && - sspreadsheet.attribute_domain == uint8_t(*domain_) && - sspreadsheet.active_layer_index == *layer_index_; -} - -bool GeometryDataSetTreeViewItem::supports_collapsing() const -{ - return true; -} - -GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const +GeometryDataSetTreeView &DataSetViewItem::get_tree() const { return static_cast(this->get_tree_view()); } -std::optional GeometryDataSetTreeViewItem::count() const +void DataSetViewItem::get_parent_instance_ids(Vector &r_instance_ids) const +{ + UNUSED_VARS(r_instance_ids); +} + +void DataSetViewItem::on_activate(bContext &C) +{ + const std::optional data_to_activate = this->get_data_id_to_activate(); + if (!data_to_activate) { + return; + } + + Vector instance_ids; + this->get_parent_instance_ids(instance_ids); + + bScreen &screen = *CTX_wm_screen(&C); + SpaceSpreadsheet &sspreadsheet = *CTX_wm_space_spreadsheet(&C); + + MEM_SAFE_FREE(sspreadsheet.instance_ids); + sspreadsheet.instance_ids = MEM_cnew_array(instance_ids.size(), __func__); + sspreadsheet.instance_ids_num = instance_ids.size(); + initialized_copy_n(instance_ids.data(), instance_ids.size(), sspreadsheet.instance_ids); + + sspreadsheet.geometry_component_type = uint8_t(data_to_activate->component_type); + if (data_to_activate->domain) { + sspreadsheet.attribute_domain = uint8_t(*data_to_activate->domain); + } + if (data_to_activate->layer_index) { + sspreadsheet.active_layer_index = *data_to_activate->layer_index; + } + PointerRNA ptr = RNA_pointer_create(&screen.id, &RNA_SpaceSpreadsheet, &sspreadsheet); + /* These updates also make sure that the attribute domain is set properly based on the + * component type. */ + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain")); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type")); +} + +std::optional DataSetViewItem::should_be_active() const { GeometryDataSetTreeView &tree_view = this->get_tree(); - bke::GeometrySet &geometry = tree_view.geometry_set_; + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - /* Special case for volumes since there is no grid domain. */ - if (component_type_ == bke::GeometryComponent::Type::Volume) { - if (const Volume *volume = geometry.get_volume()) { - return BKE_volume_num_grids(volume); - } - return 0; + const std::optional data_id = this->get_exact_data_id(); + if (!data_id) { + return false; } - - if (!domain_) { - return std::nullopt; + if (bke::GeometryComponent::Type(sspreadsheet.geometry_component_type) != + data_id->component_type) + { + return false; } - - if (component_type_ == bke::GeometryComponent::Type::GreasePencil && layer_index_) { - const GreasePencil *grease_pencil = geometry.get_grease_pencil(); - if (const bke::greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing( - *grease_pencil->layer(*layer_index_))) - { - return drawing->strokes().attributes().domain_size(*domain_); + if (data_id->domain) { + if (bke::AttrDomain(sspreadsheet.attribute_domain) != data_id->domain) { + return false; } } - - if (const bke::GeometryComponent *component = geometry.get_component(component_type_)) { - return component->attribute_domain_size(*domain_); + if (data_id->layer_index) { + if (sspreadsheet.active_layer_index != *data_id->layer_index) { + return false; + } } - - return 0; + Vector instance_ids; + this->get_parent_instance_ids(instance_ids); + if (sspreadsheet.instance_ids_num != instance_ids.size()) { + return false; + } + for (const int i : instance_ids.index_range()) { + const SpreadsheetInstanceID &a = sspreadsheet.instance_ids[i]; + const SpreadsheetInstanceID &b = instance_ids[i]; + if (a.reference_index != b.reference_index) { + return false; + } + } + return true; } void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel) -- 2.30.2 From 812f3c92bff3ee84cd75eaf840263874f892cf3e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 18:17:19 +0200 Subject: [PATCH 03/17] show nested instances --- source/blender/blenkernel/BKE_instances.hh | 2 + source/blender/blenkernel/intern/instances.cc | 20 ++++++ .../blender/editors/include/UI_tree_view.hh | 1 + .../editors/interface/views/tree_view.cc | 7 ++ .../spreadsheet_data_source_geometry.cc | 21 ++++++ .../spreadsheet_data_source_geometry.hh | 3 + .../spreadsheet_dataset_draw.cc | 64 ++++++++++++++++- .../space_spreadsheet/spreadsheet_layout.cc | 71 +++++-------------- .../space_spreadsheet/spreadsheet_layout.hh | 2 + 9 files changed, 135 insertions(+), 56 deletions(-) diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh index 82eb4e6c5d1..826f1bfb883 100644 --- a/source/blender/blenkernel/BKE_instances.hh +++ b/source/blender/blenkernel/BKE_instances.hh @@ -86,6 +86,8 @@ class InstanceReference { GeometrySet &geometry_set(); const GeometrySet &geometry_set() const; + std::string name() const; + bool owns_direct_data() const; void ensure_owns_direct_data(); diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc index 6319bd74092..645f55b5570 100644 --- a/source/blender/blenkernel/intern/instances.cc +++ b/source/blender/blenkernel/intern/instances.cc @@ -6,10 +6,15 @@ #include "BLI_rand.hh" #include "BLI_task.hh" +#include "DNA_collection_types.h" +#include "DNA_object_types.h" + #include "BKE_customdata.hh" #include "BKE_geometry_set.hh" #include "BKE_instances.hh" +#include "BLT_translation.hh" + namespace blender::bke { InstanceReference::InstanceReference(GeometrySet geometry_set) @@ -35,6 +40,21 @@ bool InstanceReference::owns_direct_data() const return geometry_set_->owns_direct_data(); } +std::string InstanceReference::name() const +{ + switch (type_) { + case Type::Object: + return this->object().id.name + 2; + case Type::Collection: + return this->collection().id.name + 2; + case Type::GeometrySet: + return IFACE_("Geometry"); + case Type::None: + break; + } + return ""; +} + bool operator==(const InstanceReference &a, const InstanceReference &b) { if (a.geometry_set_ && b.geometry_set_) { diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index c94b3b13652..7b699ffba10 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -93,6 +93,7 @@ class TreeViewItemContainer { protected: void foreach_item_recursive(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const; + void foreach_parent(ItemIterFn iter_fn) const; }; ENUM_OPERATORS(TreeViewItemContainer::IterOptions, diff --git a/source/blender/editors/interface/views/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc index 597fca3c793..9b6a7be3163 100644 --- a/source/blender/editors/interface/views/tree_view.cc +++ b/source/blender/editors/interface/views/tree_view.cc @@ -83,6 +83,13 @@ void TreeViewItemContainer::foreach_item_recursive(ItemIterFn iter_fn, IterOptio } } +void TreeViewItemContainer::foreach_parent(ItemIterFn iter_fn) const +{ + for (ui::AbstractTreeViewItem *item = parent_; item; item = item->parent_) { + iter_fn(*item); + } +} + /* ---------------------------------------------------------------------- */ /* Implementation for the base class virtual function. More specialized iterators below. */ 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 cb47f3c888b..8faeba86022 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -42,6 +42,8 @@ #include "RNA_access.hh" #include "RNA_enum_types.hh" +#include "UI_resources.hh" + #include "bmesh.hh" #include "spreadsheet_data_source_geometry.hh" @@ -545,6 +547,25 @@ int VolumeDataSource::tot_rows() const return BKE_volume_num_grids(volume); } +int get_instance_reference_icon(const bke::InstanceReference &reference) +{ + switch (reference.type()) { + case bke::InstanceReference::Type::Object: { + return ICON_OBJECT_DATA; + } + case bke::InstanceReference::Type::Collection: { + return ICON_OUTLINER_COLLECTION; + } + case bke::InstanceReference::Type::GeometrySet: { + return ICON_EMPTY_AXIS; + } + case bke::InstanceReference::Type::None: { + break; + } + } + return ICON_NONE; +} + bke::GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, Object *object_eval) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 592c1e6958e..0fa25b7d360 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -9,6 +9,7 @@ #include "BLI_resource_scope.hh" #include "BKE_geometry_set.hh" +#include "BKE_instances.hh" #include "spreadsheet_data_source.hh" @@ -109,6 +110,8 @@ class VolumeDataSource : public DataSource { int tot_rows() const override; }; +int get_instance_reference_icon(const bke::InstanceReference &reference); + std::unique_ptr data_source_from_geometry(const bContext *C, Object *object_eval); } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index da0ef15f3a7..8d990475f72 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -12,6 +12,7 @@ #include "BKE_context.hh" #include "BKE_curves.hh" +#include "BKE_geometry_set_instances.hh" #include "BKE_grease_pencil.hh" #include "BKE_instances.hh" #include "BKE_volume.hh" @@ -26,6 +27,7 @@ #include "BLT_translation.hh" +#include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_dataset_draw.hh" #include "spreadsheet_intern.hh" @@ -411,6 +413,30 @@ class InstancesViewItem : public DataSetViewItem { } }; +class InstanceReferenceViewItem : public DataSetViewItem { + private: + const bke::InstanceReference &reference_; + int reference_index_; + + public: + InstanceReferenceViewItem(const bke::Instances &instances, const int reference_index) + : reference_(instances.references()[reference_index]), reference_index_(reference_index) + { + label_ = std::to_string(reference_index); + } + + void build_row(uiLayout &row) override + { + const int icon = get_instance_reference_icon(reference_); + uiItemL(&row, reference_.name().c_str(), icon); + } + + int reference_index() const + { + return reference_index_; + } +}; + class GeometryDataSetTreeView : public ui::AbstractTreeView { private: bke::GeometrySet root_geometry_set_; @@ -515,7 +541,36 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView { void build_tree_for_instances(const bke::Instances *instances, ui::TreeViewItemContainer &parent) { - parent.add_tree_item(instances); + auto &instances_view = parent.add_tree_item(instances); + if (!instances) { + return; + } + const Span references = instances->references(); + for (const int reference_i : references.index_range()) { + auto &reference_item = instances_view.add_tree_item(*instances, + reference_i); + const bke::InstanceReference &reference = references[reference_i]; + switch (reference.type()) { + case bke::InstanceReference::Type::Object: { + const Object &object = reference.object(); + const bke::GeometrySet geometry_set = bke::object_get_evaluated_geometry_set(object); + this->build_tree_for_geometry(geometry_set, reference_item, false); + break; + } + case bke::InstanceReference::Type::Collection: { + /* TODO */ + break; + } + case bke::InstanceReference::Type::GeometrySet: { + const bke::GeometrySet &geometry_set = reference.geometry_set(); + this->build_tree_for_geometry(geometry_set, reference_item, false); + break; + } + case bke::InstanceReference::Type::None: { + break; + } + } + } } }; @@ -526,7 +581,12 @@ GeometryDataSetTreeView &DataSetViewItem::get_tree() const void DataSetViewItem::get_parent_instance_ids(Vector &r_instance_ids) const { - UNUSED_VARS(r_instance_ids); + this->foreach_parent([&](const ui::AbstractTreeViewItem &item) { + if (auto *reference_item = dynamic_cast(&item)) { + r_instance_ids.append({reference_item->reference_index()}); + } + }); + std::reverse(r_instance_ids.begin(), r_instance_ids.end()); } void DataSetViewItem::on_activate(bContext &C) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 08abb6b96be..f876f0e7458 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -15,6 +15,7 @@ #include "BKE_instances.hh" #include "spreadsheet_column_values.hh" +#include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_layout.hh" #include "DNA_collection_types.h" @@ -203,60 +204,22 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { } else if (data.type().is()) { const bke::InstanceReference value = data.get(real_index); - switch (value.type()) { - case bke::InstanceReference::Type::Object: { - const Object &object = value.object(); - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_OBJECT_DATA, - object.id.name + 2, - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - nullptr); - break; - } - case bke::InstanceReference::Type::Collection: { - Collection &collection = value.collection(); - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_OUTLINER_COLLECTION, - collection.id.name + 2, - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - nullptr); - break; - } - case bke::InstanceReference::Type::GeometrySet: { - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_MESH_DATA, - "Geometry", - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - nullptr); - break; - } - case bke::InstanceReference::Type::None: { - break; - } + const std::string name = value.name(); + const int icon = get_instance_reference_icon(value); + if (!name.empty()) { + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + icon, + name.c_str(), + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + nullptr); } } else if (data.type().is()) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh index 4b08e124dd0..757067eb34d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh @@ -9,6 +9,8 @@ #include "spreadsheet_column_values.hh" #include "spreadsheet_draw.hh" +#include "BKE_instances.hh" + namespace blender::ed::spreadsheet { /* Layout information for a single column. */ -- 2.30.2 From b6e5e76108dc3548fb73548c782ed7264fb2876b Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 18:37:33 +0200 Subject: [PATCH 04/17] show data for instanced geometry --- .../spreadsheet_data_source_geometry.cc | 44 ++++++++++++++++++- .../spreadsheet_data_source_geometry.hh | 1 + 2 files changed, 44 insertions(+), 1 deletion(-) 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 8faeba86022..992282774b4 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -12,6 +12,7 @@ #include "BKE_editmesh.hh" #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" +#include "BKE_geometry_set_instances.hh" #include "BKE_global.hh" #include "BKE_grease_pencil.hh" #include "BKE_instances.hh" @@ -629,13 +630,54 @@ bke::GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *ss return geometry_set; } +static bke::GeometrySet get_geometry_set_for_instance_ids( + const bke::GeometrySet &root_geometry, const Span instance_ids) +{ + bke::GeometrySet geometry = root_geometry; + for (const SpreadsheetInstanceID &instance_id : instance_ids) { + const bke::Instances *instances = geometry.get_instances(); + if (!instances) { + return {}; + } + const Span references = instances->references(); + if (instance_id.reference_index < 0 || instance_id.reference_index >= references.size()) { + return {}; + } + const bke::InstanceReference &reference = references[instance_id.reference_index]; + switch (reference.type()) { + case bke::InstanceReference::Type::GeometrySet: { + geometry = reference.geometry_set(); + break; + } + case bke::InstanceReference::Type::Object: { + const Object &object = reference.object(); + geometry = bke::object_get_evaluated_geometry_set(object); + break; + } + case bke::InstanceReference::Type::Collection: { + /* TODO. */ + return {}; + } + case bke::InstanceReference::Type::None: { + return {}; + } + } + } + return geometry; +} + std::unique_ptr data_source_from_geometry(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); + + const bke::GeometrySet root_geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, + object_eval); + const bke::GeometrySet geometry_set = get_geometry_set_for_instance_ids( + root_geometry_set, Span{sspreadsheet->instance_ids, sspreadsheet->instance_ids_num}); + const bke::AttrDomain domain = (bke::AttrDomain)sspreadsheet->attribute_domain; const auto component_type = bke::GeometryComponent::Type(sspreadsheet->geometry_component_type); const int active_layer_index = sspreadsheet->active_layer_index; - bke::GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); if (!geometry_set.has(component_type)) { return {}; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 0fa25b7d360..bca3b1efe96 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -40,6 +40,7 @@ class ExtraColumns { class GeometryDataSource : public DataSource { private: + /* TODO: Rethink handling of object_eval_. */ Object *object_eval_; const bke::GeometrySet geometry_set_; const bke::GeometryComponent *component_; -- 2.30.2 From cadc221304ad1724a9c784988dda0fbe3dd7029d Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 18:42:03 +0200 Subject: [PATCH 05/17] fix --- .../editors/space_spreadsheet/spreadsheet_dataset_draw.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 8d990475f72..6d7066aa075 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -399,7 +399,7 @@ class InstancesViewItem : public DataSetViewItem { label_ = IFACE_("Instances"); } - std::optional get_data_id_to_activate() const override + std::optional get_exact_data_id() const override { return GeometryDataIdentifier{ bke::GeometryComponent::Type::Instance, std::nullopt, bke::AttrDomain::Instance}; -- 2.30.2 From 54988e895d18d281794a4708e9bb7c9cc4f4adb1 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 19:45:16 +0200 Subject: [PATCH 06/17] improve handling of collections --- source/blender/blenkernel/BKE_instances.hh | 8 ++ source/blender/blenkernel/intern/instances.cc | 48 +++++++++ source/blender/editors/include/ED_outliner.hh | 3 + .../editors/space_outliner/outliner_draw.cc | 5 + .../spreadsheet_data_source_geometry.cc | 21 +--- .../spreadsheet_dataset_draw.cc | 100 ++++++++++++++---- .../geometry/intern/realize_instances.cc | 55 ++-------- 7 files changed, 154 insertions(+), 86 deletions(-) diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh index 826f1bfb883..edbfece0627 100644 --- a/source/blender/blenkernel/BKE_instances.hh +++ b/source/blender/blenkernel/BKE_instances.hh @@ -86,6 +86,14 @@ class InstanceReference { GeometrySet &geometry_set(); const GeometrySet &geometry_set() const; + /** + * Converts the instance reference to a geometry set, even if it was an object or collection + * before. + * + * \note Uses out-parameter to be able to use #GeometrySet forward declaration. + */ + void to_geometry_set(GeometrySet &r_geometry_set) const; + std::string name() const; bool owns_direct_data() const; diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc index 645f55b5570..e64f829f268 100644 --- a/source/blender/blenkernel/intern/instances.cc +++ b/source/blender/blenkernel/intern/instances.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "BLI_array_utils.hh" +#include "BLI_listbase.h" #include "BLI_rand.hh" #include "BLI_task.hh" @@ -11,6 +12,7 @@ #include "BKE_customdata.hh" #include "BKE_geometry_set.hh" +#include "BKE_geometry_set_instances.hh" #include "BKE_instances.hh" #include "BLT_translation.hh" @@ -40,6 +42,52 @@ bool InstanceReference::owns_direct_data() const return geometry_set_->owns_direct_data(); } +static void convert_collection_to_instances(const Collection &collection, + bke::Instances &instances) +{ + LISTBASE_FOREACH (CollectionChild *, collection_child, &collection.children) { + float4x4 transform = float4x4::identity(); + transform.location() += float3(collection_child->collection->instance_offset); + transform.location() -= float3(collection.instance_offset); + const int handle = instances.add_reference(*collection_child->collection); + instances.add_instance(handle, transform); + } + + LISTBASE_FOREACH (CollectionObject *, collection_object, &collection.gobject) { + float4x4 transform = float4x4::identity(); + transform.location() -= float3(collection.instance_offset); + transform *= (collection_object->ob)->object_to_world(); + const int handle = instances.add_reference(*collection_object->ob); + instances.add_instance(handle, transform); + } +} + +void InstanceReference::to_geometry_set(GeometrySet &r_geometry_set) const +{ + r_geometry_set.clear(); + switch (type_) { + case Type::Object: { + const Object &object = this->object(); + r_geometry_set = bke::object_get_evaluated_geometry_set(object); + break; + } + case Type::Collection: { + const Collection &collection = this->collection(); + std::unique_ptr instances_ptr = std::make_unique(); + convert_collection_to_instances(collection, *instances_ptr); + r_geometry_set.replace_instances(instances_ptr.release()); + break; + } + case Type::GeometrySet: { + r_geometry_set = this->geometry_set(); + break; + } + case Type::None: { + break; + } + } +} + std::string InstanceReference::name() const { switch (type_) { diff --git a/source/blender/editors/include/ED_outliner.hh b/source/blender/editors/include/ED_outliner.hh index 49b6c6fff19..b2aee00f556 100644 --- a/source/blender/editors/include/ED_outliner.hh +++ b/source/blender/editors/include/ED_outliner.hh @@ -12,6 +12,7 @@ struct Base; struct ListBase; struct SpaceOutliner; struct bContext; +struct ID; bool ED_outliner_collections_editor_poll(bContext *C); @@ -47,3 +48,5 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_out * Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw. */ void ED_outliner_select_sync_flag_outliners(const bContext *C); + +int ED_outliner_icon_from_id(const ID &id); diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index f163d50f4c5..d8207aa2177 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -4130,3 +4130,8 @@ void draw_outliner(const bContext *C) /** \} */ } // namespace blender::ed::outliner + +int ED_outliner_icon_from_id(const ID &id) +{ + return blender::ed::outliner::tree_element_get_icon_from_id(&id); +} 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 992282774b4..f687d31bbde 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -644,24 +644,9 @@ static bke::GeometrySet get_geometry_set_for_instance_ids( return {}; } const bke::InstanceReference &reference = references[instance_id.reference_index]; - switch (reference.type()) { - case bke::InstanceReference::Type::GeometrySet: { - geometry = reference.geometry_set(); - break; - } - case bke::InstanceReference::Type::Object: { - const Object &object = reference.object(); - geometry = bke::object_get_evaluated_geometry_set(object); - break; - } - case bke::InstanceReference::Type::Collection: { - /* TODO. */ - return {}; - } - case bke::InstanceReference::Type::None: { - return {}; - } - } + bke::GeometrySet reference_geometry; + reference.to_geometry_set(reference_geometry); + geometry = reference_geometry; } return geometry; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 6d7066aa075..0d46ce76540 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -4,6 +4,7 @@ #include "BLI_string.h" +#include "DNA_collection_types.h" #include "DNA_curves_types.h" #include "DNA_mesh_types.h" #include "DNA_pointcloud_types.h" @@ -27,6 +28,8 @@ #include "BLT_translation.hh" +#include "ED_outliner.hh" + #include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_dataset_draw.hh" #include "spreadsheet_intern.hh" @@ -437,6 +440,53 @@ class InstanceReferenceViewItem : public DataSetViewItem { } }; +class CollectionChildViewItem : public DataSetViewItem { + private: + const CollectionChild *collection_child_; + int child_index_; + + public: + CollectionChildViewItem(const CollectionChild &collection_child, const int child_index) + : collection_child_(&collection_child), child_index_(child_index) + { + label_ = std::to_string(child_index); + } + + void build_row(uiLayout &row) override + { + uiItemL(&row, collection_child_->collection->id.name + 2, ICON_OUTLINER_COLLECTION); + } + + int child_index() const + { + return child_index_; + } +}; + +class CollectionObjectViewItem : public DataSetViewItem { + private: + const CollectionObject *collection_object_; + int child_index_; + + public: + CollectionObjectViewItem(const CollectionObject &collection_object, const int child_index) + : collection_object_(&collection_object), child_index_(child_index) + { + label_ = std::to_string(child_index); + } + + void build_row(uiLayout &row) override + { + const int icon = ED_outliner_icon_from_id(collection_object_->ob->id); + uiItemL(&row, collection_object_->ob->id.name + 2, icon); + } + + int child_index() const + { + return child_index_; + } +}; + class GeometryDataSetTreeView : public ui::AbstractTreeView { private: bke::GeometrySet root_geometry_set_; @@ -550,26 +600,31 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView { auto &reference_item = instances_view.add_tree_item(*instances, reference_i); const bke::InstanceReference &reference = references[reference_i]; - switch (reference.type()) { - case bke::InstanceReference::Type::Object: { - const Object &object = reference.object(); - const bke::GeometrySet geometry_set = bke::object_get_evaluated_geometry_set(object); - this->build_tree_for_geometry(geometry_set, reference_item, false); - break; - } - case bke::InstanceReference::Type::Collection: { - /* TODO */ - break; - } - case bke::InstanceReference::Type::GeometrySet: { - const bke::GeometrySet &geometry_set = reference.geometry_set(); - this->build_tree_for_geometry(geometry_set, reference_item, false); - break; - } - case bke::InstanceReference::Type::None: { - break; - } + if (reference.type() == bke::InstanceReference::Type::Collection) { + this->build_tree_for_collection(reference.collection(), reference_item); } + else { + bke::GeometrySet reference_geometry; + reference.to_geometry_set(reference_geometry); + this->build_tree_for_geometry(reference_geometry, reference_item, false); + } + } + } + + void build_tree_for_collection(const Collection &collection, ui::TreeViewItemContainer &parent) + { + int child_index = 0; + LISTBASE_FOREACH (CollectionChild *, collection_child, &collection.children) { + auto &collection_child_item = parent.add_tree_item( + *collection_child, child_index++); + this->build_tree_for_collection(*collection_child->collection, collection_child_item); + } + LISTBASE_FOREACH (CollectionObject *, collection_object, &collection.gobject) { + auto &collection_object_item = parent.add_tree_item( + *collection_object, child_index++); + const bke::GeometrySet geometry = bke::object_get_evaluated_geometry_set( + *collection_object->ob); + this->build_tree_for_geometry(geometry, collection_object_item, false); } } }; @@ -585,6 +640,13 @@ void DataSetViewItem::get_parent_instance_ids(Vector &r_i if (auto *reference_item = dynamic_cast(&item)) { r_instance_ids.append({reference_item->reference_index()}); } + else if (auto *collection_object_item = dynamic_cast(&item)) + { + r_instance_ids.append({collection_object_item->child_index()}); + } + else if (auto *collection_child_item = dynamic_cast(&item)) { + r_instance_ids.append({collection_child_item->child_index()}); + } }); std::reverse(r_instance_ids.begin(), r_instance_ids.end()); } diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 4bc8b9e1a63..c666dff52f3 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -320,25 +320,6 @@ static int64_t get_final_points_num(const GatherTasks &tasks) return points_num; } -static void realize_collections(Collection &collection, bke::Instances &instances) -{ - LISTBASE_FOREACH (CollectionChild *, collection_child, &collection.children) { - float4x4 transform = float4x4::identity(); - transform.location() += float3(collection_child->collection->instance_offset); - transform.location() -= float3(collection.instance_offset); - const int handle = instances.add_reference(*collection_child->collection); - instances.add_instance(handle, transform); - } - - LISTBASE_FOREACH (CollectionObject *, collection_object, &collection.gobject) { - float4x4 transform = float4x4::identity(); - transform.location() -= float3(collection.instance_offset); - transform *= (collection_object->ob)->object_to_world(); - const int handle = instances.add_reference(*collection_object->ob); - instances.add_instance(handle, transform); - } -} - static void copy_transformed_positions(const Span src, const float4x4 &transform, MutableSpan dst) @@ -500,33 +481,6 @@ static Vector> prepare_attribute_fallbacks( return attributes_to_override; } -static bke::GeometrySet geometry_set_from_reference(const InstanceReference &reference) -{ - switch (reference.type()) { - case InstanceReference::Type::Object: { - const Object &object = reference.object(); - const bke::GeometrySet geometry_set = bke::object_get_evaluated_geometry_set(object); - return geometry_set; - } - case InstanceReference::Type::Collection: { - std::unique_ptr instances_ptr = std::make_unique(); - realize_collections(reference.collection(), *instances_ptr); - bke::GeometrySet geometry_set; - geometry_set.replace_instances(instances_ptr.release()); - return geometry_set; - } - case InstanceReference::Type::GeometrySet: { - const bke::GeometrySet geometry_set = reference.geometry_set(); - return geometry_set; - } - case InstanceReference::Type::None: { - /* Return an empty GeometrySet for None type. */ - return {}; - } - } - return {}; -} - /** * Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation * that is applied to every instance. @@ -538,7 +492,8 @@ static void foreach_geometry_in_reference( FunctionRef fn) { - bke::GeometrySet geometry_set = geometry_set_from_reference(reference); + bke::GeometrySet geometry_set; + reference.to_geometry_set(geometry_set); fn(geometry_set, base_transform, id); } @@ -770,8 +725,10 @@ static bool attribute_foreach(const bke::GeometrySet &geometry_set, IndexMask(IndexRange(instances.instances_num())); indices.foreach_index([&](const int i) { const int child_depth_target = (0 == current_depth) ? instance_depth[i] : depth_target; - bke::GeometrySet instance_geometry_set = geometry_set_from_reference( - instances.references()[instances.reference_handles()[i]]); + const bke::InstanceReference &reference = + instances.references()[instances.reference_handles()[i]]; + bke::GeometrySet instance_geometry_set; + reference.to_geometry_set(instance_geometry_set); /* Process child instances with a recursive call. */ if (current_depth != child_depth_target) { child_has_component = child_has_component | attribute_foreach(instance_geometry_set, -- 2.30.2 From 914159b6706d1408e43b044e437f5969f1b501bd Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 19:49:47 +0200 Subject: [PATCH 07/17] improve object instance --- .../space_spreadsheet/spreadsheet_data_source_geometry.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 f687d31bbde..2377957a1be 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -33,6 +33,7 @@ #include "DEG_depsgraph_query.hh" #include "ED_curves.hh" +#include "ED_outliner.hh" #include "ED_spreadsheet.hh" #include "NOD_geometry_nodes_lazy_function.hh" @@ -552,7 +553,8 @@ int get_instance_reference_icon(const bke::InstanceReference &reference) { switch (reference.type()) { case bke::InstanceReference::Type::Object: { - return ICON_OBJECT_DATA; + const Object &object = reference.object(); + return ED_outliner_icon_from_id(object.id); } case bke::InstanceReference::Type::Collection: { return ICON_OUTLINER_COLLECTION; -- 2.30.2 From f6f9e6a980b610cccdca85f1d1ef8d920c40c411 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 20:03:04 +0200 Subject: [PATCH 08/17] cleanup activating child element --- .../spreadsheet_dataset_draw.cc | 85 +++++++++---------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 0d46ce76540..dcf33a07efb 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -114,7 +114,7 @@ static BIFIconID curves_domain_to_icon(const bke::AttrDomain domain) } class DataSetViewItem : public ui::AbstractTreeViewItem { - private: + public: GeometryDataSetTreeView &get_tree() const; void get_parent_instance_ids(Vector &r_instance_ids) const; @@ -128,9 +128,22 @@ class DataSetViewItem : public ui::AbstractTreeViewItem { return std::nullopt; } - virtual std::optional get_data_id_to_activate() const + std::optional get_data_id_to_activate() const { - return this->get_exact_data_id(); + if (std::optional data_id = this->get_exact_data_id()) { + return data_id; + } + /* Try to find the next data item that can be activated. */ + std::optional data_id; + this->foreach_item_recursive([&](const ui::AbstractTreeViewItem &item) { + if (data_id) { + return; + } + if (auto *data_set_view_item = dynamic_cast(&item)) { + data_id = data_set_view_item->get_exact_data_id(); + } + }); + return data_id; } }; @@ -141,12 +154,6 @@ class MeshViewItem : public DataSetViewItem { label_ = IFACE_("Mesh"); } - std::optional get_data_id_to_activate() const override - { - return GeometryDataIdentifier{ - bke::GeometryComponent::Type::Mesh, std::nullopt, bke::AttrDomain::Point}; - } - void build_row(uiLayout &row) override { uiItemL(&row, label_.c_str(), ICON_MESH_DATA); @@ -186,12 +193,6 @@ class CurvesViewItem : public DataSetViewItem { label_ = IFACE_("Curve"); } - std::optional get_data_id_to_activate() const override - { - return GeometryDataIdentifier{ - bke::GeometryComponent::Type::Curve, std::nullopt, bke::AttrDomain::Point}; - } - void build_row(uiLayout &row) override { uiItemL(&row, label_.c_str(), ICON_CURVE_DATA); @@ -232,12 +233,6 @@ class GreasePencilViewItem : public DataSetViewItem { label_ = IFACE_("Grease Pencil"); } - std::optional get_data_id_to_activate() const override - { - return GeometryDataIdentifier{ - bke::GeometryComponent::Type::GreasePencil, std::nullopt, bke::AttrDomain::Layer}; - } - void build_row(uiLayout &row) override { uiItemL(&row, label_.c_str(), ICON_OUTLINER_DATA_GREASEPENCIL); @@ -280,12 +275,6 @@ class GreasePencilLayerViewItem : public DataSetViewItem { label_ = layer_.name(); } - std::optional get_data_id_to_activate() const override - { - return GeometryDataIdentifier{ - bke::GeometryComponent::Type::GreasePencil, layer_index_, bke::AttrDomain::Point}; - } - void build_row(uiLayout &row) override { uiItemL(&row, label_.c_str(), ICON_CURVE_DATA); @@ -332,12 +321,6 @@ class PointCloudViewItem : public DataSetViewItem { label_ = IFACE_("Point Cloud"); } - std::optional get_data_id_to_activate() const override - { - return GeometryDataIdentifier{ - bke::GeometryComponent::Type::PointCloud, std::nullopt, bke::AttrDomain::Point}; - } - void build_row(uiLayout &row) override { uiItemL(&row, label_.c_str(), ICON_POINTCLOUD_DATA); @@ -653,13 +636,29 @@ void DataSetViewItem::get_parent_instance_ids(Vector &r_i void DataSetViewItem::on_activate(bContext &C) { - const std::optional data_to_activate = this->get_data_id_to_activate(); - if (!data_to_activate) { - return; + Vector instance_ids; + std::optional data_id = this->get_exact_data_id(); + if (data_id) { + this->get_parent_instance_ids(instance_ids); + } + else { + /* Try to find the next data item that can be activated. */ + this->foreach_item_recursive([&](const ui::AbstractTreeViewItem &item) { + if (data_id) { + return; + } + if (auto *data_set_view_item = dynamic_cast(&item)) { + data_id = data_set_view_item->get_exact_data_id(); + if (data_id) { + data_set_view_item->get_parent_instance_ids(instance_ids); + } + } + }); } - Vector instance_ids; - this->get_parent_instance_ids(instance_ids); + if (!data_id) { + return; + } bScreen &screen = *CTX_wm_screen(&C); SpaceSpreadsheet &sspreadsheet = *CTX_wm_space_spreadsheet(&C); @@ -669,12 +668,12 @@ void DataSetViewItem::on_activate(bContext &C) sspreadsheet.instance_ids_num = instance_ids.size(); initialized_copy_n(instance_ids.data(), instance_ids.size(), sspreadsheet.instance_ids); - sspreadsheet.geometry_component_type = uint8_t(data_to_activate->component_type); - if (data_to_activate->domain) { - sspreadsheet.attribute_domain = uint8_t(*data_to_activate->domain); + sspreadsheet.geometry_component_type = uint8_t(data_id->component_type); + if (data_id->domain) { + sspreadsheet.attribute_domain = uint8_t(*data_id->domain); } - if (data_to_activate->layer_index) { - sspreadsheet.active_layer_index = *data_to_activate->layer_index; + if (data_id->layer_index) { + sspreadsheet.active_layer_index = *data_id->layer_index; } PointerRNA ptr = RNA_pointer_create(&screen.id, &RNA_SpaceSpreadsheet, &sspreadsheet); /* These updates also make sure that the attribute domain is set properly based on the -- 2.30.2 From 05775c748d055fc999b38d8a3293b9013e18fe8a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 4 Jul 2024 20:18:20 +0200 Subject: [PATCH 09/17] cleanup --- .../spreadsheet_dataset_draw.cc | 41 ++++++------------- .../space_spreadsheet/spreadsheet_layout.hh | 2 - source/blender/makesdna/DNA_space_types.h | 4 ++ 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index dcf33a07efb..a8f1300e7de 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -123,28 +123,11 @@ class DataSetViewItem : public ui::AbstractTreeViewItem { std::optional should_be_active() const override; - virtual std::optional get_exact_data_id() const + /** Get information about which part of a geometry this item corresponds to. */ + virtual std::optional get_geometry_data_id() const { return std::nullopt; } - - std::optional get_data_id_to_activate() const - { - if (std::optional data_id = this->get_exact_data_id()) { - return data_id; - } - /* Try to find the next data item that can be activated. */ - std::optional data_id; - this->foreach_item_recursive([&](const ui::AbstractTreeViewItem &item) { - if (data_id) { - return; - } - if (auto *data_set_view_item = dynamic_cast(&item)) { - data_id = data_set_view_item->get_exact_data_id(); - } - }); - return data_id; - } }; class MeshViewItem : public DataSetViewItem { @@ -171,7 +154,7 @@ class MeshDomainViewItem : public DataSetViewItem { label_ = mesh_domain_to_label(domain); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{bke::GeometryComponent::Type::Mesh, std::nullopt, domain_}; } @@ -211,7 +194,7 @@ class CurvesDomainViewItem : public DataSetViewItem { label_ = curves_domain_to_label(domain); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{bke::GeometryComponent::Type::Curve, std::nullopt, domain_}; } @@ -249,7 +232,7 @@ class GreasePencilLayersViewItem : public DataSetViewItem { label_ = IFACE_("Layer"); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{ bke::GeometryComponent::Type::GreasePencil, std::nullopt, bke::AttrDomain::Layer}; @@ -296,7 +279,7 @@ class GreasePencilLayerCurvesDomainViewItem : public DataSetViewItem { label_ = curves_domain_to_label(domain); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{ bke::GeometryComponent::Type::GreasePencil, layer_index_, domain_}; @@ -337,7 +320,7 @@ class PointsViewItem : public DataSetViewItem { label_ = IFACE_("Point"); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{ bke::GeometryComponent::Type::PointCloud, std::nullopt, bke::AttrDomain::Point}; @@ -361,7 +344,7 @@ class VolumeGridsViewItem : public DataSetViewItem { label_ = IFACE_("Volume Grids"); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{ bke::GeometryComponent::Type::Volume, std::nullopt, std::nullopt}; @@ -385,7 +368,7 @@ class InstancesViewItem : public DataSetViewItem { label_ = IFACE_("Instances"); } - std::optional get_exact_data_id() const override + std::optional get_geometry_data_id() const override { return GeometryDataIdentifier{ bke::GeometryComponent::Type::Instance, std::nullopt, bke::AttrDomain::Instance}; @@ -637,7 +620,7 @@ void DataSetViewItem::get_parent_instance_ids(Vector &r_i void DataSetViewItem::on_activate(bContext &C) { Vector instance_ids; - std::optional data_id = this->get_exact_data_id(); + std::optional data_id = this->get_geometry_data_id(); if (data_id) { this->get_parent_instance_ids(instance_ids); } @@ -648,7 +631,7 @@ void DataSetViewItem::on_activate(bContext &C) return; } if (auto *data_set_view_item = dynamic_cast(&item)) { - data_id = data_set_view_item->get_exact_data_id(); + data_id = data_set_view_item->get_geometry_data_id(); if (data_id) { data_set_view_item->get_parent_instance_ids(instance_ids); } @@ -687,7 +670,7 @@ std::optional DataSetViewItem::should_be_active() const GeometryDataSetTreeView &tree_view = this->get_tree(); SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - const std::optional data_id = this->get_exact_data_id(); + const std::optional data_id = this->get_geometry_data_id(); if (!data_id) { return false; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh index 757067eb34d..4b08e124dd0 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh @@ -9,8 +9,6 @@ #include "spreadsheet_column_values.hh" #include "spreadsheet_draw.hh" -#include "BKE_instances.hh" - namespace blender::ed::spreadsheet { /* Layout information for a single column. */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 7e2541d4eda..59bb6df75b7 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1979,6 +1979,10 @@ typedef struct SpaceSpreadsheet { */ ViewerPath viewer_path; + /** + * The "path" to the currently active instance reference. This is needed when viewing nested + * instances. + */ SpreadsheetInstanceID *instance_ids; int instance_ids_num; -- 2.30.2 From 5bcb32aab0202db581fb72d31e79ce042051e2a2 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 5 Jul 2024 09:50:35 +0200 Subject: [PATCH 10/17] remove unused method --- .../space_spreadsheet/spreadsheet_data_source_geometry.hh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index bca3b1efe96..c2f45d70002 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -71,11 +71,6 @@ class GeometryDataSource : public DataSource { { } - Object *object_eval() const - { - return object_eval_; - } - bool has_selection_filter() const override; IndexMask apply_selection_filter(IndexMaskMemory &memory) const; -- 2.30.2 From f09f6fd53a69cd3da1f1eda24f6edc0224093385 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 5 Jul 2024 10:01:42 +0200 Subject: [PATCH 11/17] Fix handling of selection filtering --- .../spreadsheet_data_source_geometry.cc | 32 +++++++++++-------- .../spreadsheet_data_source_geometry.hh | 11 ++++--- 2 files changed, 25 insertions(+), 18 deletions(-) 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 2377957a1be..00d6a2aa5d8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -341,31 +341,33 @@ int GeometryDataSource::tot_rows() const bool GeometryDataSource::has_selection_filter() const { - Object *object_orig = DEG_get_original_object(object_eval_); + if (!object_orig_) { + return false; + } switch (component_->type()) { case bke::GeometryComponent::Type::Mesh: { - if (object_orig->type != OB_MESH) { + if (object_orig_->type != OB_MESH) { return false; } - if (object_orig->mode != OB_MODE_EDIT) { + if (object_orig_->mode != OB_MODE_EDIT) { return false; } return true; } case bke::GeometryComponent::Type::Curve: { - if (object_orig->type != OB_CURVES) { + if (object_orig_->type != OB_CURVES) { return false; } - if (!ELEM(object_orig->mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) { + if (!ELEM(object_orig_->mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) { return false; } return true; } case bke::GeometryComponent::Type::PointCloud: { - if (object_orig->type != OB_POINTCLOUD) { + if (object_orig_->type != OB_POINTCLOUD) { return false; } - if (object_orig->mode != OB_MODE_EDIT) { + if (object_orig_->mode != OB_MODE_EDIT) { return false; } return true; @@ -385,12 +387,11 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co switch (component_->type()) { case bke::GeometryComponent::Type::Mesh: { - BLI_assert(object_eval_->type == OB_MESH); - BLI_assert(object_eval_->mode == OB_MODE_EDIT); - Object *object_orig = DEG_get_original_object(object_eval_); + BLI_assert(object_orig_->type == OB_MESH); + BLI_assert(object_orig_->mode == OB_MODE_EDIT); const Mesh *mesh_eval = geometry_set_.get_mesh(); const bke::AttributeAccessor attributes_eval = mesh_eval->attributes(); - Mesh *mesh_orig = (Mesh *)object_orig->data; + Mesh *mesh_orig = (Mesh *)object_orig_->data; BMesh *bm = mesh_orig->runtime->edit_mesh->bm; BM_mesh_elem_table_ensure(bm, BM_VERT); @@ -432,7 +433,7 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co return full_range; } case bke::GeometryComponent::Type::Curve: { - BLI_assert(object_eval_->type == OB_CURVES); + BLI_assert(object_orig_->type == OB_CURVES); const bke::CurveComponent &component = static_cast(*component_); const Curves &curves_id = *component.get(); switch (domain_) { @@ -446,7 +447,7 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co return full_range; } case bke::GeometryComponent::Type::PointCloud: { - BLI_assert(object_eval_->type == OB_POINTCLOUD); + BLI_assert(object_orig_->type == OB_POINTCLOUD); const bke::AttributeAccessor attributes = *component_->attributes(); const VArray &selection = *attributes.lookup_or_default( ".selection", bke::AttrDomain::Point, false); @@ -672,8 +673,11 @@ std::unique_ptr data_source_from_geometry(const bContext *C, Object if (component_type == bke::GeometryComponent::Type::Volume) { return std::make_unique(std::move(geometry_set)); } + Object *object_orig = sspreadsheet->instance_ids_num == 0 ? + DEG_get_original_object(object_eval) : + nullptr; return std::make_unique( - object_eval, std::move(geometry_set), component_type, domain, active_layer_index); + object_orig, std::move(geometry_set), component_type, domain, active_layer_index); } } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index c2f45d70002..61470d996da 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -40,8 +40,11 @@ class ExtraColumns { class GeometryDataSource : public DataSource { private: - /* TODO: Rethink handling of object_eval_. */ - Object *object_eval_; + /** + * Object that contains original data for the geometry component. This is used for selection + * filtering. May be null. + */ + Object *object_orig_; const bke::GeometrySet geometry_set_; const bke::GeometryComponent *component_; bke::AttrDomain domain_; @@ -56,13 +59,13 @@ class GeometryDataSource : public DataSource { mutable ResourceScope scope_; public: - GeometryDataSource(Object *object_eval, + GeometryDataSource(Object *object_orig, bke::GeometrySet geometry_set, const bke::GeometryComponent::Type component_type, const bke::AttrDomain domain, const int layer_index = -1, ExtraColumns extra_columns = {}) - : object_eval_(object_eval), + : object_orig_(object_orig), geometry_set_(std::move(geometry_set)), component_(geometry_set_.get_component(component_type)), domain_(domain), -- 2.30.2 From 45f70ca9101c3d7e16fe957c5647198079df755a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Jul 2024 17:16:33 +0200 Subject: [PATCH 12/17] use blank icon for generic geometry sets --- .../space_spreadsheet/spreadsheet_data_source_geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 00d6a2aa5d8..b252f7960d1 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -561,7 +561,7 @@ int get_instance_reference_icon(const bke::InstanceReference &reference) return ICON_OUTLINER_COLLECTION; } case bke::InstanceReference::Type::GeometrySet: { - return ICON_EMPTY_AXIS; + return ICON_BLANK1; } case bke::InstanceReference::Type::None: { break; -- 2.30.2 From c51e8a59ec2abb8ec1c60097c70b65c4f4c9ba08 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Jul 2024 18:48:46 +0200 Subject: [PATCH 13/17] show dot for geometry --- .../space_spreadsheet/spreadsheet_data_source_geometry.cc | 2 +- .../editors/space_spreadsheet/spreadsheet_dataset_draw.cc | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) 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 b252f7960d1..66d1870c4a2 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -561,7 +561,7 @@ int get_instance_reference_icon(const bke::InstanceReference &reference) return ICON_OUTLINER_COLLECTION; } case bke::InstanceReference::Type::GeometrySet: { - return ICON_BLANK1; + return ICON_DOT; } case bke::InstanceReference::Type::None: { break; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index a8f1300e7de..ab1648f81cd 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -397,7 +397,11 @@ class InstanceReferenceViewItem : public DataSetViewItem { void build_row(uiLayout &row) override { const int icon = get_instance_reference_icon(reference_); - uiItemL(&row, reference_.name().c_str(), icon); + std::string name = reference_.name(); + if (name.empty()) { + name = IFACE_("Geometry"); + } + uiItemL(&row, name.c_str(), icon); } int reference_index() const -- 2.30.2 From d11ff8326d3c21d5708906984115c1b445743597 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Jul 2024 18:52:30 +0200 Subject: [PATCH 14/17] show icon in table even if name is empty --- .../space_spreadsheet/spreadsheet_layout.cc | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 4c7ff6f959e..198074137ad 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -206,21 +206,19 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { const bke::InstanceReference value = data.get(real_index); const std::string name = value.name(); const int icon = get_instance_reference_icon(value); - if (!name.empty()) { - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - icon, - name.c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - nullptr); - } + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + icon, + name.c_str(), + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + nullptr); } else if (data.type().is()) { uiDefIconTextBut(params.block, -- 2.30.2 From 08457ec710b5b78f62762a2a14e7a42cf63e74cc Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 11 Jul 2024 18:15:53 +0200 Subject: [PATCH 15/17] don't show as activatable for some items --- .../editors/interface/interface_intern.hh | 2 ++ .../editors/interface/interface_widgets.cc | 10 +++++-- .../editors/interface/views/tree_view.cc | 1 + .../spreadsheet_dataset_draw.cc | 29 +++++++------------ 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index 68d5a806f70..5a0553abb66 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -416,6 +416,8 @@ struct uiButViewItem : public uiBut { * (e.g. so highlights are drawn smaller). */ int draw_width = 0; int draw_height = 0; + + bool activateable = true; }; /** Derived struct for #UI_BTYPE_HSVCUBE. */ diff --git a/source/blender/editors/interface/interface_widgets.cc b/source/blender/editors/interface/interface_widgets.cc index bf387710fe6..80637789da5 100644 --- a/source/blender/editors/interface/interface_widgets.cc +++ b/source/blender/editors/interface/interface_widgets.cc @@ -4205,8 +4205,10 @@ static void widget_list_itembut(uiBut *but, { rcti draw_rect = *rect; + bool activateable = true; if (but->type == UI_BTYPE_VIEW_ITEM) { uiButViewItem *item_but = static_cast(but); + activateable = item_but->activateable; if (item_but->draw_width > 0) { BLI_rcti_resize_x(&draw_rect, zoom * item_but->draw_width); } @@ -4223,9 +4225,11 @@ static void widget_list_itembut(uiBut *but, const float rad = widget_radius_from_zoom(zoom, wcol); round_box_edges(&wtb, UI_CNR_ALL, &draw_rect, rad); - if (state->but_flag & UI_HOVER && !(state->but_flag & UI_SELECT)) { - copy_v3_v3_uchar(wcol->inner, wcol->text); - wcol->inner[3] = 20; + if (activateable) { + if (state->but_flag & UI_HOVER && !(state->but_flag & UI_SELECT)) { + copy_v3_v3_uchar(wcol->inner, wcol->text); + wcol->inner[3] = 20; + } } widgetbase_draw(&wtb, wcol); diff --git a/source/blender/editors/interface/views/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc index 9b6a7be3163..58ae43dde20 100644 --- a/source/blender/editors/interface/views/tree_view.cc +++ b/source/blender/editors/interface/views/tree_view.cc @@ -322,6 +322,7 @@ void AbstractTreeViewItem::add_treerow_button(uiBlock &block) view_item_but_->view_item = this; view_item_but_->draw_height = unpadded_item_height(); + view_item_but_->activateable = is_activatable_; UI_but_func_set(view_item_but_, tree_row_click_fn, view_item_but_, nullptr); } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index ab1648f81cd..1ada552ccd0 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -135,6 +135,7 @@ class MeshViewItem : public DataSetViewItem { MeshViewItem() { label_ = IFACE_("Mesh"); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -174,6 +175,7 @@ class CurvesViewItem : public DataSetViewItem { CurvesViewItem() { label_ = IFACE_("Curve"); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -214,6 +216,7 @@ class GreasePencilViewItem : public DataSetViewItem { GreasePencilViewItem() { label_ = IFACE_("Grease Pencil"); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -256,6 +259,7 @@ class GreasePencilLayerViewItem : public DataSetViewItem { : layer_(layer), layer_index_(layer_index) { label_ = layer_.name(); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -302,6 +306,7 @@ class PointCloudViewItem : public DataSetViewItem { PointCloudViewItem() { label_ = IFACE_("Point Cloud"); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -392,6 +397,7 @@ class InstanceReferenceViewItem : public DataSetViewItem { : reference_(instances.references()[reference_index]), reference_index_(reference_index) { label_ = std::to_string(reference_index); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -420,6 +426,7 @@ class CollectionChildViewItem : public DataSetViewItem { : collection_child_(&collection_child), child_index_(child_index) { label_ = std::to_string(child_index); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -443,6 +450,7 @@ class CollectionObjectViewItem : public DataSetViewItem { : collection_object_(&collection_object), child_index_(child_index) { label_ = std::to_string(child_index); + this->disable_activatable(); } void build_row(uiLayout &row) override @@ -623,29 +631,12 @@ void DataSetViewItem::get_parent_instance_ids(Vector &r_i void DataSetViewItem::on_activate(bContext &C) { - Vector instance_ids; std::optional data_id = this->get_geometry_data_id(); - if (data_id) { - this->get_parent_instance_ids(instance_ids); - } - else { - /* Try to find the next data item that can be activated. */ - this->foreach_item_recursive([&](const ui::AbstractTreeViewItem &item) { - if (data_id) { - return; - } - if (auto *data_set_view_item = dynamic_cast(&item)) { - data_id = data_set_view_item->get_geometry_data_id(); - if (data_id) { - data_set_view_item->get_parent_instance_ids(instance_ids); - } - } - }); - } - if (!data_id) { return; } + Vector instance_ids; + this->get_parent_instance_ids(instance_ids); bScreen &screen = *CTX_wm_screen(&C); SpaceSpreadsheet &sspreadsheet = *CTX_wm_space_spreadsheet(&C); -- 2.30.2 From 30a241247627a4b420bb3ea9360f64ce9530f70c Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 22 Jul 2024 12:48:10 +0200 Subject: [PATCH 16/17] use three dots icon --- .../space_spreadsheet/spreadsheet_data_source_geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 66d1870c4a2..6cd334ee285 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -561,7 +561,7 @@ int get_instance_reference_icon(const bke::InstanceReference &reference) return ICON_OUTLINER_COLLECTION; } case bke::InstanceReference::Type::GeometrySet: { - return ICON_DOT; + return ICON_THREE_DOTS; } case bke::InstanceReference::Type::None: { break; -- 2.30.2 From ee4858cb753920f08caf1751b38a497460994ee9 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 22 Jul 2024 12:50:38 +0200 Subject: [PATCH 17/17] use fallback name in spreadsheet --- source/blender/editors/space_spreadsheet/spreadsheet_layout.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 198074137ad..2d99ce37a8f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -204,7 +204,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { } else if (data.type().is()) { const bke::InstanceReference value = data.get(real_index); - const std::string name = value.name(); + const StringRefNull name = value.name().is_empty() ? "Geometry" : value.name(); const int icon = get_instance_reference_icon(value); uiDefIconTextBut(params.block, UI_BTYPE_LABEL, -- 2.30.2