From 474adc6f883c2d5a854d7324364f7996044d83cb Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 15 Dec 2021 09:34:13 -0600 Subject: Refactor: Simplify spreadsheet handling of cell values Previously we used a `CellValue` class to hold the data for a cell, and called a function to fill it whenever necessary. This is an unnecessary complication when we have virtual generic arrays and most data is already easily accessible that way anyway. This patch removes `CellValue` and uses `fn::GVArray` to provide access to data instead. In the future, if rows have different types within a single column, we can use a `GVArray` of `blender::Any` to interface with the drawing. Along with that, the use of virtual arrays made it easy to do a few other cleanups: - Use selection domain interpolations from rB5841f8656d95 for the mesh selection filter. - Change the row filter to only calculate for necessary indices. Differential Revision: https://developer.blender.org/D13478 --- .../intern/geometry_component_instances.cc | 4 + .../editors/space_spreadsheet/CMakeLists.txt | 1 - .../editors/space_spreadsheet/space_spreadsheet.cc | 2 + .../space_spreadsheet/spreadsheet_cell_value.hh | 64 ---- .../space_spreadsheet/spreadsheet_column.cc | 38 ++ .../space_spreadsheet/spreadsheet_column_values.hh | 60 +-- .../spreadsheet_data_source_geometry.cc | 376 ++++--------------- .../spreadsheet_data_source_geometry.hh | 2 +- .../space_spreadsheet/spreadsheet_layout.cc | 171 ++++----- .../space_spreadsheet/spreadsheet_layout.hh | 2 +- .../space_spreadsheet/spreadsheet_row_filter.cc | 413 ++++++++++----------- .../space_spreadsheet/spreadsheet_row_filter.hh | 8 +- .../space_spreadsheet/spreadsheet_row_filter_ui.cc | 6 + .../blender/functions/FN_generic_virtual_array.hh | 15 + source/blender/makesdna/DNA_space_types.h | 1 + 15 files changed, 449 insertions(+), 714 deletions(-) delete mode 100644 source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 62d66f13e9f..93a7646fed0 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -31,6 +31,8 @@ #include "attribute_access_intern.hh" +#include "FN_cpp_type_make.hh" + using blender::float4x4; using blender::Map; using blender::MutableSpan; @@ -39,6 +41,8 @@ using blender::Span; using blender::VectorSet; using blender::fn::GSpan; +MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None) + /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation * \{ */ diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 27446fe1a94..f1db8dedf1a 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -49,7 +49,6 @@ set(SRC spreadsheet_row_filter_ui.cc spreadsheet_cache.hh - spreadsheet_cell_value.hh spreadsheet_column.hh spreadsheet_column_values.hh spreadsheet_context.hh diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 0cb4a52eb2f..61cc70830af 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -323,6 +323,8 @@ static float get_default_column_width(const ColumnValues &values) return 8.0f; case SPREADSHEET_VALUE_TYPE_STRING: return 5.0f; + case SPREADSHEET_VALUE_TYPE_UNKNOWN: + return 2.0f; } return float_width; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh deleted file mode 100644 index c11b4a2b23d..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include - -#include "BLI_color.hh" -#include "BLI_float2.hh" -#include "BLI_float3.hh" - -struct Collection; -struct Object; - -namespace blender::ed::spreadsheet { - -struct ObjectCellValue { - const Object *object; -}; - -struct CollectionCellValue { - const Collection *collection; -}; - -struct GeometrySetCellValue { - const GeometrySet *geometry_set; -}; - -/** - * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to - * decouple the drawing of individual cells from the code that generates the data to be displayed. - */ -class CellValue { - public: - /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use - * `std::variant` yet, due to missing compiler support. This type can really be optimized more, - * but it does not really matter too much currently. */ - - std::optional value_int; - std::optional value_float; - std::optional value_bool; - std::optional value_float2; - std::optional value_float3; - std::optional value_color; - std::optional value_object; - std::optional value_collection; - std::optional value_geometry_set; - std::optional value_string; -}; - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index ee08c86b29f..7551593ef38 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -18,14 +18,52 @@ #include "MEM_guardedalloc.h" +#include "BLI_color.hh" +#include "BLI_float2.hh" +#include "BLI_float3.hh" #include "BLI_hash.hh" #include "BLI_string.h" #include "BLI_string_ref.hh" +#include "BKE_geometry_set.hh" + +#include "FN_cpp_type.hh" + #include "spreadsheet_column.hh" +#include "spreadsheet_column_values.hh" namespace blender::ed::spreadsheet { +eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type) +{ + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_BOOL; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_INT32; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_FLOAT; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_FLOAT2; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_FLOAT3; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_COLOR; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_STRING; + } + if (type.is()) { + return SPREADSHEET_VALUE_TYPE_INSTANCES; + } + + return SPREADSHEET_VALUE_TYPE_UNKNOWN; +} + SpreadsheetColumnID *spreadsheet_column_id_new() { SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID), diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh index 877651d6530..83e3217e5c8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh @@ -20,33 +20,36 @@ #include "BLI_string_ref.hh" -#include "spreadsheet_cell_value.hh" +#include "FN_generic_virtual_array.hh" namespace blender::ed::spreadsheet { +struct CellDrawParams; + +eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type); + /** * This represents a column in a spreadsheet. It has a name and provides a value for all the cells * in the column. */ -class ColumnValues { +class ColumnValues final { protected: - eSpreadsheetColumnValueType type_; std::string name_; - int size_; + + fn::GVArray data_; public: - ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size) - : type_(type), name_(std::move(name)), size_(size) + ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data)) { + /* The array should not be empty. */ + BLI_assert(data_); } virtual ~ColumnValues() = default; - virtual void get_value(int index, CellValue &r_cell_value) const = 0; - eSpreadsheetColumnValueType type() const { - return type_; + return cpp_type_to_column_type(data_.type()); } StringRefNull name() const @@ -56,45 +59,16 @@ class ColumnValues { int size() const { - return size_; + return data_.size(); } - /* The default width of newly created columns, in UI units. */ - float default_width = 0.0f; -}; - -/* Utility class for the function below. */ -template class LambdaColumnValues : public ColumnValues { - private: - GetValueF get_value_; - - public: - LambdaColumnValues(const eSpreadsheetColumnValueType type, - std::string name, - int size, - GetValueF get_value) - : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value)) + const fn::GVArray &data() const { + return data_; } - void get_value(int index, CellValue &r_cell_value) const final - { - get_value_(index, r_cell_value); - } + /* The default width of newly created columns, in UI units. */ + float default_width = 0.0f; }; -/* Utility function that simplifies creating a spreadsheet column from a lambda function. */ -template -std::unique_ptr column_values_from_function(const eSpreadsheetColumnValueType type, - std::string name, - const int size, - GetValueF get_value, - const float default_width = 0.0f) -{ - std::unique_ptr column_values = std::make_unique>( - type, std::move(name), size, std::move(get_value)); - column_values->default_width = default_width; - return column_values; -} - } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 173ef43bfb6..337a6037c42 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BLI_virtual_array.hh" + #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" @@ -51,30 +53,6 @@ using blender::fn::GField; namespace blender::ed::spreadsheet { -static std::optional cpp_type_to_column_value_type( - const fn::CPPType &type) -{ - if (type.is()) { - return SPREADSHEET_VALUE_TYPE_BOOL; - } - if (type.is()) { - return SPREADSHEET_VALUE_TYPE_INT32; - } - if (type.is()) { - return SPREADSHEET_VALUE_TYPE_FLOAT; - } - if (type.is()) { - return SPREADSHEET_VALUE_TYPE_FLOAT2; - } - if (type.is()) { - return SPREADSHEET_VALUE_TYPE_FLOAT3; - } - if (type.is()) { - return SPREADSHEET_VALUE_TYPE_COLOR; - } - return std::nullopt; -} - void ExtraColumns::foreach_default_column_ids( FunctionRef fn) const { @@ -92,39 +70,7 @@ std::unique_ptr ExtraColumns::get_column_values( if (values == nullptr) { return {}; } - eSpreadsheetColumnValueType column_type = *cpp_type_to_column_value_type(values->type()); - return column_values_from_function(column_type, - column_id.name, - values->size(), - [column_type, values](int index, CellValue &r_cell_value) { - const void *value = (*values)[index]; - switch (column_type) { - case SPREADSHEET_VALUE_TYPE_BOOL: - r_cell_value.value_bool = *(const bool *)value; - break; - case SPREADSHEET_VALUE_TYPE_INT32: - r_cell_value.value_int = *(const int *)value; - break; - case SPREADSHEET_VALUE_TYPE_FLOAT: - r_cell_value.value_float = *(const float *)value; - break; - case SPREADSHEET_VALUE_TYPE_FLOAT2: - r_cell_value.value_float2 = *(const float2 *)value; - break; - case SPREADSHEET_VALUE_TYPE_FLOAT3: - r_cell_value.value_float3 = *(const float3 *)value; - break; - case SPREADSHEET_VALUE_TYPE_COLOR: - r_cell_value.value_color = *( - const ColorGeometry4f *)value; - break; - case SPREADSHEET_VALUE_TYPE_STRING: - r_cell_value.value_string = *(const std::string *)value; - break; - case SPREADSHEET_VALUE_TYPE_INSTANCES: - break; - } - }); + return std::make_unique(column_id.name, fn::GVArray::ForSpan(*values)); } void GeometryDataSource::foreach_default_column_ids( @@ -179,52 +125,25 @@ std::unique_ptr GeometryDataSource::get_column_values( if (STREQ(column_id.name, "Name")) { Span reference_handles = instances.instance_reference_handles(); Span references = instances.references(); - std::unique_ptr values = column_values_from_function( - SPREADSHEET_VALUE_TYPE_INSTANCES, - "Name", - domain_size, - [reference_handles, references](int index, CellValue &r_cell_value) { - const InstanceReference &reference = references[reference_handles[index]]; - switch (reference.type()) { - case InstanceReference::Type::Object: { - Object &object = reference.object(); - r_cell_value.value_object = ObjectCellValue{&object}; - break; - } - case InstanceReference::Type::Collection: { - Collection &collection = reference.collection(); - r_cell_value.value_collection = CollectionCellValue{&collection}; - break; - } - case InstanceReference::Type::GeometrySet: { - const GeometrySet &geometry_set = reference.geometry_set(); - r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set}; - break; - } - case InstanceReference::Type::None: { - break; - } - } - }); - return values; + return std::make_unique( + column_id.name, + VArray::ForFunc(domain_size, + [reference_handles, references](int64_t index) { + return references[reference_handles[index]]; + })); } Span transforms = instances.instance_transforms(); if (STREQ(column_id.name, "Rotation")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_FLOAT3, - column_id.name, - domain_size, - [transforms](int index, CellValue &r_cell_value) { - r_cell_value.value_float3 = transforms[index].to_euler(); - }); + return std::make_unique( + column_id.name, VArray::ForFunc(domain_size, [transforms](int64_t index) { + return transforms[index].to_euler(); + })); } if (STREQ(column_id.name, "Scale")) { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3, - column_id.name, - domain_size, - [transforms](int index, CellValue &r_cell_value) { - r_cell_value.value_float3 = transforms[index].scale(); - }); + return std::make_unique( + column_id.name, VArray::ForFunc(domain_size, [transforms](int64_t index) { + return transforms[index].scale(); + })); } } @@ -237,71 +156,7 @@ std::unique_ptr GeometryDataSource::get_column_values( return {}; } - const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type()); - switch (type) { - case CD_PROP_FLOAT: - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - float value; - varray.get(index, &value); - r_cell_value.value_float = value; - }); - case CD_PROP_INT32: - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_INT32, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - int value; - varray.get(index, &value); - r_cell_value.value_int = value; - }, - STREQ(column_id.name, "id") ? 5.5f : 0.0f); - case CD_PROP_BOOL: - return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - bool value; - varray.get(index, &value); - r_cell_value.value_bool = value; - }); - case CD_PROP_FLOAT2: { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT2, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - float2 value; - varray.get(index, &value); - r_cell_value.value_float2 = value; - }); - } - case CD_PROP_FLOAT3: { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - float3 value; - varray.get(index, &value); - r_cell_value.value_float3 = value; - }); - } - case CD_PROP_COLOR: { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_COLOR, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - ColorGeometry4f value; - varray.get(index, &value); - r_cell_value.value_color = value; - }); - } - default: - break; - } - return {}; + return std::make_unique(column_id.name, std::move(varray)); } int GeometryDataSource::tot_rows() const @@ -309,90 +164,9 @@ int GeometryDataSource::tot_rows() const return component_->attribute_domain_size(domain_); } -using IsVertexSelectedFn = FunctionRef; - -static void get_selected_vertex_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan selection) -{ - for (const int i : IndexRange(mesh.totvert)) { - if (!selection[i]) { - continue; - } - if (!is_vertex_selected_fn(i)) { - selection[i] = false; - } - } -} - -static void get_selected_corner_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan selection) -{ - for (const int i : IndexRange(mesh.totloop)) { - const MLoop &loop = mesh.mloop[i]; - if (!selection[i]) { - continue; - } - if (!is_vertex_selected_fn(loop.v)) { - selection[i] = false; - } - } -} - -static void get_selected_face_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan selection) -{ - for (const int poly_index : IndexRange(mesh.totpoly)) { - if (!selection[poly_index]) { - continue; - } - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; - if (!is_vertex_selected_fn(loop.v)) { - selection[poly_index] = false; - break; - } - } - } -} - -static void get_selected_edge_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan selection) -{ - for (const int i : IndexRange(mesh.totedge)) { - if (!selection[i]) { - continue; - } - const MEdge &edge = mesh.medge[i]; - if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) { - selection[i] = false; - } - } -} - -static void get_selected_indices_on_domain(const Mesh &mesh, - const AttributeDomain domain, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan selection) -{ - switch (domain) { - case ATTR_DOMAIN_POINT: - return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection); - case ATTR_DOMAIN_FACE: - return get_selected_face_indices(mesh, is_vertex_selected_fn, selection); - case ATTR_DOMAIN_CORNER: - return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection); - case ATTR_DOMAIN_EDGE: - return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection); - default: - return; - } -} - +/** + * Only data sets corresponding to mesh objects in edit mode currently support selection filtering. + */ bool GeometryDataSource::has_selection_filter() const { Object *object_orig = DEG_get_original_object(object_eval_); @@ -409,7 +183,18 @@ bool GeometryDataSource::has_selection_filter() const return true; } -void GeometryDataSource::apply_selection_filter(MutableSpan rows_included) const +static IndexMask index_mask_from_bool_array(const VArray &selection, + Vector &indices) +{ + for (const int i : selection.index_range()) { + if (selection[i]) { + indices.append(i); + } + } + return IndexMask(indices); +} + +IndexMask GeometryDataSource::apply_selection_filter(Vector &indices) const { std::lock_guard lock{mutex_}; @@ -425,27 +210,38 @@ void GeometryDataSource::apply_selection_filter(MutableSpan rows_included) int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX); if (orig_indices != nullptr) { /* Use CD_ORIGINDEX layer if it exists. */ - auto is_vertex_selected = [&](int vertex_index) -> bool { - const int i_orig = orig_indices[vertex_index]; - if (i_orig < 0) { - return false; - } - if (i_orig >= bm->totvert) { - return false; - } - BMVert *vert = bm->vtable[i_orig]; - return BM_elem_flag_test(vert, BM_ELEM_SELECT); - }; - get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included); - } - else if (mesh_eval->totvert == bm->totvert) { + VArray selection = mesh_component->attribute_try_adapt_domain( + VArray::ForFunc(mesh_eval->totvert, + [bm, orig_indices](int vertex_index) -> bool { + const int i_orig = orig_indices[vertex_index]; + if (i_orig < 0) { + return false; + } + if (i_orig >= bm->totvert) { + return false; + } + BMVert *vert = bm->vtable[i_orig]; + return BM_elem_flag_test(vert, BM_ELEM_SELECT); + }), + ATTR_DOMAIN_POINT, + domain_); + return index_mask_from_bool_array(selection, indices); + } + + if (mesh_eval->totvert == bm->totvert) { /* Use a simple heuristic to match original vertices to evaluated ones. */ - auto is_vertex_selected = [&](int vertex_index) -> bool { - BMVert *vert = bm->vtable[vertex_index]; - return BM_elem_flag_test(vert, BM_ELEM_SELECT); - }; - get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included); - } + VArray selection = mesh_component->attribute_try_adapt_domain( + VArray::ForFunc(mesh_eval->totvert, + [bm](int vertex_index) -> bool { + BMVert *vert = bm->vtable[vertex_index]; + return BM_elem_flag_test(vert, BM_ELEM_SELECT); + }), + ATTR_DOMAIN_POINT, + domain_); + return index_mask_from_bool_array(selection, indices); + } + + return IndexMask(mesh_eval->totvert); } void VolumeDataSource::foreach_default_column_ids( @@ -472,50 +268,36 @@ std::unique_ptr VolumeDataSource::get_column_values( #ifdef WITH_OPENVDB const int size = this->tot_rows(); if (STREQ(column_id.name, "Grid Name")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_STRING, - IFACE_("Grid Name"), - size, - [volume](int index, CellValue &r_cell_value) { + return std::make_unique( + IFACE_("Grid Name"), VArray::ForFunc(size, [volume](int64_t index) { const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); - r_cell_value.value_string = BKE_volume_grid_name(volume_grid); - }, - 6.0f); + return BKE_volume_grid_name(volume_grid); + })); } if (STREQ(column_id.name, "Data Type")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_STRING, - IFACE_("Type"), - size, - [volume](int index, CellValue &r_cell_value) { + return std::make_unique( + IFACE_("Data Type"), VArray::ForFunc(size, [volume](int64_t index) { const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); const VolumeGridType type = BKE_volume_grid_type(volume_grid); const char *name = nullptr; RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name); - r_cell_value.value_string = IFACE_(name); - }, - 5.0f); + return IFACE_(name); + })); } if (STREQ(column_id.name, "Class")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_STRING, - IFACE_("Class"), - size, - [volume](int index, CellValue &r_cell_value) { + return std::make_unique( + IFACE_("Class"), VArray::ForFunc(size, [volume](int64_t index) { const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); openvdb::GridClass grid_class = grid->getGridClass(); if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) { - r_cell_value.value_string = IFACE_("Fog Volume"); - } - else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) { - r_cell_value.value_string = IFACE_("Level Set"); + return IFACE_("Fog Volume"); } - else { - r_cell_value.value_string = IFACE_("Unknown"); + if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) { + return IFACE_("Level Set"); } - }, - 5.0f); + return IFACE_("Unknown"); + })); } #else UNUSED_VARS(column_id); 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 23207734d2b..b5105050d2b 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -87,7 +87,7 @@ class GeometryDataSource : public DataSource { * filtering. */ bool has_selection_filter() const override; - void apply_selection_filter(MutableSpan rows_included) const; + IndexMask apply_selection_filter(Vector &indices) const; void foreach_default_column_ids( FunctionRef fn) const override; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 202523c0e64..7cc2d8d0b48 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -17,8 +17,16 @@ #include #include +#include "BLI_float2.hh" +#include "BLI_float3.hh" + +#include "BKE_geometry_set.hh" + +#include "spreadsheet_column_values.hh" #include "spreadsheet_layout.hh" +#include "DNA_collection_types.h" +#include "DNA_object_types.h" #include "DNA_userdef_types.h" #include "UI_interface.h" @@ -92,13 +100,14 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { { const int real_index = spreadsheet_layout_.row_indices[row_index]; const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values; - CellValue cell_value; - if (real_index < column.size()) { - column.get_value(real_index, cell_value); + if (real_index > column.size()) { + return; } - if (cell_value.value_int.has_value()) { - const int value = *cell_value.value_int; + const fn::GVArray &data = column.data(); + + if (data.type().is()) { + const int value = data.get(real_index); const std::string value_str = std::to_string(value); uiBut *but = uiDefIconTextBut(params.block, UI_BTYPE_LABEL, @@ -119,8 +128,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); } - else if (cell_value.value_float.has_value()) { - const float value = *cell_value.value_float; + else if (data.type().is()) { + const float value = data.get(real_index); std::stringstream ss; ss << std::fixed << std::setprecision(3) << value; const std::string value_str = ss.str(); @@ -143,8 +152,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); } - else if (cell_value.value_bool.has_value()) { - const bool value = *cell_value.value_bool; + else if (data.type().is()) { + const bool value = data.get(real_index); const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; uiBut *but = uiDefIconTextBut(params.block, UI_BTYPE_LABEL, @@ -163,87 +172,81 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { nullptr); UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); } - else if (cell_value.value_float2.has_value()) { - const float2 value = *cell_value.value_float2; + else if (data.type().is()) { + const float2 value = data.get(real_index); this->draw_float_vector(params, Span(&value.x, 2)); } - else if (cell_value.value_float3.has_value()) { - const float3 value = *cell_value.value_float3; + else if (data.type().is()) { + const float3 value = data.get(real_index); this->draw_float_vector(params, Span(&value.x, 3)); } - else if (cell_value.value_color.has_value()) { - const ColorGeometry4f value = *cell_value.value_color; + else if (data.type().is()) { + const ColorGeometry4f value = data.get(real_index); this->draw_float_vector(params, Span(&value.r, 4)); } - else if (cell_value.value_object.has_value()) { - const ObjectCellValue value = *cell_value.value_object; - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_OBJECT_DATA, - reinterpret_cast(value.object)->name + 2, - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - else if (cell_value.value_collection.has_value()) { - const CollectionCellValue value = *cell_value.value_collection; - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_OUTLINER_COLLECTION, - reinterpret_cast(value.collection)->name + 2, - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - else if (cell_value.value_geometry_set.has_value()) { - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_MESH_DATA, - "Geometry", - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - else if (cell_value.value_string.has_value()) { - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_NONE, - cell_value.value_string->c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); + else if (data.type().is()) { + const InstanceReference value = data.get(real_index); + switch (value.type()) { + case 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, + 0, + 0, + nullptr); + break; + } + case 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, + 0, + 0, + nullptr); + break; + } + case 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, + 0, + 0, + nullptr); + break; + } + case InstanceReference::Type::None: { + break; + } + } } } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh index 1768af6ae09..f996cd99dad 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh @@ -32,7 +32,7 @@ struct ColumnLayout { /* Layout information for the entire spreadsheet. */ struct SpreadsheetLayout { Vector columns; - Span row_indices; + IndexMask row_indices; int index_column_width = 100; }; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index 1e46fef8d71..a6a0266fcc1 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -18,7 +18,6 @@ #include "BLI_listbase.h" -#include "DNA_collection_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -38,238 +37,197 @@ namespace blender::ed::spreadsheet { -template -static void apply_filter_operation(const ColumnValues &values, +template +static void apply_filter_operation(const VArray &data, OperationFn check_fn, - MutableSpan rows_included) + const IndexMask mask, + Vector &new_indices) { - for (const int i : rows_included.index_range()) { - if (!rows_included[i]) { - continue; - } - CellValue cell_value; - values.get_value(i, cell_value); - if (!check_fn(cell_value)) { - rows_included[i] = false; + for (const int64_t i : mask) { + if (check_fn(data[i])) { + new_indices.append(i); } } } -static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout, - const SpreadsheetRowFilter &row_filter, - MutableSpan rows_included) +static void apply_row_filter(const SpreadsheetRowFilter &row_filter, + const Map &columns, + const IndexMask prev_mask, + Vector &new_indices) { - for (const ColumnLayout &column : spreadsheet_layout.columns) { - const ColumnValues &values = *column.values; - if (values.name() != row_filter.column_name) { - continue; + const ColumnValues &column = *columns.lookup(row_filter.column_name); + const fn::GVArray &column_data = column.data(); + if (column_data.type().is()) { + const float value = row_filter.value_float; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold = row_filter.threshold; + apply_filter_operation( + column_data.typed(), + [&](const float cell) { return std::abs(cell - value) < threshold; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed(), + [&](const float cell) { return cell > value; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed(), + [&](const float cell) { return cell < value; }, + prev_mask, + new_indices); + break; + } } - - switch (values.type()) { - case SPREADSHEET_VALUE_TYPE_INT32: { - const int value = row_filter.value_int; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_int == value; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_int > value; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_int < value; - }, - rows_included); - break; - } - } + } + else if (column_data.type().is()) { + const int value = row_filter.value_int; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + apply_filter_operation( + column_data.typed(), + [&](const int cell) { return cell == value; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_FLOAT: { - const float value = row_filter.value_float; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold = row_filter.threshold; - apply_filter_operation( - values, - [value, threshold](const CellValue &cell_value) -> bool { - return std::abs(*cell_value.value_float - value) < threshold; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_float > value; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_float < value; - }, - rows_included); - break; - } - } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed(), + [value](const int cell) { return cell > value; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_FLOAT2: { - const float2 value = row_filter.value_float2; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold_squared = row_filter.threshold * row_filter.threshold; - apply_filter_operation( - values, - [value, threshold_squared](const CellValue &cell_value) -> bool { - return float2::distance_squared(*cell_value.value_float2, value) < - threshold_squared; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float2->x > value.x && - cell_value.value_float2->y > value.y; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float2->x < value.x && - cell_value.value_float2->y < value.y; - }, - rows_included); - break; - } - } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed(), + [&](const int cell) { return cell < value; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_FLOAT3: { - const float3 value = row_filter.value_float3; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold_squared = row_filter.threshold * row_filter.threshold; - apply_filter_operation( - values, - [value, threshold_squared](const CellValue &cell_value) -> bool { - return float3::distance_squared(*cell_value.value_float3, value) < - threshold_squared; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float3->x > value.x && - cell_value.value_float3->y > value.y && - cell_value.value_float3->z > value.z; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float3->x < value.x && - cell_value.value_float3->y < value.y && - cell_value.value_float3->z < value.z; - }, - rows_included); - break; - } - } + } + } + else if (column_data.type().is()) { + const float2 value = row_filter.value_float2; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = row_filter.threshold; + apply_filter_operation( + column_data.typed(), + [&](const float2 cell) { + return float2::distance_squared(cell, value) > threshold_sq; + }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_COLOR: { - const ColorGeometry4f value = row_filter.value_color; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold_squared = row_filter.threshold * row_filter.threshold; - apply_filter_operation( - values, - [value, threshold_squared](const CellValue &cell_value) -> bool { - return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared; - }, - rows_included); - break; - } - } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed(), + [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_BOOL: { - const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0; + case SPREADSHEET_ROW_FILTER_LESS: { apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_bool == value; + column_data.typed(), + [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; }, + prev_mask, + new_indices); + break; + } + } + } + else if (column_data.type().is()) { + const float3 value = row_filter.value_float3; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = row_filter.threshold; + apply_filter_operation( + column_data.typed(), + [&](const float3 cell) { + return float3::distance_squared(cell, value) > threshold_sq; }, - rows_included); + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_INSTANCES: { - const StringRef value = row_filter.value_string; + case SPREADSHEET_ROW_FILTER_GREATER: { apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - const ID *id = nullptr; - if (cell_value.value_object) { - id = &cell_value.value_object->object->id; - } - else if (cell_value.value_collection) { - id = &cell_value.value_collection->collection->id; - } - if (id == nullptr) { - return false; - } - - return value == id->name + 2; + column_data.typed(), + [&](const float3 cell) { + return cell.x > value.x && cell.y > value.y && cell.z > value.z; }, - rows_included); + prev_mask, + new_indices); break; } - default: + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed(), + [&](const float3 cell) { + return cell.x < value.x && cell.y < value.y && cell.z < value.z; + }, + prev_mask, + new_indices); break; + } } - - /* Only one column should have this name. */ - break; } -} - -static void index_vector_from_bools(Span selection, Vector &indices) -{ - for (const int i : selection.index_range()) { - if (selection[i]) { - indices.append(i); + else if (column_data.type().is()) { + const ColorGeometry4f value = row_filter.value_color; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = row_filter.threshold; + apply_filter_operation( + column_data.typed(), + [&](const ColorGeometry4f cell) { + return len_squared_v4v4(cell, value) > threshold_sq; + }, + prev_mask, + new_indices); + break; + } + } + } + else if (column_data.type().is()) { + const StringRef value = row_filter.value_string; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + apply_filter_operation( + column_data.typed(), + [&](const InstanceReference cell) { + switch (cell.type()) { + case InstanceReference::Type::Object: { + return value == (reinterpret_cast(cell.object()).name + 2); + } + case InstanceReference::Type::Collection: { + return value == (reinterpret_cast(cell.collection()).name + 2); + } + case InstanceReference::Type::GeometrySet: { + return false; + } + case InstanceReference::Type::None: { + return false; + } + } + BLI_assert_unreachable(); + return false; + }, + prev_mask, + new_indices); + break; + } } } } @@ -297,10 +255,10 @@ static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet, return true; } -Span spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, - const SpreadsheetLayout &spreadsheet_layout, - const DataSource &data_source, - ResourceScope &scope) +IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, + const SpreadsheetLayout &spreadsheet_layout, + const DataSource &data_source, + ResourceScope &scope) { const int tot_rows = data_source.tot_rows(); @@ -309,29 +267,46 @@ Span spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, /* Avoid allocating an array if no row filtering is necessary. */ if (!(use_filters || use_selection)) { - return IndexRange(tot_rows).as_span(); + return IndexMask(tot_rows); } - Array rows_included(tot_rows, true); + IndexMask mask(tot_rows); + + Vector mask_indices; + mask_indices.reserve(tot_rows); + + if (use_selection) { + const GeometryDataSource *geometry_data_source = dynamic_cast( + &data_source); + mask = geometry_data_source->apply_selection_filter(mask_indices); + } if (use_filters) { + Map columns; + for (const ColumnLayout &column : spreadsheet_layout.columns) { + columns.add(column.values->name(), column.values); + } + LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) { if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) { - apply_row_filter(spreadsheet_layout, *row_filter, rows_included); + if (!columns.contains(row_filter->column_name)) { + continue; + } + Vector new_indices; + new_indices.reserve(mask_indices.size()); + apply_row_filter(*row_filter, columns, mask, new_indices); + std::swap(new_indices, mask_indices); + mask = IndexMask(mask_indices); } } } - if (use_selection) { - const GeometryDataSource *geometry_data_source = dynamic_cast( - &data_source); - geometry_data_source->apply_selection_filter(rows_included); + if (mask_indices.is_empty()) { + BLI_assert(mask.is_empty() || mask.is_range()); + return mask; } - Vector &indices = scope.construct>(); - index_vector_from_bools(rows_included, indices); - - return indices; + return IndexMask(scope.add_value(std::move(mask_indices))); } SpreadsheetRowFilter *spreadsheet_row_filter_new() diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh index 0a5783e318d..3788baaa993 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh @@ -23,10 +23,10 @@ namespace blender::ed::spreadsheet { -Span spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, - const SpreadsheetLayout &spreadsheet_layout, - const DataSource &data_source, - ResourceScope &scope); +IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, + const SpreadsheetLayout &spreadsheet_layout, + const DataSource &data_source, + ResourceScope &scope); SpreadsheetRowFilter *spreadsheet_row_filter_new(); SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index a07abac4474..bcced7b5937 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -114,6 +114,8 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, } case SPREADSHEET_VALUE_TYPE_STRING: return row_filter.value_string; + case SPREADSHEET_VALUE_TYPE_UNKNOWN: + return ""; } BLI_assert_unreachable(); return ""; @@ -238,6 +240,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); break; case SPREADSHEET_VALUE_TYPE_STRING: + uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE); + break; + case SPREADSHEET_VALUE_TYPE_UNKNOWN: + uiItemL(layout, IFACE_("Unkown column type"), ICON_ERROR); break; } } diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index 03e81b13714..fc8612d6f87 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -174,6 +174,11 @@ class GVArrayCommon { void get_internal_single_to_uninitialized(void *r_value) const; void get(const int64_t index, void *r_value) const; + /** + * Returns a copy of the value at the given index. Usually a typed virtual array should + * be used instead, but sometimes this is simpler when only a few indices are needed. + */ + template T get(const int64_t index) const; void get_to_uninitialized(const int64_t index, void *r_value) const; }; @@ -691,6 +696,16 @@ inline void GVArrayCommon::get(const int64_t index, void *r_value) const impl_->get(index, r_value); } +template inline T GVArrayCommon::get(const int64_t index) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + BLI_assert(this->type().is()); + T value{}; + impl_->get(index, &value); + return value; +} + /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const { diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 3ae7b3b68b8..a7a19be5b3e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -2006,6 +2006,7 @@ typedef enum eSpaceSpreadsheet_ContextType { } eSpaceSpreadsheet_ContextType; typedef enum eSpreadsheetColumnValueType { + SPREADSHEET_VALUE_TYPE_UNKNOWN = -1, SPREADSHEET_VALUE_TYPE_BOOL = 0, SPREADSHEET_VALUE_TYPE_INT32 = 1, SPREADSHEET_VALUE_TYPE_FLOAT = 2, -- cgit v1.2.3