Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-06-19 22:12:13 +02:00
commit d9badbf25c
30 changed files with 1654 additions and 227 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
@ -7099,6 +7115,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_available(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_available(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

@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 3
#define BLENDER_FILE_SUBVERSION 4
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -1357,12 +1357,21 @@ 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.
* This would ideally be cleared here. */
BLO_write_string(writer, column->display_name);
}
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
switch (context->type) {
@ -1743,11 +1752,18 @@ 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.
* This would ideally be cleared here. */
BLO_read_data_address(reader, &column->display_name);
}
BLO_read_list(reader, &sspreadsheet->context_path);

View File

@ -44,6 +44,8 @@
#include "MEM_guardedalloc.h"
#include "versioning_common.h"
static void sort_linked_ids(Main *bmain)
{
ListBase *lb;
@ -310,17 +312,37 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!MAIN_VERSION_ATLEAST(bmain, 300, 4)) {
/* 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;
}
}
}
}
}
/* Enable spreadsheet filtering in old files without row filters. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_SPREADSHEET) {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
sspreadsheet->filter_flag |= SPREADSHEET_FILTER_ENABLE;
}
}
}
}
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
version_node_socket_name(ntree, GEO_NODE_BOUNDING_BOX, "Mesh", "Bounding Box");
@ -369,4 +391,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
BKE_animdata_main_cb(bmain, do_version_bbone_len_scale_animdata_cb, NULL);
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
}

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

@ -64,7 +64,9 @@
#include "object_intern.h"
/******************************** API ****************************/
/* -------------------------------------------------------------------- */
/** \name Public API
* \{ */
ShaderFxData *ED_object_shaderfx_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
@ -261,7 +263,12 @@ void ED_object_shaderfx_copy(Object *dst, ShaderFxData *fx)
WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, dst);
}
/**************** Generic poll callback helpers. ************************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic Poll Callback Helpers
* \{ */
static bool edit_shaderfx_poll_generic(bContext *C,
StructRNA *rna_type,
int obtype_flag,
@ -304,7 +311,11 @@ static bool edit_shaderfx_poll(bContext *C)
return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0, false);
}
/************************ add effect operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Add Effect Operator
* \{ */
static int shaderfx_add_exec(bContext *C, wmOperator *op)
{
@ -473,7 +484,9 @@ static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int
/** \} */
/************************ remove shaderfx operator *********************/
/* -------------------------------------------------------------------- */
/** \name Remove ShaderFX Operator
* \{ */
static int shaderfx_remove_exec(bContext *C, wmOperator *op)
{
@ -523,7 +536,11 @@ void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
edit_shaderfx_report_property(ot);
}
/************************ move up shaderfx operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Move up ShaderFX Operator
* \{ */
static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
{
@ -564,7 +581,11 @@ void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
edit_shaderfx_properties(ot);
}
/************************ move down shaderfx operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Move Down ShaderFX Operator
* \{ */
static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
{
@ -605,7 +626,11 @@ void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
edit_shaderfx_properties(ot);
}
/************************ move shaderfx to index operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Move ShaderFX to Index Operator
* \{ */
static int shaderfx_move_to_index_exec(bContext *C, wmOperator *op)
{
@ -648,7 +673,11 @@ void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot)
ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the effect to", 0, INT_MAX);
}
/************************ copy shader operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Copy Shader Operator
* \{ */
static int shaderfx_copy_exec(bContext *C, wmOperator *op)
{
@ -696,3 +725,5 @@ void OBJECT_OT_shaderfx_copy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_shaderfx_properties(ot);
}
/** \} */

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

