1
1

Compare commits

...

40 Commits

Author SHA1 Message Date
1fbdf19ee2 Remove "Last Data Type" hack 2021-06-15 22:12:50 -05:00
5355e9e603 Move "Selection Only" to the editor header 2021-06-15 21:56:56 -05:00
f1ebcfeef9 Gray out row filters if the flag is turned off 2021-06-15 21:41:55 -05:00
6fe76f602f Merge branch 'master' into temp-spreadsheet-row-filter 2021-06-15 21:41:16 -05:00
f5dee9b7a5 Split selection filter and row filters (filter flag no longer applies to selection filter) 2021-06-15 21:10:30 -05:00
f5f58882ef Merge branch 'master' into temp-spreadsheet-row-filter 2021-06-15 16:43:08 -05:00
72198d508a Merge branch 'master' into temp-spreadsheet-row-filter 2021-06-14 15:14:47 -05:00
3f4f28082f Fix build error after merging master 2021-06-04 08:17:41 -04:00
92ce1c8367 Merge branch 'master' into temp-spreadsheet-row-filter 2021-06-04 08:12:20 -04:00
7680d4fc6a Add support for float2, float3, color, and instance columns 2021-05-18 13:14:08 -04:00
8d7866f4b3 Merge branch 'master' into temp-spreadsheet-row-filter 2021-05-18 11:20:48 -04:00
c9c88b9626 Use "Spreadsheet" instead of "SpreadSheet" 2021-04-22 08:56:22 -05:00
deff5f1cd0 Remove unecessary comment 2021-04-22 08:56:10 -05:00
bdcdc973a7 Fix memory leak 2021-04-22 08:56:01 -05:00
ec96577057 Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-22 08:54:35 -05:00
a79288785c Remove commented code / always display "Only Selected" option 2021-04-19 16:49:31 -05:00
7612308189 Sort RNA definition automatically 2021-04-19 16:47:02 -05:00
f80bd477ac Don't mark unreachable code incorrectly 2021-04-19 16:46:53 -05:00
582928f081 Give operators more specific names 2021-04-19 16:46:26 -05:00
1d8983c549 Use StringRefNull 2021-04-19 16:39:23 -05:00
6c1ef12e80 Move assigning column runtime data to the main draw function 2021-04-19 16:38:21 -05:00
94cc56b450 Remove "T" keymap item 2021-04-19 16:36:11 -05:00
5877465c20 Don't gray out filter panels when their string is empty 2021-04-19 16:33:40 -05:00
9094e3cd77 Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-19 16:28:15 -05:00
c62d1b5476 Remember the last data type when a column is no longer visible 2021-04-16 12:49:37 -05:00
8919c68adb Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-16 11:57:39 -05:00
5e5242dbc9 Compare display names instead of the column ID 2021-04-14 12:50:18 -05:00
1b31d7bf47 Use nullptr instead of NULL 2021-04-14 11:32:26 -05:00
9f2b978617 Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-14 11:25:52 -05:00
b770c9ed40 Cleanup: Whitespace and unused includes 2021-04-13 21:41:22 -05:00
d0fd407985 New implementation of the UI in a sidebar
Includes panels and drag and drop
2021-04-13 21:33:18 -05:00
f3b85c2e6c Address small review comments from Jacques 2021-04-13 12:00:06 -05:00
7fe14a43b9 Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-13 11:52:15 -05:00
5da0baff4e Reorder enum definitions 2021-04-12 15:21:08 -05:00
95740e1153 Small cleanups 2021-04-12 15:19:10 -05:00
92aa3e75a6 Spreadsheet Editor: Row filters
{F9930989 size=full}

This patch adds support for filtering out rows based on rules and values.
Filters will work for any attribute data source, they are a property of
the spreadsheet rather than of the attribute system.

**Further Questions**
* The popover is a test, it would be easy to move this to a sidebar, but I wanted to see
  what people thought about the popover.
* `SpreadSheetColumn` does not know about the " X" suffixes that are added to vector columns.
  This means the row filter cannot determine the correct data type for vector columns.
  Luckily the default of float works, but I'm not sure how to handle this properly.

Differential Revision: https://developer.blender.org/D10959
2021-04-12 15:12:28 -05:00
4a6c00a9eb Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-12 09:07:05 -05:00
47ed4da9e9 Geometry Nodes: Working spreadsheet row filtering
Now there is only some UI work left
2021-04-09 18:03:19 -05:00
c4b1dd175d Merge branch 'master' into temp-spreadsheet-row-filter 2021-04-09 11:41:00 -05:00
d09deb3147 Implement basic UI and structures for row filters 2021-03-30 16:55:02 -05:00
24 changed files with 1349 additions and 76 deletions

View File

@@ -3010,6 +3010,22 @@ def km_clip_dopesheet_editor(_params):
return keymap
def km_spreadsheet_generic(_params):
items = []
keymap = (
"Spreadsheet Generic",
{"space_type": 'SPREADSHEET', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
*_template_space_region_type_toggle(
sidebar_key={"type": 'N', "value": 'PRESS'},
),
])
return keymap
# ------------------------------------------------------------------------------
# Animation
@@ -7067,6 +7083,7 @@ def generate_keymaps(params=None):
km_image(params),
km_node_generic(params),
km_node_editor(params),
km_spreadsheet_generic(params),
km_info(params),
km_file_browser(params),
km_file_browser_main(params),

View File

@@ -2144,6 +2144,23 @@ def km_clip_dopesheet_editor(_params):
return keymap
def km_spreadsheet_generic(_params):
items = []
keymap = (
"Spreadsheet Generic",
{"space_type": 'SPREADSHEET', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
*_template_space_region_type_toggle(
sidebar_key={"type": 'N', "value": 'PRESS'},
),
])
return keymap
# ------------------------------------------------------------------------------
# Animation
@@ -4067,6 +4084,7 @@ def generate_keymaps_impl(params=None):
km_image(params),
km_node_generic(params),
km_node_editor(params),
km_spreadsheet_generic(params),
km_info(params),
km_file_browser(params),
km_file_browser_main(params),

