WIP: Animation: Select Grouped operator #104758

Draft
RedMser wants to merge 9 commits from RedMser/blender:animation-select-grouped into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
1 changed files with 68 additions and 51 deletions
Showing only changes of commit 73e55990e0 - Show all commits

View File

@ -14,6 +14,7 @@
#include "BLI_blenlib.h"
#include "BLI_dlrbTree.h"
#include "BLI_ghash.h"
#include "BLI_lasso_2d.h"
#include "BLI_utildefines.h"
@ -1963,7 +1964,8 @@ static short select_grouped_datablock(KeyframeEditData *ked, struct BezTriple *b
static short select_grouped_active_datablock(KeyframeEditData *ked, struct BezTriple *bezt)
{
/* Stop after the first selected bezt was found. */
/* Cancel iteration if we found any selected key. The key will be added to the set in the loop,
* since the info comes from the anim data list. */
return 1;
}
@ -1971,29 +1973,32 @@ static short select_grouped_active_datablock(KeyframeEditData *ked, struct BezTr
static short select_grouped_handle_type(KeyframeEditData *ked, struct BezTriple *bezt)
{
/* TODO(redmser): Should this compare left and right handle individually? In dopesheet, you can't
* select individual handles to clarify the intent. */
char handle = *(char *)ked->data;
if (bezt->h1 == handle && bezt->h2 == handle) {
return KEYFRAME_OK_ALL;
short ok = 0;
if (BLI_gset_haskey(ked->data, POINTER_FROM_INT(bezt->h1))) {
ok |= KEYFRAME_OK_H1;
}
return 0;
if (BLI_gset_haskey(ked->data, POINTER_FROM_INT(bezt->h2))) {
ok |= KEYFRAME_OK_H2;
}
if (ok == (KEYFRAME_OK_H1 | KEYFRAME_OK_H2)) {
ok |= KEYFRAME_OK_KEY;
}
return ok;
}
static short select_grouped_active_handle_type(KeyframeEditData *ked, struct BezTriple *bezt)
{
if (bezt->h1 == bezt->h2) {
*((uint8_t *)ked->data) = bezt->h1;
BLI_gset_add(ked->data, POINTER_FROM_INT(bezt->h1));
}
return 1;
return 0;
}
/* ACTKEYS_SELECT_GROUP_INTERPOLATION_TYPE */
static short select_grouped_interpolation_type(KeyframeEditData *ked, struct BezTriple *bezt)
{
char ipo = *(char *)ked->data;
if (bezt->ipo == ipo) {
if (BLI_gset_haskey(ked->data, POINTER_FROM_INT(bezt->ipo))) {
return KEYFRAME_OK_ALL;
}
return 0;
@ -2002,16 +2007,15 @@ static short select_grouped_interpolation_type(KeyframeEditData *ked, struct Bez
static short select_grouped_active_interpolation_type(KeyframeEditData *ked,
struct BezTriple *bezt)
{
*((char *)ked->data) = bezt->ipo;
return 1;
BLI_gset_add(ked->data, POINTER_FROM_INT(bezt->ipo));
return 0;
}
/* ACTKEYS_SELECT_GROUP_KEY_TYPE */
static short select_grouped_key_type(KeyframeEditData *ked, struct BezTriple *bezt)
{
char key_type = *(char *)ked->data;
if (BEZKEYTYPE(bezt) == key_type) {
if (BLI_gset_haskey(ked->data, POINTER_FROM_INT(BEZKEYTYPE(bezt)))) {
return KEYFRAME_OK_ALL;
}
return 0;
@ -2019,30 +2023,41 @@ static short select_grouped_key_type(KeyframeEditData *ked, struct BezTriple *be
static short select_grouped_active_key_type(KeyframeEditData *ked, struct BezTriple *bezt)
{
*((char *)ked->data) = BEZKEYTYPE(bezt);
return 1;
BLI_gset_add(ked->data, POINTER_FROM_INT(BEZKEYTYPE(bezt)));
return 0;
}
/* TODO(redmser): These filters could all allow multi-selection. Instead of setting ked->data, add
* the filter (if unique) to ked->list and do an "includes" check instead. */
static KeyframeEditFunc select_grouped_get_filter_callback(ListBase *anim_data,
KeyframeEditData *ked,
int type)
{
KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
GSet *comp_set;
if (type == ACTKEYS_SELECT_GROUP_DATABLOCK) {
comp_set = BLI_gset_str_new(__func__);
}
else {
comp_set = BLI_gset_int_new(__func__);
}
ked->data = comp_set;
/* Last iteration of this loop will be used to return a callback based on type. */
bAnimListElem *ale;
for (ale = anim_data->first; ale; ale = ale->next) {
/* TODO(redmser): Other types (GP, mask, etc.). */
if (ale->datatype != ALE_FCURVE) {
continue;
}
for (ale = anim_data->first;; ale = ale->next) {
FCurve *fcu;
if (ale != NULL) {
/* TODO(redmser): Other types (GP, mask, etc.). */
if (ale->datatype != ALE_FCURVE) {
continue;
}
/* Only continue if F-Curve has keyframes. */
FCurve *fcu = (FCurve *)ale->key_data;
if (fcu->bezt == NULL) {
continue;
/* Only continue if F-Curve has keyframes. */
fcu = (FCurve *)ale->key_data;
if (fcu->bezt == NULL) {
continue;
}
}
/* Find first selected keyframe for context info. */
@ -2052,33 +2067,28 @@ static KeyframeEditFunc select_grouped_get_filter_callback(ListBase *anim_data,
break;
}
case ACTKEYS_SELECT_GROUP_HANDLE_TYPE: {
char handle = 0;
ked->data = &handle;
short result = ANIM_fcurve_keyframes_loop(
ked, fcu, ok_cb, select_grouped_active_handle_type, NULL);
if (result == 1) {
if (ale == NULL) {
return select_grouped_handle_type;
}
ANIM_fcurve_keyframes_loop(ked, fcu, ok_cb, select_grouped_active_handle_type, NULL);
break;
}
case ACTKEYS_SELECT_GROUP_INTERPOLATION_TYPE: {
char ipo = 0;
ked->data = &ipo;
short result = ANIM_fcurve_keyframes_loop(
ked, fcu, ok_cb, select_grouped_active_interpolation_type, NULL);
if (result == 1) {
if (ale == NULL) {
return select_grouped_interpolation_type;
}
ANIM_fcurve_keyframes_loop(
ked, fcu, ok_cb, select_grouped_active_interpolation_type, NULL);
break;
}
case ACTKEYS_SELECT_GROUP_KEY_TYPE: {
char key_type = 0;
ked->data = &key_type;
short result = ANIM_fcurve_keyframes_loop(
ked, fcu, ok_cb, select_grouped_active_key_type, NULL);
if (result == 1) {
if (ale == NULL) {
return select_grouped_key_type;
}
ANIM_fcurve_keyframes_loop(ked, fcu, ok_cb, select_grouped_active_key_type, NULL);
break;
}
case ACTKEYS_SELECT_GROUP_MODIFIERS: {
@ -2087,11 +2097,15 @@ static KeyframeEditFunc select_grouped_get_filter_callback(ListBase *anim_data,
}
case ACTKEYS_SELECT_GROUP_DATABLOCK: {
/* Same datablock, identified by name. */
if (ale == NULL) {
return select_grouped_datablock;
}
short result = ANIM_fcurve_keyframes_loop(
ked, fcu, ok_cb, select_grouped_active_datablock, NULL);
if (result == 1) {
ked->data = ale->id->name;
return select_grouped_datablock;
/* Found a selected key in this datablock, add its id. */
BLI_gset_add(ked->data, BLI_strdup(ale->id->name));
}
break;
}
@ -2102,10 +2116,6 @@ static KeyframeEditFunc select_grouped_get_filter_callback(ListBase *anim_data,
}
}
if (type == ACTKEYS_SELECT_GROUP_DATABLOCK) {
char empty[1] = {'\0'};
ked->data = empty;
}
return NULL;
}
@ -2157,7 +2167,7 @@ static int actkeys_select_grouped_exec(bContext *C, wmOperator *op)
/* Filtering by datablock has to be done on anim data level. */
/* TODO(redmser): This will not work for datablocks from different libraries, since they have
* the same name. */
if (type == ACTKEYS_SELECT_GROUP_DATABLOCK && !STREQ(ale->id->name, (char *)ked.data)) {
if (type == ACTKEYS_SELECT_GROUP_DATABLOCK && !BLI_gset_haskey(ked.data, ale->id->name)) {
continue;
}
@ -2166,6 +2176,13 @@ static int actkeys_select_grouped_exec(bContext *C, wmOperator *op)
ANIM_animdata_freelist(&anim_data);
if (type == ACTKEYS_SELECT_GROUP_DATABLOCK) {
BLI_gset_free(ked.data, MEM_freeN);
}
else {
BLI_gset_free(ked.data, NULL);
}
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}