@ -52,7 +52,9 @@
#include "clip_intern.h"
#include "tracking_ops_intern.h"
/********************** add marker operator *********************/
/* -------------------------------------------------------------------- */
/** \name Add Marker Operator
* \{ */
static bool add_marker(const bContext *C, float x, float y)
{
@ -147,7 +149,11 @@ void CLIP_OT_add_marker(wmOperatorType *ot)
1.0f);
}
/********************** add marker operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Add Marker Operator
* \{ */
static int add_marker_at_click_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
@ -212,7 +218,11 @@ void CLIP_OT_add_marker_at_click(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
}
/********************** delete track operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Delete Track Operator
* \{ */
static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -265,7 +275,11 @@ void CLIP_OT_delete_track(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** delete marker operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Delete Marker Operator
* \{ */
static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -334,7 +348,11 @@ void CLIP_OT_delete_marker(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** slide marker operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Slide Marker Operator
* \{ */
enum {
SLIDE_ACTION_POS = 0,
@ -1000,7 +1018,11 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
FLT_MAX);
}
/********************** clear track operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Clear Track Operator
* \{ */
static int clear_track_path_exec(bContext *C, wmOperator *op)
{
@ -1071,7 +1093,11 @@ void CLIP_OT_clear_track_path(wmOperatorType *ot)
"Clear active track only instead of all selected tracks");
}
/********************** disable markers operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Disable Markers Operator
* \{ */
enum {
MARKER_OP_DISABLE = 0,
@ -1137,7 +1163,11 @@ void CLIP_OT_disable_markers(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
}
/********************** set principal center operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Set Principal Center Operator
* \{ */
static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -1174,7 +1204,11 @@ void CLIP_OT_set_center_principal(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** hide tracks operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Hide Tracks Operator
* \{ */
static int hide_tracks_exec(bContext *C, wmOperator *op)
{
@ -1241,7 +1275,11 @@ void CLIP_OT_hide_tracks(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
}
/********************** hide tracks clear operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Hide Tracks Clear Operator
* \{ */
static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -1284,7 +1322,11 @@ void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** frame jump operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Frame Jump Operator
* \{ */
static bool frame_jump_poll(bContext *C)
{
@ -1379,7 +1421,11 @@ void CLIP_OT_frame_jump(wmOperatorType *ot)
RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jump to");
}
/********************** join tracks operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Join Tracks Operator
* \{ */
static int join_tracks_exec(bContext *C, wmOperator *op)
{
@ -1475,7 +1521,11 @@ void CLIP_OT_join_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** Average tracks operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Average Tracks Operator
* \{ */
static int average_tracks_exec(bContext *C, wmOperator *op)
{
@ -1566,7 +1616,11 @@ void CLIP_OT_average_tracks(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/********************** lock tracks operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lock Tracks Operator
* \{ */
enum {
TRACK_ACTION_LOCK = 0,
@ -1628,7 +1682,11 @@ void CLIP_OT_lock_tracks(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
}
/********************** set keyframe operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Set Keyframe Operator
* \{ */
enum {
SOLVER_KEYFRAME_A = 0,
@ -1680,7 +1738,11 @@ void CLIP_OT_set_solver_keyframe(wmOperatorType *ot)
RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe", "Keyframe to set");
}
/********************** track copy color operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Track Copy Color Operator
* \{ */
static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -1725,7 +1787,11 @@ void CLIP_OT_track_copy_color(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** clean tracks operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Clean Tracks Operator
* \{ */
static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
{
@ -1963,7 +2029,11 @@ void CLIP_OT_clean_tracks(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
}
/********************** add tracking object *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Add Tracking Object
* \{ */
static int tracking_object_new_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -1994,7 +2064,11 @@ void CLIP_OT_tracking_object_new(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** remove tracking object *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Remove Tracking Object
* \{ */
static int tracking_object_remove_exec(bContext *C, wmOperator *op)
{
@ -2033,7 +2107,11 @@ void CLIP_OT_tracking_object_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** copy tracks to clipboard operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Copy Tracks to Clipboard Operator
* \{ */
static int copy_tracks_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -2064,7 +2142,11 @@ void CLIP_OT_copy_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
/********************* paste tracks from clipboard operator ********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Paste Tracks From Clipboard Operator
* \{ */
static bool paste_tracks_poll(bContext *C)
{
@ -2106,7 +2188,11 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** Insert track keyframe operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Insert Track Keyframe Operator
* \{ */
static void keyframe_set_flag(bContext *C, bool set)
{
@ -2181,7 +2267,11 @@ void CLIP_OT_keyframe_insert(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** Delete track keyframe operator *********************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Delete Track Keyframe Operator
* \{ */
static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -2203,3 +2293,5 @@ void CLIP_OT_keyframe_delete(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */

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,366 @@
/*
* 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_float2;
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 *row_filter)
{
MEM_SAFE_FREE(row_filter->value_string);
MEM_freeN(row_filter);
}
} // 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 *row_filter);
} // 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

@ -318,16 +318,21 @@ static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
return false;
}
/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal to
* overlap of transformed strips. */
static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips)
static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
{
Editing *ed = SEQ_editing_get(t->scene, false);
ListBase *seqbasep = SEQ_active_seqbase_get(ed);
ListBase *markers = &t->scene->markers;
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
SeqCollection *collection = SEQ_collection_create();
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
SEQ_collection_append_strip(seq, collection);
}
}
return collection;
}
/* Query strips positioned after left edge of transformed strips boundbox. */
static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
{
int minframe = MAXFRAME;
{
Sequence *seq;
@ -336,35 +341,40 @@ static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *tran
}
}
/* Temporarily move strips to beyond timeline boundary */
LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
if (!(seq->flag & SELECT)) {
if (seq->startdisp >= minframe) {
seq->machine += MAXSEQ * 2;
}
SeqCollection *collection = SEQ_collection_create();
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if ((seq->flag & SELECT) == 0 && seq->startdisp >= minframe) {
SEQ_collection_append_strip(seq, collection);
}
}
/* Shuffle transformed non-effects. This is because transformed strips can overlap with strips
* on left side. */
SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
/* Move temporarily moved strips back to their original place and tag for shuffling. */
LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
if (seq->machine >= MAXSEQ * 2) {
seq->machine -= MAXSEQ * 2;
seq->tmp = (void *)1;
}
else {
seq->tmp = NULL;
}
}
/* Shuffle again to displace strips on right side. Final effect shuffling is done in
* seq_transform_handle_overlap. */
SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
return collection;
}
static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transformed_strips)
static void seq_transform_update_effects(TransInfo *t, SeqCollection *collection)
{
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
SEQ_time_update_sequence(t->scene, seq);
}
}
}
/* Check if effect strips with input are transformed. */
static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips)
{
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
return true;
}
}
return false;
}
/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal
* to overlap of transformed strips. */
static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips)
{
Editing *ed = SEQ_editing_get(t->scene, false);
ListBase *seqbasep = SEQ_active_seqbase_get(ed);
@ -372,38 +382,58 @@ static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transforme
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
seq->tmp = NULL;
SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips);
/* Temporarily move right side strips beyond timeline boundary. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
seq->machine += MAXSEQ * 2;
}
/* Check if effect strips are transformed and tag non effects. */
bool has_effect = false;
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
has_effect = true;
}
else {
seq->tmp = (void *)1;
}
/* Shuffle transformed standalone strips. This is because transformed strips can overlap with
* strips on left side. */
SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
SEQ_transform_seqbase_shuffle_time(
standalone_strips, seqbasep, t->scene, markers, use_sync_markers);
SEQ_collection_free(standalone_strips);
/* Move temporarily moved strips back to their original place and tag for shuffling. */
SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
seq->machine -= MAXSEQ * 2;
}
/* Shuffle again to displace strips on right side. Final effect shuffling is done in
* seq_transform_handle_overlap. */
SEQ_transform_seqbase_shuffle_time(
right_side_strips, seqbasep, t->scene, markers, use_sync_markers);
seq_transform_update_effects(t, right_side_strips);
SEQ_collection_free(right_side_strips);
}
static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transformed_strips)
{
Editing *ed = SEQ_editing_get(t->scene, false);
ListBase *seqbasep = SEQ_active_seqbase_get(ed);
if (t->flag & T_ALT_TRANSFORM) {
seq_transform_handle_expand_to_fit(t, transformed_strips);
}
else {
SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers);
ListBase *markers = &t->scene->markers;
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
/* Shuffle non strips with no effects attached. */
SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
SEQ_transform_seqbase_shuffle_time(
standalone_strips, seqbasep, t->scene, markers, use_sync_markers);
SEQ_collection_free(standalone_strips);
}
if (has_effect) {
if (seq_transform_check_strip_effects(transformed_strips)) {
/* Update effect strips based on strips just moved in time. */
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
SEQ_time_update_sequence(t->scene, seq);
}
}
seq_transform_update_effects(t, transformed_strips);
/* If any effects still overlap, we need to move them up. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
if (SEQ_transform_test_overlap(seqbasep, seq)) {
@ -414,24 +444,6 @@ static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transforme
}
}
static void seq_transform_update_effects(TransInfo *t, SeqCollection *transformed_strips)
{
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
if (seq->type & SEQ_TYPE_EFFECT) {
if (seq->seq1 && seq->seq1->flag & SELECT) {
SEQ_time_update_sequence(t->scene, seq);
}
else if (seq->seq2 && seq->seq2->flag & SELECT) {
SEQ_time_update_sequence(t->scene, seq);
}
else if (seq->seq3 && seq->seq3->flag & SELECT) {
SEQ_time_update_sequence(t->scene, seq);
}
}
}
}
static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc)
{
SeqCollection *collection = SEQ_collection_create();

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(

View File

@ -30,6 +30,7 @@ extern "C" {
struct ListBase;
struct Scene;
struct Sequence;
struct SeqCollection;
int SEQ_transform_get_left_handle_frame(struct Sequence *seq);
int SEQ_transform_get_right_handle_frame(struct Sequence *seq);
@ -48,7 +49,8 @@ bool SEQ_transform_seqbase_shuffle_ex(struct ListBase *seqbasep,
bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
bool SEQ_transform_seqbase_shuffle_time(struct ListBase *seqbasep,
bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
const bool use_sync_markers);

View File

@ -34,6 +34,7 @@
#include "BKE_sound.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@ -302,73 +303,69 @@ bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *ev
return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1);
}
static int shuffle_seq_time_offset_test(ListBase *seqbasep, char dir)
static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
ListBase *seqbasep,
char dir)
{
int offset = 0;
Sequence *seq, *seq_other;
Sequence *seq;
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->tmp) {
for (seq_other = seqbasep->first; seq_other; seq_other = seq_other->next) {
if (!seq_other->tmp && seq_overlap(seq, seq_other)) {
if (dir == 'L') {
offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
}
else {
offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
}
}
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
if (!seq_overlap(seq, seq_other)) {
continue;
}
if (dir == 'L') {
offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
}
else {
offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
}
}
}
return offset;
}
static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir)
static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle,
ListBase *seqbasep,
Scene *scene,
char dir)
{
int ofs = 0;
int tot_ofs = 0;
Sequence *seq;
while ((ofs = shuffle_seq_time_offset_test(seqbasep, dir))) {
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->tmp) {
/* seq_test_overlap only tests display values */
seq->startdisp += ofs;
seq->enddisp += ofs;
}
while ((ofs = shuffle_seq_time_offset_test(strips_to_shuffle, seqbasep, dir))) {
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
/* seq_test_overlap only tests display values */
seq->startdisp += ofs;
seq->enddisp += ofs;
}
tot_ofs += ofs;
}
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->tmp) {
SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */
}
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */
}
return tot_ofs;
}
bool SEQ_transform_seqbase_shuffle_time(ListBase *seqbasep,
bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
const bool use_sync_markers)
{
/* note: seq->tmp is used to tag strips to move */
Sequence *seq;
int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
int offset_l = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'L');
int offset_r = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'R');
int offset = (-offset_l < offset_r) ? offset_l : offset_r;
if (offset) {
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->tmp) {
SEQ_transform_translate_sequence(evil_scene, seq, offset);
seq->flag &= ~SEQ_OVERLAP;
}
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
SEQ_transform_translate_sequence(evil_scene, seq, offset);
seq->flag &= ~SEQ_OVERLAP;
}
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {