Allow select range in animation editor
This patch will add support to select all channels between active channel and last-clicked channel without deselecting previous selection. `Shift` key is now assigned for the range selection and `ctrl` key to extend the selection. This changes will make multi-selection similar as outliner tree-elements. New function is created `animchannel_select_range` to handle the range selection of channels. Old Differential revision: https://archive.blender.org/developer/D17079 Pull Request: https://projects.blender.org/blender/blender/pulls/104565
This commit is contained in:
committed by
Pratik Borhade
parent
c9b51591da
commit
80feb13665
@@ -3463,7 +3463,9 @@ def km_animation_channels(params):
|
|||||||
items.extend([
|
items.extend([
|
||||||
# Click select.
|
# Click select.
|
||||||
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
|
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
|
||||||
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||||
|
{"properties": [("extend_range", True)]}),
|
||||||
|
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
|
||||||
{"properties": [("extend", True)]}),
|
{"properties": [("extend", True)]}),
|
||||||
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
|
("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True},
|
||||||
{"properties": [("children_only", True)]}),
|
{"properties": [("children_only", True)]}),
|
||||||
|
|||||||
@@ -313,7 +313,64 @@ void ANIM_set_active_channel(bAnimContext *ac,
|
|||||||
ANIM_animdata_freelist(&anim_data);
|
ANIM_animdata_freelist(&anim_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale)
|
bool ANIM_is_active_channel(bAnimListElem *ale)
|
||||||
|
{
|
||||||
|
switch (ale->type) {
|
||||||
|
case ANIMTYPE_FILLACTD: /* Action Expander */
|
||||||
|
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||||
|
case ANIMTYPE_DSLAM:
|
||||||
|
case ANIMTYPE_DSCAM:
|
||||||
|
case ANIMTYPE_DSCACHEFILE:
|
||||||
|
case ANIMTYPE_DSCUR:
|
||||||
|
case ANIMTYPE_DSSKEY:
|
||||||
|
case ANIMTYPE_DSWOR:
|
||||||
|
case ANIMTYPE_DSPART:
|
||||||
|
case ANIMTYPE_DSMBALL:
|
||||||
|
case ANIMTYPE_DSARM:
|
||||||
|
case ANIMTYPE_DSMESH:
|
||||||
|
case ANIMTYPE_DSNTREE:
|
||||||
|
case ANIMTYPE_DSTEX:
|
||||||
|
case ANIMTYPE_DSLAT:
|
||||||
|
case ANIMTYPE_DSLINESTYLE:
|
||||||
|
case ANIMTYPE_DSSPK:
|
||||||
|
case ANIMTYPE_DSGPENCIL:
|
||||||
|
case ANIMTYPE_DSMCLIP:
|
||||||
|
case ANIMTYPE_DSHAIR:
|
||||||
|
case ANIMTYPE_DSPOINTCLOUD:
|
||||||
|
case ANIMTYPE_DSVOLUME:
|
||||||
|
case ANIMTYPE_NLAACTION:
|
||||||
|
case ANIMTYPE_DSSIMULATION: {
|
||||||
|
if (ale->adt) {
|
||||||
|
return ale->adt->flag & ADT_UI_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ANIMTYPE_GROUP: {
|
||||||
|
bActionGroup *argp = (bActionGroup *)ale->data;
|
||||||
|
return argp->flag & AGRP_ACTIVE;
|
||||||
|
}
|
||||||
|
case ANIMTYPE_FCURVE:
|
||||||
|
case ANIMTYPE_NLACURVE: {
|
||||||
|
FCurve *fcu = (FCurve *)ale->data;
|
||||||
|
return fcu->flag & FCURVE_ACTIVE;
|
||||||
|
}
|
||||||
|
case ANIMTYPE_GPLAYER: {
|
||||||
|
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||||
|
return gpl->flag & GP_LAYER_ACTIVE;
|
||||||
|
}
|
||||||
|
/* These channel types do not have active flags. */
|
||||||
|
case ANIMTYPE_MASKLAYER:
|
||||||
|
case ANIMTYPE_SHAPEKEY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change_active determines whether to change the active bone of the armature when selecting pose
|
||||||
|
* channels. It is false during range selection otherwise true. */
|
||||||
|
static void select_pchan_for_action_group(bAnimContext *ac,
|
||||||
|
bActionGroup *agrp,
|
||||||
|
bAnimListElem *ale,
|
||||||
|
const bool change_active)
|
||||||
{
|
{
|
||||||
/* Armatures-Specific Feature:
|
/* Armatures-Specific Feature:
|
||||||
* See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (#38737)
|
* See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (#38737)
|
||||||
@@ -329,11 +386,12 @@ static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp,
|
|||||||
* TODO: check the first F-Curve or so to be sure...
|
* TODO: check the first F-Curve or so to be sure...
|
||||||
*/
|
*/
|
||||||
bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
|
bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
|
||||||
|
|
||||||
if (agrp->flag & AGRP_SELECTED) {
|
if (agrp->flag & AGRP_SELECTED) {
|
||||||
ED_pose_bone_select(ob, pchan, true);
|
ED_pose_bone_select(ob, pchan, true, change_active);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ED_pose_bone_select(ob, pchan, false);
|
ED_pose_bone_select(ob, pchan, false, change_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -441,10 +499,15 @@ static void anim_channels_select_set(bAnimContext *ac,
|
|||||||
eAnimChannels_SetFlag sel)
|
eAnimChannels_SetFlag sel)
|
||||||
{
|
{
|
||||||
bAnimListElem *ale;
|
bAnimListElem *ale;
|
||||||
|
/* Boolean to keep active channel status during range selection. */
|
||||||
|
const bool change_active = (sel != ACHANNEL_SETFLAG_EXTEND_RANGE);
|
||||||
|
|
||||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||||
switch (ale->type) {
|
switch (ale->type) {
|
||||||
case ANIMTYPE_SCENE: {
|
case ANIMTYPE_SCENE: {
|
||||||
|
if (change_active) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
Scene *scene = (Scene *)ale->data;
|
Scene *scene = (Scene *)ale->data;
|
||||||
|
|
||||||
ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
|
ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
|
||||||
@@ -471,8 +534,10 @@ static void anim_channels_select_set(bAnimContext *ac,
|
|||||||
case ANIMTYPE_GROUP: {
|
case ANIMTYPE_GROUP: {
|
||||||
bActionGroup *agrp = (bActionGroup *)ale->data;
|
bActionGroup *agrp = (bActionGroup *)ale->data;
|
||||||
ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
|
ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
|
||||||
select_pchan_for_action_group(ac, agrp, ale);
|
select_pchan_for_action_group(ac, agrp, ale, change_active);
|
||||||
agrp->flag &= ~AGRP_ACTIVE;
|
if (change_active) {
|
||||||
|
agrp->flag &= ~AGRP_ACTIVE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ANIMTYPE_FCURVE:
|
case ANIMTYPE_FCURVE:
|
||||||
@@ -480,7 +545,7 @@ static void anim_channels_select_set(bAnimContext *ac,
|
|||||||
FCurve *fcu = (FCurve *)ale->data;
|
FCurve *fcu = (FCurve *)ale->data;
|
||||||
|
|
||||||
ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
|
ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
|
||||||
if ((fcu->flag & FCURVE_SELECTED) == 0) {
|
if (!(fcu->flag & FCURVE_SELECTED) && change_active) {
|
||||||
/* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves"
|
/* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves"
|
||||||
* retains the currently active curve. */
|
* retains the currently active curve. */
|
||||||
fcu->flag &= ~FCURVE_ACTIVE;
|
fcu->flag &= ~FCURVE_ACTIVE;
|
||||||
@@ -527,7 +592,9 @@ static void anim_channels_select_set(bAnimContext *ac,
|
|||||||
/* need to verify that this data is valid for now */
|
/* need to verify that this data is valid for now */
|
||||||
if (ale->adt) {
|
if (ale->adt) {
|
||||||
ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
|
ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
|
||||||
ale->adt->flag &= ~ADT_UI_ACTIVE;
|
if (change_active) {
|
||||||
|
ale->adt->flag &= ~ADT_UI_ACTIVE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2891,7 +2958,7 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm
|
|||||||
switch (ale->type) {
|
switch (ale->type) {
|
||||||
case ANIMTYPE_GROUP: {
|
case ANIMTYPE_GROUP: {
|
||||||
bActionGroup *agrp = (bActionGroup *)ale->data;
|
bActionGroup *agrp = (bActionGroup *)ale->data;
|
||||||
select_pchan_for_action_group(ac, agrp, ale);
|
select_pchan_for_action_group(ac, agrp, ale, true);
|
||||||
/* always clear active flag after doing this */
|
/* always clear active flag after doing this */
|
||||||
agrp->flag &= ~AGRP_ACTIVE;
|
agrp->flag &= ~AGRP_ACTIVE;
|
||||||
break;
|
break;
|
||||||
@@ -3172,6 +3239,70 @@ static int click_select_channel_scene(bAnimListElem *ale,
|
|||||||
return (ND_ANIMCHAN | NA_SELECTED);
|
return (ND_ANIMCHAN | NA_SELECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return whether active channel of given type is present. */
|
||||||
|
static bool animchannel_has_active_of_type(bAnimContext *ac, const eAnim_ChannelType type)
|
||||||
|
{
|
||||||
|
ListBase anim_data = anim_channels_for_selection(ac);
|
||||||
|
bool is_active_found = false;
|
||||||
|
|
||||||
|
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||||
|
if (ale->type != type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
is_active_found = ANIM_is_active_channel(ale);
|
||||||
|
if (is_active_found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ANIM_animdata_freelist(&anim_data);
|
||||||
|
return is_active_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select channels that lies between active channel and cursor_elem. */
|
||||||
|
static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem)
|
||||||
|
{
|
||||||
|
ListBase anim_data = anim_channels_for_selection(ac);
|
||||||
|
bool in_selection_range = false;
|
||||||
|
|
||||||
|
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||||
|
|
||||||
|
/* Allow selection when active channel and `cursor_elem` are of same type. */
|
||||||
|
if (ale->type != cursor_elem->type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool is_cursor_elem = (ale->data == cursor_elem->data);
|
||||||
|
const bool is_active_elem = ANIM_is_active_channel(ale);
|
||||||
|
|
||||||
|
/* Restrict selection when active element is not found and group-channels are excluded from the
|
||||||
|
* selection. */
|
||||||
|
if (is_active_elem || is_cursor_elem) {
|
||||||
|
/* Select first and last element from the range. Reverse selection status on extremes. */
|
||||||
|
ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD);
|
||||||
|
in_selection_range = !in_selection_range;
|
||||||
|
if (ale->type == ANIMTYPE_GROUP) {
|
||||||
|
select_pchan_for_action_group(ac, (bActionGroup *)ale->data, ale, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (in_selection_range) {
|
||||||
|
/* Select elements between the range. */
|
||||||
|
ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD);
|
||||||
|
if (ale->type == ANIMTYPE_GROUP) {
|
||||||
|
select_pchan_for_action_group(ac, (bActionGroup *)ale->data, ale, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_active_elem && is_cursor_elem) {
|
||||||
|
/* Selection range is only one element when active channel and clicked channel are same. So
|
||||||
|
* exit out of the loop when this condition is hit. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ANIM_animdata_freelist(&anim_data);
|
||||||
|
}
|
||||||
|
|
||||||
static int click_select_channel_object(bContext *C,
|
static int click_select_channel_object(bContext *C,
|
||||||
bAnimContext *ac,
|
bAnimContext *ac,
|
||||||
bAnimListElem *ale,
|
bAnimListElem *ale,
|
||||||
@@ -3195,8 +3326,13 @@ static int click_select_channel_object(bContext *C,
|
|||||||
adt->flag ^= ADT_UI_SELECTED;
|
adt->flag ^= ADT_UI_SELECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (selectmode == SELECT_EXTEND_RANGE) {
|
||||||
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE);
|
||||||
|
animchannel_select_range(ac, ale);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* deselect all */
|
/* deselect all */
|
||||||
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
||||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||||
/* TODO: should this deselect all other types of channels too? */
|
/* TODO: should this deselect all other types of channels too? */
|
||||||
LISTBASE_FOREACH (Base *, b, BKE_view_layer_object_bases_get(view_layer)) {
|
LISTBASE_FOREACH (Base *, b, BKE_view_layer_object_bases_get(view_layer)) {
|
||||||
@@ -3219,7 +3355,8 @@ static int click_select_channel_object(bContext *C,
|
|||||||
* to avoid getting stuck there, see: #48747. */
|
* to avoid getting stuck there, see: #48747. */
|
||||||
ED_object_base_activate_with_mode_exit_if_needed(C, base); /* adds notifier */
|
ED_object_base_activate_with_mode_exit_if_needed(C, base); /* adds notifier */
|
||||||
|
|
||||||
if ((adt) && (adt->flag & ADT_UI_SELECTED)) {
|
/* Similar to outliner, do not change active element when selecting elements in range.*/
|
||||||
|
if ((adt) && (adt->flag & ADT_UI_SELECTED) && (selectmode != SELECT_EXTEND_RANGE)) {
|
||||||
adt->flag |= ADT_UI_ACTIVE;
|
adt->flag |= ADT_UI_ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3239,14 +3376,18 @@ static int click_select_channel_dummy(bAnimContext *ac,
|
|||||||
/* inverse selection status of this AnimData block only */
|
/* inverse selection status of this AnimData block only */
|
||||||
ale->adt->flag ^= ADT_UI_SELECTED;
|
ale->adt->flag ^= ADT_UI_SELECTED;
|
||||||
}
|
}
|
||||||
|
else if (selectmode == SELECT_EXTEND_RANGE) {
|
||||||
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE);
|
||||||
|
animchannel_select_range(ac, ale);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* select AnimData block by itself */
|
/* select AnimData block by itself */
|
||||||
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
||||||
ale->adt->flag |= ADT_UI_SELECTED;
|
ale->adt->flag |= ADT_UI_SELECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set active? */
|
/* Similar to outliner, do not change active element when selecting elements in range. */
|
||||||
if (ale->adt->flag & ADT_UI_SELECTED) {
|
if ((ale->adt->flag & ADT_UI_SELECTED) && (selectmode != SELECT_EXTEND_RANGE)) {
|
||||||
ale->adt->flag |= ADT_UI_ACTIVE;
|
ale->adt->flag |= ADT_UI_ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3292,6 +3433,10 @@ static int click_select_channel_group(bAnimContext *ac,
|
|||||||
/* inverse selection status of this group only */
|
/* inverse selection status of this group only */
|
||||||
agrp->flag ^= AGRP_SELECTED;
|
agrp->flag ^= AGRP_SELECTED;
|
||||||
}
|
}
|
||||||
|
else if (selectmode == SELECT_EXTEND_RANGE) {
|
||||||
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE);
|
||||||
|
animchannel_select_range(ac, ale);
|
||||||
|
}
|
||||||
else if (selectmode == -1) {
|
else if (selectmode == -1) {
|
||||||
/* select all in group (and deselect everything else) */
|
/* select all in group (and deselect everything else) */
|
||||||
FCurve *fcu;
|
FCurve *fcu;
|
||||||
@@ -3318,17 +3463,22 @@ static int click_select_channel_group(bAnimContext *ac,
|
|||||||
agrp->flag |= AGRP_SELECTED;
|
agrp->flag |= AGRP_SELECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if group is selected now, make group the 'active' one in the visible list */
|
/* if group is selected now, make group the 'active' one in the visible list.
|
||||||
|
* Similar to outliner, do not change active element when selecting elements in range. */
|
||||||
if (agrp->flag & AGRP_SELECTED) {
|
if (agrp->flag & AGRP_SELECTED) {
|
||||||
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
|
if (selectmode != SELECT_EXTEND_RANGE) {
|
||||||
if (pchan) {
|
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
|
||||||
ED_pose_bone_select(ob, pchan, true);
|
if (pchan) {
|
||||||
|
ED_pose_bone_select(ob, pchan, true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP);
|
if (selectmode != SELECT_EXTEND_RANGE) {
|
||||||
if (pchan) {
|
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP);
|
||||||
ED_pose_bone_select(ob, pchan, false);
|
if (pchan) {
|
||||||
|
ED_pose_bone_select(ob, pchan, false, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3347,14 +3497,19 @@ static int click_select_channel_fcurve(bAnimContext *ac,
|
|||||||
/* inverse selection status of this F-Curve only */
|
/* inverse selection status of this F-Curve only */
|
||||||
fcu->flag ^= FCURVE_SELECTED;
|
fcu->flag ^= FCURVE_SELECTED;
|
||||||
}
|
}
|
||||||
|
else if (selectmode == SELECT_EXTEND_RANGE) {
|
||||||
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE);
|
||||||
|
animchannel_select_range(ac, ale);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* select F-Curve by itself */
|
/* select F-Curve by itself */
|
||||||
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
||||||
fcu->flag |= FCURVE_SELECTED;
|
fcu->flag |= FCURVE_SELECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
|
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list.
|
||||||
if (fcu->flag & FCURVE_SELECTED) {
|
* Similar to outliner, do not change active element when selecting elements in range. */
|
||||||
|
if ((fcu->flag & FCURVE_SELECTED) && (selectmode != SELECT_EXTEND_RANGE)) {
|
||||||
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
|
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3422,14 +3577,19 @@ static int click_select_channel_gplayer(bContext *C,
|
|||||||
/* invert selection status of this layer only */
|
/* invert selection status of this layer only */
|
||||||
gpl->flag ^= GP_LAYER_SELECT;
|
gpl->flag ^= GP_LAYER_SELECT;
|
||||||
}
|
}
|
||||||
|
else if (selectmode == SELECT_EXTEND_RANGE) {
|
||||||
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE);
|
||||||
|
animchannel_select_range(ac, ale);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* select layer by itself */
|
/* select layer by itself */
|
||||||
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
||||||
gpl->flag |= GP_LAYER_SELECT;
|
gpl->flag |= GP_LAYER_SELECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change active layer, if this is selected (since we must always have an active layer) */
|
/* change active layer, if this is selected (since we must always have an active layer).
|
||||||
if (gpl->flag & GP_LAYER_SELECT) {
|
* Similar to outliner, do not change active element when selecting elements in range. */
|
||||||
|
if ((gpl->flag & GP_LAYER_SELECT) && (selectmode != SELECT_EXTEND_RANGE)) {
|
||||||
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
|
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
|
||||||
/* update other layer status */
|
/* update other layer status */
|
||||||
BKE_gpencil_layer_active_set(gpd, gpl);
|
BKE_gpencil_layer_active_set(gpd, gpl);
|
||||||
@@ -3478,7 +3638,7 @@ static int click_select_channel_masklayer(bAnimContext *ac,
|
|||||||
static int mouse_anim_channels(bContext *C,
|
static int mouse_anim_channels(bContext *C,
|
||||||
bAnimContext *ac,
|
bAnimContext *ac,
|
||||||
const int channel_index,
|
const int channel_index,
|
||||||
const short /* eEditKeyframes_Select or -1 */ selectmode)
|
short /* eEditKeyframes_Select or -1 */ selectmode)
|
||||||
{
|
{
|
||||||
ListBase anim_data = {NULL, NULL};
|
ListBase anim_data = {NULL, NULL};
|
||||||
bAnimListElem *ale;
|
bAnimListElem *ale;
|
||||||
@@ -3516,6 +3676,11 @@ static int mouse_anim_channels(bContext *C,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Change selection mode to single when no active element is found. */
|
||||||
|
if ((selectmode == SELECT_EXTEND_RANGE) && !animchannel_has_active_of_type(ac, ale->type)) {
|
||||||
|
selectmode = SELECT_INVERT;
|
||||||
|
}
|
||||||
|
|
||||||
/* action to take depends on what channel we've got */
|
/* action to take depends on what channel we've got */
|
||||||
/* WARNING: must keep this in sync with the equivalent function in nla_channels.c */
|
/* WARNING: must keep this in sync with the equivalent function in nla_channels.c */
|
||||||
switch (ale->type) {
|
switch (ale->type) {
|
||||||
@@ -3619,6 +3784,9 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
|
|||||||
if (RNA_boolean_get(op->ptr, "extend")) {
|
if (RNA_boolean_get(op->ptr, "extend")) {
|
||||||
selectmode = SELECT_INVERT;
|
selectmode = SELECT_INVERT;
|
||||||
}
|
}
|
||||||
|
else if (RNA_boolean_get(op->ptr, "extend_range")) {
|
||||||
|
selectmode = SELECT_EXTEND_RANGE;
|
||||||
|
}
|
||||||
else if (RNA_boolean_get(op->ptr, "children_only")) {
|
else if (RNA_boolean_get(op->ptr, "children_only")) {
|
||||||
/* this is a bit of a special case for ActionGroups only...
|
/* this is a bit of a special case for ActionGroups only...
|
||||||
* should it be removed or extended to all instead? */
|
* should it be removed or extended to all instead? */
|
||||||
@@ -3672,6 +3840,13 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
|
|||||||
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
|
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
|
||||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||||
|
|
||||||
|
prop = RNA_def_boolean(ot->srna,
|
||||||
|
"extend_range",
|
||||||
|
false,
|
||||||
|
"Extend Range",
|
||||||
|
"Selection of active channel to clicked channel");
|
||||||
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||||
|
|
||||||
/* Key-map: Enable with `Ctrl-Shift`. */
|
/* Key-map: Enable with `Ctrl-Shift`. */
|
||||||
prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", "");
|
prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", "");
|
||||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void ED_pose_bone_select_tag_update(Object *ob)
|
|||||||
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
|
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
|
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, bool change_active)
|
||||||
{
|
{
|
||||||
bArmature *arm;
|
bArmature *arm;
|
||||||
|
|
||||||
@@ -109,11 +109,15 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
|
|||||||
/* change selection state - activate too if selected */
|
/* change selection state - activate too if selected */
|
||||||
if (select) {
|
if (select) {
|
||||||
pchan->bone->flag |= BONE_SELECTED;
|
pchan->bone->flag |= BONE_SELECTED;
|
||||||
arm->act_bone = pchan->bone;
|
if (change_active) {
|
||||||
|
arm->act_bone = pchan->bone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pchan->bone->flag &= ~BONE_SELECTED;
|
pchan->bone->flag &= ~BONE_SELECTED;
|
||||||
arm->act_bone = NULL;
|
if (change_active) {
|
||||||
|
arm->act_bone = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: select and activate corresponding vgroup? */
|
/* TODO: select and activate corresponding vgroup? */
|
||||||
|
|||||||
@@ -530,6 +530,8 @@ typedef enum eAnimChannels_SetFlag {
|
|||||||
ACHANNEL_SETFLAG_INVERT = 2,
|
ACHANNEL_SETFLAG_INVERT = 2,
|
||||||
/** some on -> all off / all on */
|
/** some on -> all off / all on */
|
||||||
ACHANNEL_SETFLAG_TOGGLE = 3,
|
ACHANNEL_SETFLAG_TOGGLE = 3,
|
||||||
|
/** turn off, keep active flag **/
|
||||||
|
ACHANNEL_SETFLAG_EXTEND_RANGE = 4,
|
||||||
} eAnimChannels_SetFlag;
|
} eAnimChannels_SetFlag;
|
||||||
|
|
||||||
/* types of settings for AnimChannels */
|
/* types of settings for AnimChannels */
|
||||||
@@ -698,6 +700,11 @@ void ANIM_set_active_channel(bAnimContext *ac,
|
|||||||
void *channel_data,
|
void *channel_data,
|
||||||
eAnim_ChannelType channel_type);
|
eAnim_ChannelType channel_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether channel is active.
|
||||||
|
*/
|
||||||
|
bool ANIM_is_active_channel(bAnimListElem *ale);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the F-Curve from the given AnimData block (if possible),
|
* Delete the F-Curve from the given AnimData block (if possible),
|
||||||
* as appropriate according to animation context.
|
* as appropriate according to animation context.
|
||||||
|
|||||||
@@ -356,8 +356,13 @@ bool ED_pose_deselect_all(struct Object *ob, int select_mode, bool ignore_visibi
|
|||||||
void ED_pose_bone_select_tag_update(struct Object *ob);
|
void ED_pose_bone_select_tag_update(struct Object *ob);
|
||||||
/**
|
/**
|
||||||
* Utility method for changing the selection status of a bone.
|
* Utility method for changing the selection status of a bone.
|
||||||
|
* change_active determines whether to change the active bone of the armature when selecting pose
|
||||||
|
* channels. It is false during range selection otherwise true.
|
||||||
*/
|
*/
|
||||||
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
|
void ED_pose_bone_select(struct Object *ob,
|
||||||
|
struct bPoseChannel *pchan,
|
||||||
|
bool select,
|
||||||
|
bool change_active);
|
||||||
|
|
||||||
/* meshlaplacian.cc */
|
/* meshlaplacian.cc */
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ typedef enum eEditKeyframes_Select {
|
|||||||
SELECT_SUBTRACT = (1 << 2),
|
SELECT_SUBTRACT = (1 << 2),
|
||||||
/* flip ok status of keyframes based on key status */
|
/* flip ok status of keyframes based on key status */
|
||||||
SELECT_INVERT = (1 << 3),
|
SELECT_INVERT = (1 << 3),
|
||||||
|
SELECT_EXTEND_RANGE = (1 << 4),
|
||||||
} eEditKeyframes_Select;
|
} eEditKeyframes_Select;
|
||||||
|
|
||||||
/* "selection map" building modes */
|
/* "selection map" building modes */
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ bool ED_object_jump_to_bone(bContext *C,
|
|||||||
|
|
||||||
/* Select it. */
|
/* Select it. */
|
||||||
ED_pose_deselect_all(ob, SEL_DESELECT, true);
|
ED_pose_deselect_all(ob, SEL_DESELECT, true);
|
||||||
ED_pose_bone_select(ob, pchan, true);
|
ED_pose_bone_select(ob, pchan, true, true);
|
||||||
|
|
||||||
arm->act_bone = pchan->bone;
|
arm->act_bone = pchan->bone;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user