View File

@@ -59,9 +59,12 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False)
layout.separator_spacer()
if isinstance(obj, bpy.types.Object) and obj.mode == 'EDIT':
layout.prop(space, "show_only_selected", text="Selected Only")
row = layout.row(align=True)
sub = row.row(align=True)
sub.active = self.selection_filter_enabled(space)
sub.prop(space, "show_only_selected", text="")
row.prop(space, "use_filter", toggle=True, icon='FILTER', icon_only=True)
def draw_without_context_path(self, layout):
layout.label(text="No active context")
@@ -102,6 +105,17 @@ class SPREADSHEET_HT_header(bpy.types.Header):
def draw_spreadsheet_context_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
layout.prop(space, "display_context_path_collapsed", icon_only=True, emboss=False, icon=icon)
def selection_filter_enabled(self, space):
root_context = space.context_path[0]
if root_context.type != 'OBJECT':
return False
obj = root_context.object
if obj is None:
return False
if obj.type != 'MESH' or obj.mode != 'EDIT':
return False
return True
classes = (
SPREADSHEET_HT_header,
)

View File

@@ -1357,12 +1357,20 @@ static void write_area(BlendWriter *writer, ScrArea *area)
}
else if (sl->spacetype == SPACE_SPREADSHEET) {
BLO_write_struct(writer, SpaceSpreadsheet, sl);
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
BLO_write_struct(writer, SpreadsheetRowFilter, row_filter);
BLO_write_string(writer, row_filter->value_string);
}
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
BLO_write_struct(writer, SpreadsheetColumn, column);
BLO_write_struct(writer, SpreadsheetColumnID, column->id);
BLO_write_string(writer, column->id->name);
/* While the display name is technically runtime data, we write it here, otherwise the row
* filters might not now their type if their region draws before the main region. */
BLO_write_string(writer, column->display_name);
}
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
switch (context->type) {
@@ -1743,11 +1751,17 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
sspreadsheet->runtime = NULL;
BLO_read_list(reader, &sspreadsheet->row_filters);
LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
BLO_read_data_address(reader, &row_filter->value_string);
}
BLO_read_list(reader, &sspreadsheet->columns);
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
BLO_read_data_address(reader, &column->id);
BLO_read_data_address(reader, &column->id->name);
/* While the display name is technically runtime data, it is loaded here, otherwise the row
* filters might not now their type if their region draws before the main region. */
BLO_read_data_address(reader, &column->display_name);
}
BLO_read_list(reader, &sspreadsheet->context_path);

View File

