From 66a5469bcfc22d2e1d41bb9477aef053fb89fcfe Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 26 May 2025 19:16:20 +0200 Subject: [PATCH] Spreadsheet: support restoring temporarily unavailable data columns Previously, columns were removed from a table in the spreadsheet if they are not available anymore. This also meant that their position and width was lost. When the same column became available again, it was inserted at the end. This patch makes it so that each table also remembers the columns that are not available currently (and flags them accordingly). This way, the position and width can be restored once the data becomes available again. Pull Request: https://projects.blender.org/blender/blender/pulls/139440 --- .../space_spreadsheet/space_spreadsheet.cc | 17 +++++------ .../space_spreadsheet/spreadsheet_ops.cc | 30 +++++++++++++++++-- source/blender/makesdna/DNA_space_enums.h | 9 ++++++ source/blender/makesdna/DNA_space_types.h | 4 ++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index d57709d1351..b6b6464806c 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -384,15 +384,11 @@ static void update_visible_columns(SpreadsheetTable &table, DataSource &data_sou Set> handled_columns; Vector new_columns; for (SpreadsheetColumn *column : Span{table.columns, table.num_columns}) { - const bool still_exists = data_source.get_column_values(*column->id) != nullptr; - if (still_exists) { - if (handled_columns.add(*column->id)) { - new_columns.append(column); - continue; - } + if (handled_columns.add(*column->id)) { + const bool has_data = data_source.get_column_values(*column->id) != nullptr; + SET_FLAG_FROM_TEST(column->flag, !has_data, SPREADSHEET_COLUMN_FLAG_UNAVAILABLE); + new_columns.append(column); } - /* Free columns that don't exist anymore or are duplicates for some reason. */ - spreadsheet_column_free(column); } data_source.foreach_default_column_ids( @@ -468,8 +464,9 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region) for (SpreadsheetColumn *column : Span{table->columns, table->num_columns}) { std::unique_ptr values_ptr = data_source->get_column_values(*column->id); - /* Should have been removed before if it does not exist anymore. */ - BLI_assert(values_ptr); + if (!values_ptr) { + continue; + } const ColumnValues *values = scope.add(std::move(values_ptr)); if (column->width <= 0.0f) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc index 8ab019449bd..2ed6e4c2e25 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc @@ -196,6 +196,9 @@ SpreadsheetColumn *find_hovered_column_edge(SpaceSpreadsheet &sspreadsheet, } const float cursor_x_view = UI_view2d_region_to_view_x(®ion.v2d, cursor_re.x); for (SpreadsheetColumn *column : Span{table->columns, table->num_columns}) { + if (column->flag & SPREADSHEET_COLUMN_FLAG_UNAVAILABLE) { + continue; + } if (std::abs(cursor_x_view - column->runtime->right_x) < SPREADSHEET_EDGE_ACTION_ZONE) { return column; } @@ -213,6 +216,9 @@ SpreadsheetColumn *find_hovered_column(SpaceSpreadsheet &sspreadsheet, } const float cursor_x_view = UI_view2d_region_to_view_x(®ion.v2d, cursor_re.x); for (SpreadsheetColumn *column : Span{table->columns, table->num_columns}) { + if (column->flag & SPREADSHEET_COLUMN_FLAG_UNAVAILABLE) { + continue; + } if (cursor_x_view > column->runtime->left_x && cursor_x_view <= column->runtime->right_x) { return column; } @@ -321,6 +327,26 @@ struct ReorderColumnData { View2DEdgePanData pan_data{}; }; +static std::optional find_first_available_column_index(const SpreadsheetTable &table) +{ + for (int i = 0; i < table.num_columns; i++) { + if (!(table.columns[i]->flag & SPREADSHEET_COLUMN_FLAG_UNAVAILABLE)) { + return i; + } + } + return std::nullopt; +} + +static std::optional find_last_available_column_index(const SpreadsheetTable &table) +{ + for (int i = table.num_columns - 1; i >= 0; i--) { + if (!(table.columns[i]->flag & SPREADSHEET_COLUMN_FLAG_UNAVAILABLE)) { + return i; + } + } + return std::nullopt; +} + static wmOperatorStatus reorder_columns_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceSpreadsheet &sspreadsheet = *CTX_wm_space_spreadsheet(C); @@ -384,10 +410,10 @@ static wmOperatorStatus reorder_columns_modal(bContext *C, wmOperator *op, const } else { if (cursor_re.x > sspreadsheet.runtime->left_column_width) { - new_index = columns.size() - 1; + new_index = *find_last_available_column_index(table); } else { - new_index = 0; + new_index = *find_first_available_column_index(table); } } diff --git a/source/blender/makesdna/DNA_space_enums.h b/source/blender/makesdna/DNA_space_enums.h index 13befddb5d5..4f4c007002a 100644 --- a/source/blender/makesdna/DNA_space_enums.h +++ b/source/blender/makesdna/DNA_space_enums.h @@ -1019,6 +1019,15 @@ typedef enum eSpreadsheetColumnValueType { SPREADSHEET_VALUE_TYPE_FLOAT4X4 = 12, } eSpreadsheetColumnValueType; +typedef enum eSpreadsheetColumnFlag { + /** + * There is no data for this column currently, so it's not displayed. However, it is still kept + * around so that the column remembers its position and width when the data becomes available + * again. + */ + SPREADSHEET_COLUMN_FLAG_UNAVAILABLE = (1 << 0), +} eSpreadsheetColumnFlag; + typedef enum eSpreadsheetTableIDType { /** This table uses the #SpreadsheetTableIDGeometry key. */ SPREADSHEET_TABLE_ID_TYPE_GEOMETRY = 0, diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 37fc65d1eb1..8645d1f2f72 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1091,7 +1091,9 @@ typedef struct SpreadsheetColumn { * #eSpreadsheetColumnValueType. */ uint8_t data_type; - char _pad0[3]; + char _pad0[1]; + /** #eSpreadsheetColumnFlag. */ + uint16_t flag; /** Width in SPREADSHEET_WIDTH_UNIT. */ float width;