diff options
author | Jacques Lucke <jacques@blender.org> | 2021-03-15 14:19:48 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-03-15 14:23:03 +0300 |
commit | 5ad4713cd8ed2943d96a020ba63ed4d611d14007 (patch) | |
tree | 7ef0da55a2c97f33422547608402795ae6df1212 /source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc | |
parent | 4ed208bcd82e912fa9a0da6137af6e87004e9365 (diff) |
Spreadsheet: improve separation of drawing and data generation
This is a refactor and no functional changes are expected.
The goal is to make it simpler to add other data sources without having
to repeat the drawing code everywhere. Also, having the `CellValue` class
allows us to implement filtering and sorting in a more generic way.
Diffstat (limited to 'source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc')
-rw-r--r-- | source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc | 289 |
1 files changed, 46 insertions, 243 deletions
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc index b60a1478352..0ba405d97e0 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc @@ -14,14 +14,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include <iomanip> -#include <sstream> - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "BLF_api.h" - #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" @@ -46,137 +38,6 @@ namespace blender::ed::spreadsheet { using blender::bke::ReadAttribute; using blender::bke::ReadAttributePtr; -class AttributeColumn { - public: - std::string name; - int width; - - AttributeColumn(std::string column_name) : name(std::move(column_name)) - { - /* Compute the column width based on its name. */ - const int fontid = UI_style_get()->widget.uifont_id; - const int header_name_padding = UI_UNIT_X; - const int minimum_column_width = 3 * UI_UNIT_X; - /* Use a consistent font size for the width calculation. */ - BLF_size(fontid, 11 * U.pixelsize, U.dpi); - const int text_width = BLF_width(fontid, name.data(), name.size()); - width = std::max(text_width + header_name_padding, minimum_column_width); - } - - virtual ~AttributeColumn() = default; - virtual void draw(const int index, const CellDrawParams ¶ms) const = 0; -}; - -class GeometryAttributeSpreadsheetDrawer : public SpreadsheetDrawer { - private: - /* Contains resources that are used during drawing. They will be freed automatically. */ - std::unique_ptr<ResourceCollector> resources_; - /* Information about how to draw the individual columns. */ - Vector<std::unique_ptr<AttributeColumn>> columns_; - /* This is used to filter the selected rows. The referenced data lives at least as long as the - * resource collector above. */ - Span<int64_t> visible_rows_; - - public: - GeometryAttributeSpreadsheetDrawer(std::unique_ptr<ResourceCollector> resources, - Vector<std::unique_ptr<AttributeColumn>> columns, - Span<int64_t> visible_rows, - const int domain_size) - : resources_(std::move(resources)), columns_(std::move(columns)), visible_rows_(visible_rows) - { - tot_columns = columns_.size(); - tot_rows = visible_rows.size(); - - /* Compute index column width based on number of digits. */ - const int fontid = UI_style_get()->widget.uifont_id; - left_column_width = std::to_string(std::max(domain_size - 1, 0)).size() * - BLF_width(fontid, "0", 1) + - UI_UNIT_X * 0.75; - } - - void draw_top_row_cell(int column_index, const CellDrawParams ¶ms) const final - { - uiBut *but = uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_NONE, - columns_[column_index]->name.c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - /* Center-align column headers. */ - UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); - UI_but_drawflag_disable(but, UI_BUT_TEXT_RIGHT); - } - - void draw_left_column_cell(int row_index, const CellDrawParams ¶ms) const final - { - const int real_index = visible_rows_[row_index]; - std::string index_str = std::to_string(real_index); - uiBut *but = uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_NONE, - index_str.c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - /* Right-align indices. */ - UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); - UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); - } - - void draw_content_cell(int row_index, int column_index, const CellDrawParams ¶ms) const final - { - const int real_index = visible_rows_[row_index]; - columns_[column_index]->draw(real_index, params); - } - - int column_width(int column_index) const final - { - return columns_[column_index]->width; - } -}; - -/* Utility to make writing column drawing code more concise. */ -template<typename DrawF> class CustomAttributeColumn : public AttributeColumn { - private: - DrawF draw_; - - public: - CustomAttributeColumn(std::string attribute_name, DrawF draw) - : AttributeColumn(std::move(attribute_name)), draw_(std::move(draw)) - { - } - - void draw(const int index, const CellDrawParams ¶ms) const final - { - draw_(index, params); - } -}; - -template<typename DrawF> -std::unique_ptr<CustomAttributeColumn<DrawF>> create_attribute_column(std::string attribute_name, - DrawF draw) -{ - return std::make_unique<CustomAttributeColumn<DrawF>>(std::move(attribute_name), - std::move(draw)); -} - static Vector<std::string> get_sorted_attribute_names_to_display( const GeometryComponent &component, const AttributeDomain domain) { @@ -196,92 +57,30 @@ static Vector<std::string> get_sorted_attribute_names_to_display( return attribute_names; } -static void draw_float_in_cell(const CellDrawParams ¶ms, const float value) -{ - std::stringstream ss; - ss << std::fixed << std::setprecision(3) << value; - const std::string value_str = ss.str(); - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_NONE, - value_str.c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); -} - -static void draw_int_in_cell(const CellDrawParams ¶ms, const int value) -{ - const std::string value_str = std::to_string(value); - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_NONE, - value_str.c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); -} - -static void draw_bool_in_cell(const CellDrawParams ¶ms, const bool value) -{ - const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - icon, - "", - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); -} - static void add_columns_for_attribute(const ReadAttribute *attribute, const StringRefNull attribute_name, - Vector<std::unique_ptr<AttributeColumn>> &columns) + Vector<std::unique_ptr<SpreadsheetColumn>> &columns) { const CustomDataType data_type = attribute->custom_data_type(); switch (data_type) { case CD_PROP_FLOAT: { - columns.append(create_attribute_column(attribute_name, - [attribute](int index, const CellDrawParams ¶ms) { - float value; - attribute->get(index, &value); - draw_float_in_cell(params, value); - })); + columns.append(spreadsheet_column_from_function( + attribute_name, [attribute](int index, CellValue &r_cell_value) { + float value; + attribute->get(index, &value); + r_cell_value.value = value; + })); break; } case CD_PROP_FLOAT2: { static std::array<char, 2> axis_char = {'X', 'Y'}; for (const int i : {0, 1}) { std::string name = attribute_name + " " + axis_char[i]; - columns.append( - create_attribute_column(name, [attribute, i](int index, const CellDrawParams ¶ms) { + columns.append(spreadsheet_column_from_function( + name, [attribute, i](int index, CellValue &r_cell_value) { float2 value; attribute->get(index, &value); - draw_float_in_cell(params, value[i]); + r_cell_value.value = value[i]; })); } break; @@ -290,11 +89,11 @@ static void add_columns_for_attribute(const ReadAttribute *attribute, static std::array<char, 3> axis_char = {'X', 'Y', 'Z'}; for (const int i : {0, 1, 2}) { std::string name = attribute_name + " " + axis_char[i]; - columns.append( - create_attribute_column(name, [attribute, i](int index, const CellDrawParams ¶ms) { + columns.append(spreadsheet_column_from_function( + name, [attribute, i](int index, CellValue &r_cell_value) { float3 value; attribute->get(index, &value); - draw_float_in_cell(params, value[i]); + r_cell_value.value = value[i]; })); } break; @@ -303,31 +102,31 @@ static void add_columns_for_attribute(const ReadAttribute *attribute, static std::array<char, 4> axis_char = {'R', 'G', 'B', 'A'}; for (const int i : {0, 1, 2, 3}) { std::string name = attribute_name + " " + axis_char[i]; - columns.append( - create_attribute_column(name, [attribute, i](int index, const CellDrawParams ¶ms) { + columns.append(spreadsheet_column_from_function( + name, [attribute, i](int index, CellValue &r_cell_value) { Color4f value; attribute->get(index, &value); - draw_float_in_cell(params, value[i]); + r_cell_value.value = value[i]; })); } break; } case CD_PROP_INT32: { - columns.append(create_attribute_column(attribute_name, - [attribute](int index, const CellDrawParams ¶ms) { - int value; - attribute->get(index, &value); - draw_int_in_cell(params, value); - })); + columns.append(spreadsheet_column_from_function( + attribute_name, [attribute](int index, CellValue &r_cell_value) { + int value; + attribute->get(index, &value); + r_cell_value.value = value; + })); break; } case CD_PROP_BOOL: { - columns.append(create_attribute_column(attribute_name, - [attribute](int index, const CellDrawParams ¶ms) { - bool value; - attribute->get(index, &value); - draw_bool_in_cell(params, value); - })); + columns.append(spreadsheet_column_from_function( + attribute_name, [attribute](int index, CellValue &r_cell_value) { + bool value; + attribute->get(index, &value); + r_cell_value.value = value; + })); break; } default: @@ -526,52 +325,56 @@ static GeometryComponentType get_display_component_type(const bContext *C, Objec return GEO_COMPONENT_TYPE_MESH; } -std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_geometry_attributes(const bContext *C, - Object *object_eval) +void spreadsheet_columns_from_geometry(const bContext *C, + Object *object_eval, + SpreadsheetColumnLayout &column_layout, + ResourceCollector &resources) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const GeometryComponentType component_type = get_display_component_type(C, object_eval); /* Create a resource collector that owns stuff that needs to live until drawing is done. */ - std::unique_ptr<ResourceCollector> resources = std::make_unique<ResourceCollector>(); - GeometrySet &geometry_set = resources->add_value( + GeometrySet &geometry_set = resources.add_value( get_display_geometry_set(sspreadsheet, object_eval, component_type), "geometry set"); const GeometryComponent *component = geometry_set.get_component_for_read(component_type); if (component == nullptr) { - return {}; + return; } if (!component->attribute_domain_supported(domain)) { - return {}; + return; } Vector<std::string> attribute_names = get_sorted_attribute_names_to_display(*component, domain); - Vector<std::unique_ptr<AttributeColumn>> columns; + Vector<std::unique_ptr<SpreadsheetColumn>> &columns = + resources.construct<Vector<std::unique_ptr<SpreadsheetColumn>>>("columns"); + for (StringRefNull attribute_name : attribute_names) { ReadAttributePtr attribute_ptr = component->attribute_try_get_for_read(attribute_name); ReadAttribute &attribute = *attribute_ptr; - resources->add(std::move(attribute_ptr), "attribute"); + resources.add(std::move(attribute_ptr), "attribute"); add_columns_for_attribute(&attribute, attribute_name, columns); } + for (std::unique_ptr<SpreadsheetColumn> &column : columns) { + column_layout.columns.append(column.get()); + } + /* The filter below only works for mesh vertices currently. */ Span<int64_t> visible_rows; if (component_type == GEO_COMPONENT_TYPE_MESH) { visible_rows = filter_mesh_elements_by_selection( - C, object_eval, static_cast<const MeshComponent *>(component), domain, *resources); + C, object_eval, static_cast<const MeshComponent *>(component), domain, resources); } else { visible_rows = IndexRange(component->attribute_domain_size(domain)).as_span(); } const int domain_size = component->attribute_domain_size(domain); - sspreadsheet->runtime->tot_rows = domain_size; - sspreadsheet->runtime->visible_rows = visible_rows.size(); - sspreadsheet->runtime->tot_columns = columns.size(); - return std::make_unique<GeometryAttributeSpreadsheetDrawer>( - std::move(resources), std::move(columns), visible_rows, domain_size); + column_layout.row_indices = visible_rows; + column_layout.tot_rows = domain_size; } } // namespace blender::ed::spreadsheet |