@@ -2090,5 +2090,23 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
/* Add a properties sidebar to the spreadsheet editor. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_SPREADSHEET) {
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
ARegion *new_sidebar = do_versions_add_region_if_not_found(
regionbase, RGN_TYPE_UI, "sidebar for spreadsheet", RGN_TYPE_FOOTER);
if (new_sidebar != NULL) {
new_sidebar->alignment = RGN_ALIGN_RIGHT;
new_sidebar->flag |= RGN_FLAG_HIDDEN;
}
}
}
}
}
}
}

View File

@@ -317,6 +317,7 @@ bool ED_operator_animview_active(struct bContext *C);
bool ED_operator_outliner_active(struct bContext *C);
bool ED_operator_outliner_active_no_editobject(struct bContext *C);
bool ED_operator_file_active(struct bContext *C);
bool ED_operator_spreadsheet_active(struct bContext *C);
bool ED_operator_action_active(struct bContext *C);
bool ED_operator_buttons_active(struct bContext *C);
bool ED_operator_node_active(struct bContext *C);

View File

@@ -674,7 +674,7 @@ static bool panel_type_context_poll(ARegion *region,
const PanelType *panel_type,
const char *context)
{
if (UI_panel_category_is_visible(region)) {
if (!BLI_listbase_is_empty(&region->panels_category)) {
return STREQ(panel_type->category, UI_panel_category_active_get(region, false));
}

View File

@@ -279,6 +279,11 @@ bool ED_operator_file_active(bContext *C)
return ed_spacetype_test(C, SPACE_FILE);
}
bool ED_operator_spreadsheet_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_SPREADSHEET);
}
bool ED_operator_action_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_ACTION);

View File

@@ -20,6 +20,7 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
../../blentranslation
../../bmesh
../../depsgraph
../../functions
@@ -40,6 +41,8 @@ set(SRC
spreadsheet_draw.cc
spreadsheet_layout.cc
spreadsheet_ops.cc
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
spreadsheet_context.hh
spreadsheet_cell_value.hh
@@ -50,6 +53,8 @@ set(SRC
spreadsheet_draw.hh
spreadsheet_intern.hh
spreadsheet_layout.hh
spreadsheet_row_filter.hh
spreadsheet_row_filter_ui.hh
)
set(LIB

View File

@@ -49,6 +49,8 @@
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
#include "spreadsheet_row_filter.hh"
#include "spreadsheet_row_filter_ui.hh"
using namespace blender;
using namespace blender::ed::spreadsheet;
@@ -59,6 +61,8 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
"spreadsheet space");
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
{
/* Header. */
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
@@ -75,6 +79,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
}
{
/* Properties region. */
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
region->flag = RGN_FLAG_HIDDEN;
}
{
/* Main window. */
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
@@ -88,8 +101,12 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
MEM_SAFE_FREE(sspreadsheet->runtime);
LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
spreadsheet_row_filter_free(row_filter);
}
LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
spreadsheet_column_free(column);
}
@@ -113,6 +130,11 @@ 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->row_filters);
LISTBASE_FOREACH (const SpreadsheetRowFilter *, src_filter, &sspreadsheet_old->row_filters) {
SpreadsheetRowFilter *new_filter = spreadsheet_row_filter_copy(src_filter);
BLI_addtail(&sspreadsheet_new->row_filters, new_filter);
}
BLI_listbase_clear(&sspreadsheet_new->columns);
LISTBASE_FOREACH (SpreadsheetColumn *, src_column, &sspreadsheet_old->columns) {
SpreadsheetColumn *new_column = spreadsheet_column_copy(src_column);
@@ -128,8 +150,10 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
return (SpaceLink *)sspreadsheet_new;
}
static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
static void spreadsheet_keymap(wmKeyConfig *keyconf)
{
/* Entire editor only. */
WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
}
static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
@@ -160,8 +184,15 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
{
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
}
{
wmKeyMap *keymap = WM_keymap_ensure(
wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
}
}
ID *ED_spreadsheet_get_current_id(struct SpaceSpreadsheet *sspreadsheet)
@@ -346,24 +377,14 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
const ColumnValues *values = scope.add(std::move(values_ptr), __func__);
const int width = get_column_width_in_pixels(*values);
spreadsheet_layout.columns.append({values, width});
spreadsheet_column_assign_runtime_data(column, values->type(), values->name());
}
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();
}
}
}
}
spreadsheet_layout.row_indices = spreadsheet_filter_rows(
*sspreadsheet, spreadsheet_layout, *data_source, scope);
sspreadsheet->runtime->tot_columns = spreadsheet_layout.columns.size();
sspreadsheet->runtime->tot_rows = tot_rows;
@@ -372,9 +393,11 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
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. */
/* Tag other regions for redraw, because the main region updates data for them. */
ARegion *footer = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_FOOTER);
ED_region_tag_redraw(footer);
ARegion *sidebar = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_UI);
ED_region_tag_redraw(sidebar);
}
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
@@ -511,6 +534,24 @@ static void spreadsheet_footer_region_listener(const wmRegionListenerParams *UNU
{
}
static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
{
UI_panel_category_active_set_default(region, "Filters");
ED_region_panels_init(wm, region);
wmKeyMap *keymap = WM_keymap_ensure(
wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
}
static void spreadsheet_right_region_free(ARegion *UNUSED(region))
{
}
static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUSED(params))
{
}
void ED_spacetype_spreadsheet(void)
{
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
@@ -563,5 +604,20 @@ void ED_spacetype_spreadsheet(void)
art->listener = spreadsheet_footer_region_listener;
BLI_addhead(&st->regiontypes, art);
/* regions: right panel buttons */
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->init = spreadsheet_sidebar_init;
art->layout = ED_region_panels_layout;
art->draw = ED_region_panels_draw;
art->free = spreadsheet_right_region_free;
art->listener = spreadsheet_right_region_listener;
BLI_addhead(&st->regiontypes, art);
register_row_filter_panels(*art);
BKE_spacetype_register(st);
}

View File

@@ -56,16 +56,29 @@ SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
return column;
}
void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
const eSpreadsheetColumnValueType data_type,
const StringRefNull display_name)
{
column->data_type = data_type;
MEM_SAFE_FREE(column->display_name);
column->display_name = BLI_strdup(display_name.c_str());
}
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column)
{
SpreadsheetColumnID *new_column_id = spreadsheet_column_id_copy(src_column->id);
SpreadsheetColumn *new_column = spreadsheet_column_new(new_column_id);
if (src_column->display_name != nullptr) {
new_column->display_name = BLI_strdup(src_column->display_name);
}
return new_column;
}
void spreadsheet_column_free(SpreadsheetColumn *column)
{
spreadsheet_column_id_free(column->id);
MEM_SAFE_FREE(column->display_name);
MEM_freeN(column);
}

View File

@@ -43,6 +43,9 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column);
void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
const eSpreadsheetColumnValueType data_type,
const StringRefNull display_name);
void spreadsheet_column_free(SpreadsheetColumn *column);
} // namespace blender::ed::spreadsheet

View File

