diff options
author | Jacques Lucke <jacques@blender.org> | 2021-04-09 11:20:46 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-04-09 11:20:46 +0300 |
commit | 75491fe1002122f19fc9fe8eae941a406b81706a (patch) | |
tree | 16a05f5b5ccc7087595ce27656aaa60a5f5c118a /source/blender/editors/space_spreadsheet/space_spreadsheet.cc | |
parent | 22574f741c4e4d142c7068316296d24bbfc2a12c (diff) |
Spreadsheet: persistent column storage and data source
A `DataSource` provides columns for the spreadsheet to display.
Every column has a SpreadsheetColumnID as identifier. Columns
are not generated eagerly anymore, instead the main spreadsheet
code can request a column from a data source with an column
identifier. The column identifiers can be stored in DNA and allow us
to store persistent data per column.
On the user level the only thing that changes is that columns are
not shown in alphabetical order anymore. Instead, new columns
are always added on the left. The behavior can be changed,
however I'd prefer not to automate this too much currently. I think
we should just add operators to hide/reorder/resize columns soonish.
Differential Revision: https://developer.blender.org/D10901
Diffstat (limited to 'source/blender/editors/space_spreadsheet/space_spreadsheet.cc')
-rw-r--r-- | source/blender/editors/space_spreadsheet/space_spreadsheet.cc | 133 |
1 files changed, 112 insertions, 21 deletions
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 403e6cd6206..d34b625293c 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -17,7 +17,6 @@ #include <cstring> #include "BLI_listbase.h" -#include "BLI_resource_scope.hh" #include "BKE_screen.h" @@ -41,12 +40,15 @@ #include "WM_api.h" #include "WM_types.h" +#include "BLF_api.h" + #include "spreadsheet_intern.hh" -#include "spreadsheet_column_layout.hh" -#include "spreadsheet_from_geometry.hh" +#include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_intern.hh" +#include "spreadsheet_layout.hh" +using namespace blender; using namespace blender::ed::spreadsheet; static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) @@ -85,6 +87,10 @@ static void spreadsheet_free(SpaceLink *sl) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; MEM_SAFE_FREE(sspreadsheet->runtime); + + LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) { + spreadsheet_column_free(column); + } } static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area) @@ -94,6 +100,10 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area) sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN( sizeof(SpaceSpreadsheet_Runtime), __func__); } + LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) { + spreadsheet_column_free(column); + } + BLI_listbase_clear(&sspreadsheet->columns); } static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) @@ -102,6 +112,12 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old); sspreadsheet_new->runtime = (SpaceSpreadsheet_Runtime *)MEM_dupallocN(sspreadsheet_old->runtime); + BLI_listbase_clear(&sspreadsheet_new->columns); + LISTBASE_FOREACH (SpreadsheetColumn *, src_column, &sspreadsheet_old->columns) { + SpreadsheetColumn *new_column = spreadsheet_column_copy(src_column); + BLI_addtail(&sspreadsheet_new->columns, new_column); + } + return (SpaceLink *)sspreadsheet_new; } @@ -133,47 +149,122 @@ static ID *get_used_id(const bContext *C) return (ID *)active_object; } -class FallbackSpreadsheetDrawer : public SpreadsheetDrawer { -}; - -static void gather_spreadsheet_columns(const bContext *C, - SpreadsheetColumnLayout &column_layout, - blender::ResourceScope &scope) +static std::unique_ptr<DataSource> get_data_source(const bContext *C) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); ID *used_id = get_used_id(C); if (used_id == nullptr) { - return; + return {}; } const ID_Type id_type = GS(used_id->name); if (id_type != ID_OB) { - return; + return {}; } Object *object_orig = (Object *)used_id; if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD)) { - return; + return {}; } Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig); if (object_eval == nullptr) { - return; + return {}; } - return spreadsheet_columns_from_geometry(C, object_eval, column_layout, scope); + return data_source_from_geometry(C, object_eval); +} + +static float get_column_width(const ColumnValues &values) +{ + if (values.default_width > 0) { + return values.default_width * UI_UNIT_X; + } + const int fontid = UI_style_get()->widget.uifont_id; + const int widget_points = UI_style_get_dpi()->widget.points; + BLF_size(fontid, widget_points * U.pixelsize, U.dpi); + const StringRefNull name = values.name(); + const float name_width = BLF_width(fontid, name.data(), name.size()); + return std::max<float>(name_width + UI_UNIT_X, 3 * UI_UNIT_X); +} + +static int get_index_column_width(const int tot_rows) +{ + const int fontid = UI_style_get()->widget.uifont_id; + BLF_size(fontid, UI_style_get_dpi()->widget.points * U.pixelsize, U.dpi); + return std::to_string(std::max(0, tot_rows - 1)).size() * BLF_width(fontid, "0", 1) + + UI_UNIT_X * 0.75; +} + +static void update_visible_columns(ListBase &columns, DataSource &data_source) +{ + Set<SpreadsheetColumnID> used_ids; + LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &columns) { + std::unique_ptr<ColumnValues> values = data_source.get_column_values(*column->id); + /* Remove columns that don't exist anymore. */ + if (!values) { + BLI_remlink(&columns, column); + spreadsheet_column_free(column); + continue; + } + + used_ids.add(*column->id); + } + + data_source.foreach_default_column_ids([&](const SpreadsheetColumnID &column_id) { + std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id); + if (values) { + if (used_ids.add(column_id)) { + SpreadsheetColumnID *new_id = spreadsheet_column_id_copy(&column_id); + SpreadsheetColumn *new_column = spreadsheet_column_new(new_id); + BLI_addtail(&columns, new_column); + } + } + }); } static void spreadsheet_main_region_draw(const bContext *C, ARegion *region) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - blender::ResourceScope scope; - SpreadsheetColumnLayout column_layout; - gather_spreadsheet_columns(C, column_layout, scope); + std::unique_ptr<DataSource> data_source = get_data_source(C); + if (!data_source) { + data_source = std::make_unique<DataSource>(); + } + + update_visible_columns(sspreadsheet->columns, *data_source); + + SpreadsheetLayout spreadsheet_layout; + ResourceScope scope; + + LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) { + std::unique_ptr<ColumnValues> values_ptr = data_source->get_column_values(*column->id); + /* Should have been removed before if it does not exist anymore. */ + BLI_assert(values_ptr); + const ColumnValues *values = scope.add(std::move(values_ptr), __func__); + const int width = get_column_width(*values); + spreadsheet_layout.columns.append({values, width}); + } + + const int tot_rows = data_source->tot_rows(); + spreadsheet_layout.index_column_width = get_index_column_width(tot_rows); + spreadsheet_layout.row_indices = IndexRange(tot_rows).as_span(); + + if (const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>( + data_source.get())) { + Object *object_eval = geometry_data_source->object_eval(); + Object *object_orig = DEG_get_original_object(object_eval); + if (object_orig->type == OB_MESH) { + if (object_orig->mode == OB_MODE_EDIT) { + if (sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY) { + spreadsheet_layout.row_indices = geometry_data_source->get_selected_element_indices(); + } + } + } + } - sspreadsheet->runtime->visible_rows = column_layout.row_indices.size(); - sspreadsheet->runtime->tot_columns = column_layout.columns.size(); - sspreadsheet->runtime->tot_rows = column_layout.tot_rows; + sspreadsheet->runtime->tot_columns = spreadsheet_layout.columns.size(); + sspreadsheet->runtime->tot_rows = tot_rows; + sspreadsheet->runtime->visible_rows = spreadsheet_layout.row_indices.size(); - std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_column_layout(column_layout); + std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_layout(spreadsheet_layout); draw_spreadsheet_in_region(C, region, *drawer); /* Tag footer for redraw, because the main region updates data for the footer. */ |