The main goal of this patch is that the column widths and ordering is not reset every time one switches between different contexts. It does that by keeping track of multiple `SpreadsheetTable`. There is one for each table that is viewed (so e.g. the point and edge domain of the same mesh are two different tables). Each table has an identifier and an array of columns. There is some garbage collection in place so that the number of stored tables does not increase unbounded. This also comes with an updated Python API: ```python import bpy spreadsheet = bpy.context.screen.areas[...].spaces.active active_table = spreadsheet.tables.active print(active_table.id.type) print(active_table.id.attribute_domain) print(active_table.columns[0].id.name) ``` In the future, we might add some smarter logic to keep tables with different identifiers more in sync. We don't have a great heuristic for that yet. Pull Request: https://projects.blender.org/blender/blender/pulls/139205
128 lines
3.6 KiB
C++
128 lines
3.6 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup DNA
|
|
*
|
|
* Contains functions that help dealing with arrays that are stored in DNA. Due to the constraints
|
|
* of DNA, all structs are trivial from the language's point of view (`std::is_trivial_v`).
|
|
* However, semantically, these types may have non-trivial copy-constructors and destructors.
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_function_ref.hh"
|
|
#include "BLI_index_range.hh"
|
|
#include "BLI_utildefines.h"
|
|
|
|
namespace blender::dna::array {
|
|
|
|
/**
|
|
* Removes an element from the array and shifts the elements after it towards the front.
|
|
*/
|
|
template<typename T>
|
|
inline void remove_index(
|
|
T **items, int *items_num, int *active_index, const int index, void (*destruct_item)(T *))
|
|
{
|
|
static_assert(std::is_trivial_v<T>);
|
|
BLI_assert(index >= 0);
|
|
BLI_assert(index < *items_num);
|
|
|
|
const int old_items_num = *items_num;
|
|
const int new_items_num = old_items_num - 1;
|
|
|
|
T *old_items = *items;
|
|
T *new_items = MEM_calloc_arrayN<T>(new_items_num, __func__);
|
|
|
|
std::copy_n(old_items, index, new_items);
|
|
std::copy_n(old_items + index + 1, old_items_num - index - 1, new_items + index);
|
|
|
|
destruct_item(&old_items[index]);
|
|
MEM_freeN(old_items);
|
|
|
|
*items = new_items;
|
|
*items_num = new_items_num;
|
|
|
|
if (active_index) {
|
|
const int old_active_index = active_index ? *active_index : 0;
|
|
const int new_active_index = std::max(
|
|
0, old_active_index == new_items_num ? new_items_num - 1 : old_active_index);
|
|
*active_index = new_active_index;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all elements for which the predicate is true. The remaining ones stay in the order they
|
|
* were in before.
|
|
*/
|
|
template<typename T>
|
|
inline void remove_if(T **items,
|
|
int *items_num,
|
|
FunctionRef<bool(const T &)> predicate,
|
|
void (*destruct_item)(T *))
|
|
{
|
|
static_assert(std::is_trivial_v<T>);
|
|
/* This sorts the items-to-remove to the back. */
|
|
const int remaining = std::partition(*items,
|
|
*items + *items_num,
|
|
[&](const T &value) { return !predicate(value); }) -
|
|
*items;
|
|
for (const int i : IndexRange::from_begin_end(remaining, *items_num)) {
|
|
destruct_item(&(*items)[i]);
|
|
}
|
|
*items_num = remaining;
|
|
}
|
|
|
|
/**
|
|
* Removes all elements from an array and frees it.
|
|
*/
|
|
template<typename T>
|
|
inline void clear(T **items, int *items_num, int *active_index, void (*destruct_item)(T *))
|
|
{
|
|
static_assert(std::is_trivial_v<T>);
|
|
for (const int i : IndexRange(*items_num)) {
|
|
destruct_item(&(*items)[i]);
|
|
}
|
|
MEM_SAFE_FREE(*items);
|
|
*items_num = 0;
|
|
if (active_index) {
|
|
*active_index = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Moves one element from one index to another, moving other elements if necessary.
|
|
*/
|
|
template<typename T>
|
|
inline void move_index(T *items, const int items_num, const int from_index, const int to_index)
|
|
{
|
|
static_assert(std::is_trivial_v<T>);
|
|
BLI_assert(from_index >= 0);
|
|
BLI_assert(from_index < items_num);
|
|
BLI_assert(to_index >= 0);
|
|
BLI_assert(to_index < items_num);
|
|
UNUSED_VARS_NDEBUG(items_num);
|
|
|
|
if (from_index == to_index) {
|
|
return;
|
|
}
|
|
|
|
if (from_index < to_index) {
|
|
const T tmp = items[from_index];
|
|
for (int i = from_index; i < to_index; i++) {
|
|
items[i] = items[i + 1];
|
|
}
|
|
items[to_index] = tmp;
|
|
}
|
|
else if (from_index > to_index) {
|
|
const T tmp = items[from_index];
|
|
for (int i = from_index; i > to_index; i--) {
|
|
items[i] = items[i - 1];
|
|
}
|
|
items[to_index] = tmp;
|
|
}
|
|
}
|
|
|
|
} // namespace blender::dna::array
|