@@ -16,6 +16,8 @@
#pragma once
#include "DNA_space_types.h"
#include "BLI_string_ref.hh"
#include "spreadsheet_cell_value.hh"
@@ -28,11 +30,13 @@ namespace blender::ed::spreadsheet {
*/
class ColumnValues {
protected:
eSpreadsheetColumnValueType type_;
std::string name_;
int size_;
public:
ColumnValues(std::string name, const int size) : name_(std::move(name)), size_(size)
ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size)
: type_(type), name_(std::move(name)), size_(size)
{
}
@@ -40,6 +44,11 @@ class ColumnValues {
virtual void get_value(int index, CellValue &r_cell_value) const = 0;
eSpreadsheetColumnValueType type() const
{
return type_;
}
StringRefNull name() const
{
return name_;
@@ -60,8 +69,11 @@ template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
GetValueF get_value_;
public:
LambdaColumnValues(std::string name, int size, GetValueF get_value)
: ColumnValues(std::move(name), size), get_value_(std::move(get_value))
LambdaColumnValues(const eSpreadsheetColumnValueType type,
std::string name,
int size,
GetValueF get_value)
: ColumnValues(type, std::move(name), size), get_value_(std::move(get_value))
{
}
@@ -73,13 +85,14 @@ template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
template<typename GetValueF>
std::unique_ptr<ColumnValues> column_values_from_function(std::string name,
std::unique_ptr<ColumnValues> 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<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>(
std::move(name), size, std::move(get_value));
type, std::move(name), size, std::move(get_value));
column_values->default_width = default_width;
return column_values;
}

View File

@@ -53,6 +53,15 @@ class DataSource {
return {};
}
/**
* Returns true iff the data source has the ability to limit visible rows
* by user interface selection status.
*/
virtual bool has_selection_filter() const
{
return false;
}
/**
* Returns the number of rows in columns returned by #get_column_values.
*/

View File

@@ -69,28 +69,35 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type());
switch (type) {
case CD_PROP_FLOAT:
return column_values_from_function(
column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
float value;
varray->get(index, &value);
r_cell_value.value_float = value;
});
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(
column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
int value;
varray->get(index, &value);
r_cell_value.value_int = value;
});
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;
});
case CD_PROP_BOOL:
return column_values_from_function(
column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
bool value;
varray->get(index, &value);
r_cell_value.value_bool = value;
});
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) {
@@ -102,6 +109,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
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) {
@@ -113,6 +121,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
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) {
@@ -137,55 +146,63 @@ using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
static void get_selected_vertex_indices(const Mesh &mesh,
const IsVertexSelectedFn is_vertex_selected_fn,
Vector<int64_t> &r_vertex_indices)
MutableSpan<bool> selection)
{
for (const int i : IndexRange(mesh.totvert)) {
if (is_vertex_selected_fn(i)) {
r_vertex_indices.append(i);
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,
Vector<int64_t> &r_corner_indices)
MutableSpan<bool> selection)
{
for (const int i : IndexRange(mesh.totloop)) {
const MLoop &loop = mesh.mloop[i];
if (is_vertex_selected_fn(loop.v)) {
r_corner_indices.append(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,
Vector<int64_t> &r_face_indices)
MutableSpan<bool> selection)
{
for (const int poly_index : IndexRange(mesh.totpoly)) {
if (!selection[poly_index]) {
continue;
}
const MPoly &poly = mesh.mpoly[poly_index];
bool is_selected = true;
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
const MLoop &loop = mesh.mloop[loop_index];
if (!is_vertex_selected_fn(loop.v)) {
is_selected = false;
selection[poly_index] = false;
break;
}
}
if (is_selected) {
r_face_indices.append(poly_index);
}
}
}
static void get_selected_edge_indices(const Mesh &mesh,
const IsVertexSelectedFn is_vertex_selected_fn,
Vector<int64_t> &r_edge_indices)
MutableSpan<bool> 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)) {
r_edge_indices.append(i);
if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) {
selection[i] = false;
}
}
}
@@ -193,30 +210,40 @@ static void get_selected_edge_indices(const Mesh &mesh,
static void get_selected_indices_on_domain(const Mesh &mesh,
const AttributeDomain domain,
const IsVertexSelectedFn is_vertex_selected_fn,
Vector<int64_t> &r_indices)
MutableSpan<bool> selection)
{
switch (domain) {
case ATTR_DOMAIN_POINT:
return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices);
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, r_indices);
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, r_indices);
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, r_indices);
return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection);
default:
return;
}
}
Span<int64_t> GeometryDataSource::get_selected_element_indices() const
bool GeometryDataSource::has_selection_filter() const
{
Object *object_orig = DEG_get_original_object(object_eval_);
if (object_orig->type == OB_MESH) {
if (object_orig->mode == OB_MODE_EDIT) {
return true;
}
}
return false;
}
void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const
{
std::lock_guard lock{mutex_};
BLI_assert(object_eval_->mode == OB_MODE_EDIT);
BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
Object *object_orig = DEG_get_original_object(object_eval_);
Vector<int64_t> &indices = scope_.construct<Vector<int64_t>>(__func__);
const MeshComponent *mesh_component = static_cast<const MeshComponent *>(component_);
const Mesh *mesh_eval = mesh_component->get_for_read();
Mesh *mesh_orig = (Mesh *)object_orig->data;
@@ -237,7 +264,7 @@ Span<int64_t> GeometryDataSource::get_selected_element_indices() const
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, indices);
get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
}
else if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
@@ -245,10 +272,8 @@ Span<int64_t> GeometryDataSource::get_selected_element_indices() const
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, indices);
get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
}
return indices;
}
void InstancesDataSource::foreach_default_column_ids(
@@ -279,7 +304,10 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
Span<int> reference_handles = component_->instance_reference_handles();
Span<InstanceReference> references = component_->references();
std::unique_ptr<ColumnValues> values = column_values_from_function(
"Name", size, [reference_handles, references](int index, CellValue &r_cell_value) {
SPREADSHEET_VALUE_TYPE_INSTANCES,
"Name",
size,
[reference_handles, references](int index, CellValue &r_cell_value) {
const InstanceReference &reference = references[reference_handles[index]];
switch (reference.type()) {
case InstanceReference::Type::Object: {
@@ -303,6 +331,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
Span<float4x4> transforms = component_->instance_transforms();
if (STREQ(column_id.name, "Position")) {
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
@@ -312,6 +341,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
}
if (STREQ(column_id.name, "Rotation")) {
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
@@ -321,6 +351,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
}
if (STREQ(column_id.name, "Scale")) {
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
@@ -332,6 +363,7 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
if (STREQ(column_id.name, "ID")) {
/* Make the column a bit wider by default, since the IDs tend to be large numbers. */
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_INT32,
column_id.name,
size,
[ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },

View File

@@ -58,7 +58,8 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
Span<int64_t> get_selected_element_indices() const;
bool has_selection_filter() const override;
void apply_selection_filter(MutableSpan<bool> rows_included) const;
void foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &)> fn) const override;

View File

@@ -14,8 +14,83 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "WM_types.h"
#include "spreadsheet_intern.hh"
#include "spreadsheet_row_filter.hh"
using namespace blender::ed::spreadsheet;
static int row_filter_add_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
SpreadsheetRowFilter *row_filter = spreadsheet_row_filter_new();
BLI_addtail(&sspreadsheet->row_filters, row_filter);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SPREADSHEET, sspreadsheet);
return OPERATOR_FINISHED;
}
static void SPREADSHEET_OT_add_row_filter_rule(wmOperatorType *ot)
{
ot->name = "Add Row Filter";
ot->description = "Add a filter to remove rows from the displayed data";
ot->idname = "SPREADSHEET_OT_add_row_filter_rule";
ot->exec = row_filter_add_exec;
ot->poll = ED_operator_spreadsheet_active;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int row_filter_remove_exec(bContext *C, wmOperator *op)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)BLI_findlink(
&sspreadsheet->row_filters, RNA_int_get(op->ptr, "index"));
if (row_filter == nullptr) {
return OPERATOR_CANCELLED;
}
BLI_remlink(&sspreadsheet->row_filters, row_filter);
spreadsheet_row_filter_free(row_filter);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SPREADSHEET, sspreadsheet);
return OPERATOR_FINISHED;
}
static void SPREADSHEET_OT_remove_row_filter_rule(wmOperatorType *ot)
{
ot->name = "Remove Row Filter";
ot->description = "Remove a row filter from the rules";
ot->idname = "SPREADSHEET_OT_remove_row_filter_rule";
ot->exec = row_filter_remove_exec;
ot->poll = ED_operator_spreadsheet_active;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
}
void spreadsheet_operatortypes()
{
WM_operatortype_append(SPREADSHEET_OT_add_row_filter_rule);
WM_operatortype_append(SPREADSHEET_OT_remove_row_filter_rule);
}

View File

@@ -0,0 +1,365 @@
/*
* 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.
*/
#include <cstring>
#include "BLI_listbase.h"
#include "DNA_collection_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
#include "spreadsheet_intern.hh"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
#include "spreadsheet_row_filter.hh"
namespace blender::ed::spreadsheet {
template<typename OperationFn>
static void apply_filter_operation(const ColumnValues &values,
OperationFn check_fn,
MutableSpan<bool> rows_included)
{
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;
}
}
}
static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout,
const SpreadsheetRowFilter &row_filter,
MutableSpan<bool> rows_included)
{
for (const ColumnLayout &column : spreadsheet_layout.columns) {
const ColumnValues &values = *column.values;
if (values.name() != row_filter.column_name) {
continue;
}
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;
}
}
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;
}
}
break;
}
case SPREADSHEET_VALUE_TYPE_FLOAT2: {
const float2 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 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;
}
}
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;
}
}
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;
}
}
break;
}
case SPREADSHEET_VALUE_TYPE_BOOL: {
const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
apply_filter_operation(
values,
[value](const CellValue &cell_value) -> bool {
return *cell_value.value_bool == value;
},
rows_included);
break;
}
case SPREADSHEET_VALUE_TYPE_INSTANCES: {
const StringRef value = row_filter.value_string;
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;
},
rows_included);
break;
}
default:
break;
}
/* Only one column should have this name. */
break;
}
}
static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices)
{
for (const int i : selection.index_range()) {
if (selection[i]) {
indices.append(i);
}
}
}
static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
{
if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_ENABLE)) {
return false;
}
if (BLI_listbase_is_empty(&sspreadsheet.row_filters)) {
return false;
}
return true;
}
static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
const DataSource &data_source)
{
if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY)) {
return false;
}
if (!data_source.has_selection_filter()) {
return false;
}
return true;
}
Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
const SpreadsheetLayout &spreadsheet_layout,
const DataSource &data_source,
ResourceScope &scope)
{
const int tot_rows = data_source.tot_rows();
const bool use_selection = use_selection_filter(sspreadsheet, data_source);
const bool use_filters = use_row_filters(sspreadsheet);
/* Avoid allocating an array if no row filtering is necessary. */
if (!(use_filters || use_selection)) {
return IndexRange(tot_rows).as_span();
}
Array<bool> rows_included(tot_rows, true);
if (use_filters) {
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 (use_selection) {
const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
&data_source);
geometry_data_source->apply_selection_filter(rows_included);
}
Vector<int64_t> &indices = scope.construct<Vector<int64_t>>(__func__);
index_vector_from_bools(rows_included, indices);
return indices;
}
SpreadsheetRowFilter *spreadsheet_row_filter_new()
{
SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN(
sizeof(SpreadsheetRowFilter), __func__);
row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED);
row_filter->operation = SPREADSHEET_ROW_FILTER_LESS;
row_filter->threshold = 0.01f;
row_filter->column_name[0] = '\0';
return row_filter;
}
SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter)
{
SpreadsheetRowFilter *new_filter = spreadsheet_row_filter_new();
memcpy(new_filter, src_row_filter, sizeof(SpreadsheetRowFilter));
new_filter->next = nullptr;
new_filter->prev = nullptr;
return new_filter;
}
void spreadsheet_row_filter_free(SpreadsheetRowFilter *column)
{
MEM_freeN(column);
}
} // namespace blender::ed::spreadsheet

