Spreadsheet: support showing data of nested instances (alternative 1) #124186
@ -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,
|
||||
|
@ -421,6 +421,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. */
|
||||
|
@ -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<uiButViewItem *>(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);
|
||||
|
@ -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. */
|
||||
@ -315,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);
|
||||
}
|
||||
|
||||
|
@ -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<SpreadsheetInstanceID *>(
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
@ -632,13 +633,39 @@ 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<SpreadsheetInstanceID> 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<bke::InstanceReference> 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];
|
||||
bke::GeometrySet reference_geometry;
|
||||
reference.to_geometry_set(reference_geometry);
|
||||
geometry = reference_geometry;
|
||||
}
|
||||
return geometry;
|
||||
}
|
||||
|
||||
std::unique_ptr<DataSource> 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 {};
|
||||
}
|
||||
@ -646,7 +673,9 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
|
||||
if (component_type == bke::GeometryComponent::Type::Volume) {
|
||||
return std::make_unique<VolumeDataSource>(std::move(geometry_set));
|
||||
}
|
||||
Object *object_orig = DEG_get_original_object(object_eval);
|
||||
Object *object_orig = sspreadsheet->instance_ids_num == 0 ?
|
||||
DEG_get_original_object(object_eval) :
|
||||
nullptr;
|
||||
return std::make_unique<GeometryDataSource>(
|
||||
object_orig, std::move(geometry_set), component_type, domain, active_layer_index);
|
||||
}
|
||||
|
@ -117,6 +117,8 @@ class DataSetViewItem : public ui::AbstractTreeViewItem {
|
||||
public:
|
||||
GeometryDataSetTreeView &get_tree() const;
|
||||
|
||||
void get_parent_instance_ids(Vector<SpreadsheetInstanceID> &r_instance_ids) const;
|
||||
|
||||
void on_activate(bContext &C) override;
|
||||
|
||||
std::optional<bool> should_be_active() const override;
|
||||
@ -133,6 +135,7 @@ class MeshViewItem : public DataSetViewItem {
|
||||
MeshViewItem()
|
||||
{
|
||||
label_ = IFACE_("Mesh");
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
void build_row(uiLayout &row) override
|
||||
@ -172,6 +175,7 @@ class CurvesViewItem : public DataSetViewItem {
|
||||
CurvesViewItem()
|
||||
{
|
||||
label_ = IFACE_("Curve");
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
void build_row(uiLayout &row) override
|
||||
@ -212,6 +216,7 @@ class GreasePencilViewItem : public DataSetViewItem {
|
||||
GreasePencilViewItem()
|
||||
{
|
||||
label_ = IFACE_("Grease Pencil");
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
void build_row(uiLayout &row) override
|
||||
@ -254,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
|
||||
@ -300,6 +306,7 @@ class PointCloudViewItem : public DataSetViewItem {
|
||||
PointCloudViewItem()
|
||||
{
|
||||
label_ = IFACE_("Point Cloud");
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
void build_row(uiLayout &row) override
|
||||
@ -380,6 +387,84 @@ 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);
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
void build_row(uiLayout &row) override
|
||||
{
|
||||
const int icon = get_instance_reference_icon(reference_);
|
||||
std::string name = reference_.name();
|
||||
if (name.empty()) {
|
||||
name = IFACE_("Geometry");
|
||||
}
|
||||
uiItemL(&row, name.c_str(), icon);
|
||||
}
|
||||
|
||||
int reference_index() const
|
||||
{
|
||||
return reference_index_;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
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);
|
||||
this->disable_activatable();
|
||||
}
|
||||
|
||||
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_;
|
||||
@ -398,28 +483,37 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView {
|
||||
|
||||
void build_tree() override
|
||||
{
|
||||
this->build_tree_for_geometry(root_geometry_set_, *this);
|
||||
this->build_tree_for_geometry(root_geometry_set_, *this, true);
|
||||
}
|
||||
|
||||
void build_tree_for_geometry(const bke::GeometrySet &geometry, ui::TreeViewItemContainer &parent)
|
||||
void build_tree_for_geometry(const bke::GeometrySet &geometry,
|
||||
ui::TreeViewItemContainer &parent,
|
||||
const bool all_components)
|
||||
{
|
||||
const Mesh *mesh = geometry.get_mesh();
|
||||
this->build_tree_for_mesh(mesh, parent);
|
||||
|
||||
if (mesh || all_components) {
|
||||
this->build_tree_for_mesh(mesh, parent);
|
||||
}
|
||||
const Curves *curves = geometry.get_curves();
|
||||
this->build_tree_for_curves(curves, parent);
|
||||
|
||||
if (curves || all_components) {
|
||||
this->build_tree_for_curves(curves, parent);
|
||||
}
|
||||
const GreasePencil *grease_pencil = geometry.get_grease_pencil();
|
||||
this->build_tree_for_grease_pencil(grease_pencil, parent);
|
||||
|
||||
if (grease_pencil || all_components) {
|
||||
this->build_tree_for_grease_pencil(grease_pencil, parent);
|
||||
}
|
||||
const PointCloud *pointcloud = geometry.get_pointcloud();
|
||||
this->build_tree_for_pointcloud(pointcloud, parent);
|
||||
|
||||
if (pointcloud || all_components) {
|
||||
this->build_tree_for_pointcloud(pointcloud, parent);
|
||||
}
|
||||
const Volume *volume = geometry.get_volume();
|
||||
this->build_tree_for_volume(volume, parent);
|
||||
|
||||
if (volume || all_components) {
|
||||
this->build_tree_for_volume(volume, parent);
|
||||
}
|
||||
const bke::Instances *instances = geometry.get_instances();
|
||||
this->build_tree_for_instances(instances, parent);
|
||||
if (instances || all_components) {
|
||||
this->build_tree_for_instances(instances, parent);
|
||||
}
|
||||
}
|
||||
|
||||
void build_tree_for_mesh(const Mesh *mesh, ui::TreeViewItemContainer &parent)
|
||||
@ -475,7 +569,41 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView {
|
||||
|
||||
void build_tree_for_instances(const bke::Instances *instances, ui::TreeViewItemContainer &parent)
|
||||
{
|
||||
parent.add_tree_item<InstancesViewItem>(instances);
|
||||
auto &instances_view = parent.add_tree_item<InstancesViewItem>(instances);
|
||||
if (!instances) {
|
||||
return;
|
||||
}
|
||||
const Span<bke::InstanceReference> references = instances->references();
|
||||
for (const int reference_i : references.index_range()) {
|
||||
auto &reference_item = instances_view.add_tree_item<InstanceReferenceViewItem>(*instances,
|
||||
reference_i);
|
||||
const bke::InstanceReference &reference = references[reference_i];
|
||||
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<CollectionChildViewItem>(
|
||||
*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<CollectionObjectViewItem>(
|
||||
*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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -484,26 +612,40 @@ GeometryDataSetTreeView &DataSetViewItem::get_tree() const
|
||||
return static_cast<GeometryDataSetTreeView &>(this->get_tree_view());
|
||||
}
|
||||
|
||||
void DataSetViewItem::get_parent_instance_ids(Vector<SpreadsheetInstanceID> &r_instance_ids) const
|
||||
{
|
||||
this->foreach_parent([&](const ui::AbstractTreeViewItem &item) {
|
||||
if (auto *reference_item = dynamic_cast<const InstanceReferenceViewItem *>(&item)) {
|
||||
r_instance_ids.append({reference_item->reference_index()});
|
||||
}
|
||||
else if (auto *collection_object_item = dynamic_cast<const CollectionObjectViewItem *>(&item))
|
||||
{
|
||||
r_instance_ids.append({collection_object_item->child_index()});
|
||||
}
|
||||
else if (auto *collection_child_item = dynamic_cast<const CollectionChildViewItem *>(&item)) {
|
||||
r_instance_ids.append({collection_child_item->child_index()});
|
||||
}
|
||||
});
|
||||
std::reverse(r_instance_ids.begin(), r_instance_ids.end());
|
||||
}
|
||||
|
||||
void DataSetViewItem::on_activate(bContext &C)
|
||||
{
|
||||
std::optional<GeometryDataIdentifier> data_id = this->get_geometry_data_id();
|
||||
if (!data_id) {
|
||||
this->foreach_item_recursive([&](const ui::AbstractTreeViewItem &item) {
|
||||
if (data_id) {
|
||||
return;
|
||||
}
|
||||
if (auto *data_set_view_item = dynamic_cast<const DataSetViewItem *>(&item)) {
|
||||
data_id = data_set_view_item->get_geometry_data_id();
|
||||
}
|
||||
});
|
||||
if (!data_id) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Vector<SpreadsheetInstanceID> 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<SpreadsheetInstanceID>(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_id->component_type);
|
||||
if (data_id->domain) {
|
||||
sspreadsheet.attribute_domain = uint8_t(*data_id->domain);
|
||||
@ -542,6 +684,18 @@ std::optional<bool> DataSetViewItem::should_be_active() const
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Vector<SpreadsheetInstanceID> 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;
|
||||
}
|
||||
|
||||
|
@ -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,13 @@ 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;
|
||||
|
||||
/* eSpaceSpreadsheet_FilterFlag. */
|
||||
uint8_t filter_flag;
|
||||
|
||||
@ -1989,7 +2000,6 @@ typedef struct SpaceSpreadsheet {
|
||||
|
||||
/* eSpaceSpreadsheet_Flag. */
|
||||
uint32_t flag;
|
||||
char _pad1[4];
|
||||
|
||||
SpaceSpreadsheet_Runtime *runtime;
|
||||
} SpaceSpreadsheet;
|
||||
|
Loading…
Reference in New Issue
Block a user