View File

@@ -0,0 +1,35 @@
/*
* 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 "BLI_resource_scope.hh"
#include "spreadsheet_data_source.hh"
#include "spreadsheet_layout.hh"
namespace blender::ed::spreadsheet {
Span<int64_t> 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);
void spreadsheet_row_filter_free(SpreadsheetRowFilter *column);
} // namespace blender::ed::spreadsheet

View File

@@ -0,0 +1,347 @@
/*
* 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.
*/
#include <cstring>
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_screen.h"
#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "BLT_translation.h"
#include "WM_api.h"
#include "WM_types.h"
#include "spreadsheet_column.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_row_filter.hh"
#include "spreadsheet_row_filter_ui.hh"
using namespace blender;
using namespace blender::ed::spreadsheet;
static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name)
{
/* All row filters use the same panel ID. */
BLI_snprintf(r_name, BKE_ST_MAXNAME, "SPREADSHEET_PT_filter");
}
static std::string operation_string(const eSpreadsheetColumnValueType data_type,
const eSpreadsheetFilterOperation operation)
{
if (ELEM(data_type,
SPREADSHEET_VALUE_TYPE_BOOL,
SPREADSHEET_VALUE_TYPE_INSTANCES,
SPREADSHEET_VALUE_TYPE_COLOR)) {
return "==";
}
switch (operation) {
case SPREADSHEET_ROW_FILTER_EQUAL:
return "==";
case SPREADSHEET_ROW_FILTER_GREATER:
return ">";
case SPREADSHEET_ROW_FILTER_LESS:
return "<";
}
BLI_assert_unreachable();
return "";
}
static std::string value_string(const SpreadsheetRowFilter &row_filter,
const eSpreadsheetColumnValueType data_type)
{
switch (data_type) {
case SPREADSHEET_VALUE_TYPE_INT32:
return std::to_string(row_filter.value_int);
case SPREADSHEET_VALUE_TYPE_FLOAT: {
std::ostringstream result;
result.precision(3);
result << std::fixed << row_filter.value_float;
return result.str();
}
case SPREADSHEET_VALUE_TYPE_FLOAT2: {
std::ostringstream result;
result.precision(3);
result << std::fixed << "(" << row_filter.value_float2[0] << ", "
<< row_filter.value_float2[1] << ")";
return result.str();
}
case SPREADSHEET_VALUE_TYPE_FLOAT3: {
std::ostringstream result;
result.precision(3);
result << std::fixed << "(" << row_filter.value_float3[0] << ", "
<< row_filter.value_float3[1] << ", " << row_filter.value_float3[2] << ")";
return result.str();
}
case SPREADSHEET_VALUE_TYPE_BOOL:
return (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) ? IFACE_("True") :
IFACE_("False");
case SPREADSHEET_VALUE_TYPE_INSTANCES:
if (row_filter.value_string != nullptr) {
return row_filter.value_string;
}
return "";
case SPREADSHEET_VALUE_TYPE_COLOR:
std::ostringstream result;
result.precision(3);
result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1]
<< ", " << row_filter.value_color[2] << ", " << row_filter.value_color[3] << ")";
return result.str();
}
BLI_assert_unreachable();
return "";
}
static SpreadsheetColumn *lookup_visible_column_for_filter(const SpaceSpreadsheet &sspreadsheet,
const StringRef column_name)
{
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet.columns) {
if (column->display_name == column_name) {
return column;
}
}
return nullptr;
}
static void spreadsheet_filter_panel_draw_header(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
const SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
const StringRef column_name = filter->column_name;
const eSpreadsheetFilterOperation operation = (eSpreadsheetFilterOperation)filter->operation;
const SpreadsheetColumn *column = lookup_visible_column_for_filter(*sspreadsheet, column_name);
if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE) ||
(column == nullptr && !column_name.is_empty())) {
uiLayoutSetActive(layout, false);
}
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
uiItemR(row, filter_ptr, "enabled", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (column_name.is_empty()) {
uiItemL(row, IFACE_("Filter"), ICON_NONE);
}
else if (column == nullptr) {
uiItemL(row, column_name.data(), ICON_NONE);
}
else {
const eSpreadsheetColumnValueType data_type = (eSpreadsheetColumnValueType)column->data_type;
std::stringstream ss;
ss << column_name;
ss << " ";
ss << operation_string(data_type, operation);
ss << " ";
ss << value_string(*filter, data_type);
uiItemL(row, ss.str().c_str(), ICON_NONE);
}
row = uiLayoutRow(layout, true);
uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
const int current_index = BLI_findindex(&sspreadsheet->row_filters, filter);
uiItemIntO(row, "", ICON_X, "SPREADSHEET_OT_remove_row_filter_rule", "index", current_index);
/* Some padding so the X isn't too close to the drag icon. */
uiItemS_ex(layout, 0.25f);
}
static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
const StringRef column_name = filter->column_name;
const eSpreadsheetFilterOperation operation = (eSpreadsheetFilterOperation)filter->operation;
const SpreadsheetColumn *column = lookup_visible_column_for_filter(*sspreadsheet, column_name);
if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE) ||
!(filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) ||
(column == nullptr && !column_name.is_empty())) {
uiLayoutSetActive(layout, false);
}
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, filter_ptr, "column_name", 0, IFACE_("Column"), ICON_NONE);
/* Don't draw settings for filters with no corresponding visible column. */
if (column == nullptr || column_name.is_empty()) {
return;
}
switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) {
case SPREADSHEET_VALUE_TYPE_INT32:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_FLOAT:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_float", 0, IFACE_("Value"), ICON_NONE);
if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
}
break;
case SPREADSHEET_VALUE_TYPE_FLOAT2:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_float2", 0, IFACE_("Value"), ICON_NONE);
if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
}
break;
case SPREADSHEET_VALUE_TYPE_FLOAT3:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_float3", 0, IFACE_("Value"), ICON_NONE);
if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
}
break;
case SPREADSHEET_VALUE_TYPE_BOOL:
uiItemR(layout, filter_ptr, "value_boolean", 0, IFACE_("Value"), ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_INSTANCES:
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_COLOR:
uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE);
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
break;
}
}
static void spreadsheet_row_filters_layout(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
ARegion *region = CTX_wm_region(C);
bScreen *screen = CTX_wm_screen(C);
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
ListBase *row_filters = &sspreadsheet->row_filters;
if (!(sspreadsheet->filter_flag & SPREADSHEET_FILTER_ENABLE)) {
uiLayoutSetActive(layout, false);
}
uiItemO(layout, nullptr, ICON_ADD, "SPREADSHEET_OT_add_row_filter_rule");
const bool panels_match = UI_panel_list_matches_data(region, row_filters, filter_panel_id_fn);
if (!panels_match) {
UI_panels_free_instanced(C, region);
LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, row_filters) {
char panel_idname[MAX_NAME];
filter_panel_id_fn(row_filter, panel_idname);
PointerRNA *filter_ptr = (PointerRNA *)MEM_mallocN(sizeof(PointerRNA), "panel customdata");
RNA_pointer_create(&screen->id, &RNA_SpreadsheetRowFilter, row_filter, filter_ptr);
UI_panel_add_instanced(C, region, &region->panels, panel_idname, filter_ptr);
}
}
else {
/* Assuming there's only one group of instanced panels, update the custom data pointers. */
Panel *panel = (Panel *)region->panels.first;
LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, row_filters) {
/* Move to the next instanced panel corresponding to the next filter. */
while ((panel->type == nullptr) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
panel = panel->next;
BLI_assert(panel != nullptr); /* There shouldn't be fewer panels than filters. */
}
PointerRNA *filter_ptr = (PointerRNA *)MEM_mallocN(sizeof(PointerRNA), "panel customdata");
RNA_pointer_create(&screen->id, &RNA_SpreadsheetRowFilter, row_filter, filter_ptr);
UI_panel_custom_data_set(panel, filter_ptr);
panel = panel->next;
}
}
}
static void filter_reorder(bContext *C, Panel *panel, int new_index)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
ListBase *row_filters = &sspreadsheet->row_filters;
PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
int current_index = BLI_findindex(row_filters, filter);
BLI_assert(current_index >= 0);
BLI_assert(new_index >= 0);
BLI_listbase_link_move(row_filters, filter, new_index - current_index);
}
static short get_filter_expand_flag(const bContext *UNUSED(C), Panel *panel)
{
PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
return (short)filter->flag & SPREADSHEET_ROW_FILTER_UI_EXPAND;
}
static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, short expand_flag)
{
PointerRNA *filter_ptr = UI_panel_custom_data_get(panel);
SpreadsheetRowFilter *filter = (SpreadsheetRowFilter *)filter_ptr->data;
SET_FLAG_FROM_TEST(filter->flag,
expand_flag & SPREADSHEET_ROW_FILTER_UI_EXPAND,
SPREADSHEET_ROW_FILTER_UI_EXPAND);
}
void register_row_filter_panels(ARegionType &region_type)
{
{
PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
strcpy(panel_type->label, N_("Filters"));
strcpy(panel_type->category, "Filters");
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
panel_type->flag = PANEL_TYPE_NO_HEADER;
panel_type->draw = spreadsheet_row_filters_layout;
BLI_addtail(&region_type.paneltypes, panel_type);
}
{
PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
strcpy(panel_type->label, "");
strcpy(panel_type->category, "Filters");
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
panel_type->flag = PANEL_TYPE_INSTANCED | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_HEADER_EXPAND;
panel_type->draw_header = spreadsheet_filter_panel_draw_header;
panel_type->draw = spreadsheet_filter_panel_draw;
panel_type->get_list_data_expand_flag = get_filter_expand_flag;
panel_type->set_list_data_expand_flag = set_filter_expand_flag;
panel_type->reorder = filter_reorder;
BLI_addtail(&region_type.paneltypes, panel_type);
}
}

View File

@@ -0,0 +1,21 @@
/*
* 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
struct ARegionType;
void register_row_filter_panels(ARegionType &region_type);

View File

@@ -1874,6 +1874,19 @@ typedef struct SpreadsheetColumn {
* #SpreadsheetColumnID in the future for different kinds of ids.
*/
SpreadsheetColumnID *id;
/**
* An indicator of the type of values in the column, set at runtime.
* #eSpreadsheetColumnValueType.
*/
uint8_t data_type;
char _pad0[7];
/**
* The final column name generated by the data source, also just
* cached at runtime when the data source columns are generated.
*/
char *display_name;
} SpreadsheetColumn;
/**
@@ -1914,6 +1927,9 @@ typedef struct SpaceSpreadsheet {
/* List of #SpreadsheetColumn. */
ListBase columns;
/* SpreadsheetRowFilter. */
ListBase row_filters;
/**
* List of #SpreadsheetContext.
* This is a path to the data that is displayed in the spreadsheet.
@@ -1945,8 +1961,44 @@ typedef enum eSpaceSpreadsheet_Flag {
typedef enum eSpaceSpreadsheet_FilterFlag {
SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
SPREADSHEET_FILTER_ENABLE = (1 << 1),
} eSpaceSpreadsheet_FilterFlag;
typedef struct SpreadsheetRowFilter {
struct SpreadsheetRowFilter *next, *prev;
char column_name[64]; /* MAX_NAME. */
/* eSpreadsheetFilterOperation. */
uint8_t operation;
/* eSpaceSpreadsheet_RowFilterFlag. */
uint8_t flag;
char _pad0[2];
int value_int;
char *value_string;
float value_float;
float threshold;
float value_float2[2];
float value_float3[3];
float value_color[4];
char _pad1[4];
} SpreadsheetRowFilter;
typedef enum eSpaceSpreadsheet_RowFilterFlag {
SPREADSHEET_ROW_FILTER_UI_EXPAND = (1 << 0),
SPREADSHEET_ROW_FILTER_BOOL_VALUE = (1 << 1),
SPREADSHEET_ROW_FILTER_ENABLED = (1 << 2),
} eSpaceSpreadsheet_RowFilterFlag;
typedef enum eSpreadsheetFilterOperation {
SPREADSHEET_ROW_FILTER_EQUAL = 0,
SPREADSHEET_ROW_FILTER_GREATER = 1,
SPREADSHEET_ROW_FILTER_LESS = 2,
} eSpreadsheetFilterOperation;
typedef enum eSpaceSpreadsheet_ObjectEvalState {
SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED = 0,
SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
@@ -1958,6 +2010,16 @@ typedef enum eSpaceSpreadsheet_ContextType {
SPREADSHEET_CONTEXT_NODE = 2,
} eSpaceSpreadsheet_ContextType;
typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_BOOL = 0,
SPREADSHEET_VALUE_TYPE_INT32 = 1,
SPREADSHEET_VALUE_TYPE_FLOAT = 2,
SPREADSHEET_VALUE_TYPE_FLOAT2 = 3,
SPREADSHEET_VALUE_TYPE_FLOAT3 = 4,
SPREADSHEET_VALUE_TYPE_COLOR = 5,
SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
} eSpreadsheetColumnValueType;
/**
* We can't just use UI_UNIT_X, because it does not take `widget.points` into account, which
* modifies the width of text as well.

View File

@@ -615,10 +615,12 @@ extern StructRNA RNA_Spline;
extern StructRNA RNA_SplineIKConstraint;
extern StructRNA RNA_SplinePoint;
extern StructRNA RNA_SpotLight;
extern StructRNA RNA_SpreadsheetColumnID;
extern StructRNA RNA_SpreadsheetContext;
extern StructRNA RNA_SpreadsheetContextObject;
extern StructRNA RNA_SpreadsheetContextModifier;
extern StructRNA RNA_SpreadsheetContextNode;
extern StructRNA RNA_SpreadsheetRowFilter;
extern StructRNA RNA_Stereo3dDisplay;
extern StructRNA RNA_StretchToConstraint;
extern StructRNA RNA_StringAttribute;

View File

@@ -7411,6 +7411,131 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
}
static void rna_def_spreadsheet_column_id(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SpreadsheetColumnID", NULL);
RNA_def_struct_sdna(srna, "SpreadsheetColumnID");
RNA_def_struct_ui_text(
srna, "Spreadsheet Column ID", "Data used to identify a spreadsheet column");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Column Name", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
}
static void rna_def_spreadsheet_column(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem data_type_items[] = {
{SPREADSHEET_VALUE_TYPE_INT32, "INT32", ICON_NONE, "Integer", ""},
{SPREADSHEET_VALUE_TYPE_FLOAT, "FLOAT", ICON_NONE, "Float", ""},
{SPREADSHEET_VALUE_TYPE_BOOL, "BOOLEAN", ICON_NONE, "Boolean", ""},
{SPREADSHEET_VALUE_TYPE_INSTANCES, "INSTANCES", ICON_NONE, "Instances", ""},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "SpreadsheetColumn", NULL);
RNA_def_struct_sdna(srna, "SpreadsheetColumn");
RNA_def_struct_ui_text(
srna, "Spreadsheet Column", "Persistent data associated with a spreadsheet column");
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "data_type");
RNA_def_property_enum_items(prop, data_type_items);
RNA_def_property_ui_text(
prop, "Data Type", "The data type of the corresponding column visible in the spreadsheet");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
rna_def_spreadsheet_column_id(brna);
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "SpreadsheetColumnID");
RNA_def_property_ui_text(
prop, "ID", "Data used to identify the corresponding data from the data source");
}
static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem rule_operation_items[] = {
{SPREADSHEET_ROW_FILTER_EQUAL, "EQUAL", ICON_NONE, "Equal To", ""},
{SPREADSHEET_ROW_FILTER_GREATER, "GREATER", ICON_NONE, "Greater Than", ""},
{SPREADSHEET_ROW_FILTER_LESS, "LESS", ICON_NONE, "Less Than", ""},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "SpreadsheetRowFilter", NULL);
RNA_def_struct_sdna(srna, "SpreadsheetRowFilter");
RNA_def_struct_ui_text(srna, "Spreadsheet Row Filter", "");
prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_ENABLED);
RNA_def_property_ui_text(prop, "Enabled", "");
RNA_def_property_ui_icon(prop, ICON_CHECKBOX_DEHLT, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_UI_EXPAND);
RNA_def_property_ui_text(prop, "Show Expanded", "");
RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "column_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Column Name", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rule_operation_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_float", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Float Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_float2", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
RNA_def_property_ui_text(prop, "2D Vector Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_float3", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Vector Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_color", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Color Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_string", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Text Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Threshold", "How close float values need to be to be equal");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_int", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "value_int");
RNA_def_property_ui_text(prop, "Integer Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE);
RNA_def_property_ui_text(prop, "Boolean Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
}
static const EnumPropertyItem spreadsheet_context_type_items[] = {
{SPREADSHEET_CONTEXT_OBJECT, "OBJECT", ICON_NONE, "Object", ""},
{SPREADSHEET_CONTEXT_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
@@ -7545,13 +7670,18 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_FOOTER));
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_FOOTER));
prop = RNA_def_property(srna, "is_pinned", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_PINNED);
RNA_def_property_ui_text(prop, "Is Pinned", "Context path is pinned");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_ENABLE);
RNA_def_property_ui_text(prop, "Use Filter", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "display_context_path_collapsed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED);
RNA_def_property_ui_text(prop, "Display Context Path Collapsed", "");
@@ -7566,6 +7696,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
RNA_def_property_ui_text(
prop, "Show Only Selected", "Only include rows that correspond to selected elements");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE);
@@ -7587,6 +7718,22 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Object Evaluation State", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
rna_def_spreadsheet_column(brna);
prop = RNA_def_property(srna, "columns", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "columns", NULL);
RNA_def_property_struct_type(prop, "SpreadsheetColumn");
RNA_def_property_ui_text(prop, "Columns", "Persistent data associated with spreadsheet columns");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
rna_def_spreadsheet_row_filter(brna);
prop = RNA_def_property(srna, "row_filters", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "row_filters", NULL);
RNA_def_property_struct_type(prop, "SpreadsheetRowFilter");
RNA_def_property_ui_text(prop, "Row Filters", "Filters to remove rows from the displayed data");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
func = RNA_def_function(
srna, "set_geometry_node_context", "rna_spreadsheet_set_geometry_node_context");
RNA_def_function_ui_description(