Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/keyframes_edit.c87
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h6
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c2
-rw-r--r--source/blender/editors/space_graph/graph_select.c134
-rw-r--r--source/blender/editors/space_graph/space_graph.c3
-rw-r--r--source/blender/editors/transform/transform.c1
-rw-r--r--source/blender/editors/transform/transform.h6
-rw-r--r--source/blender/editors/transform/transform_convert.c40
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c208
-rw-r--r--source/blender/editors/transform/transform_generics.c2
10 files changed, 322 insertions, 167 deletions
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index f8328e9f07f..dc413e936eb 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -501,10 +501,16 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
ok |= KEYFRAME_OK_KEY; \
\
if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
- if (check(0)) \
- ok |= KEYFRAME_OK_H1; \
- if (check(2)) \
- ok |= KEYFRAME_OK_H2; \
+ /* Only act on visible items, so check handle visiblity state. */ \
+ const bool handles_visible = ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ? \
+ (BEZT_ISSEL_ANY(bezt)) : \
+ true); \
+ if (handles_visible) { \
+ if (check(0)) \
+ ok |= KEYFRAME_OK_H1; \
+ if (check(2)) \
+ ok |= KEYFRAME_OK_H2; \
+ } \
} \
} \
(void)0
@@ -1054,7 +1060,11 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
/* Sets the selected bezier handles to type 'auto' */
static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
+ /* If the key is selected, always apply to both handles. */
+ if (bezt->f2 & SELECT) {
+ bezt->h1 = bezt->h2 = HD_AUTO;
+ }
+ else {
if (bezt->f1 & SELECT) {
bezt->h1 = HD_AUTO;
}
@@ -1064,6 +1074,7 @@ static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
ENSURE_HANDLES_MATCH(bezt);
}
+
return 0;
}
@@ -1072,7 +1083,11 @@ static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
*/
static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
+ /* If the key is selected, always apply to both handles. */
+ if (bezt->f2 & SELECT) {
+ bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
+ }
+ else {
if (bezt->f1 & SELECT) {
bezt->h1 = HD_AUTO_ANIM;
}
@@ -1082,18 +1097,26 @@ static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *b
ENSURE_HANDLES_MATCH(bezt);
}
+
return 0;
}
/* Sets the selected bezier handles to type 'vector' */
static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- if (bezt->f1 & SELECT) {
- bezt->h1 = HD_VECT;
+ /* If the key is selected, always apply to both handles. */
+ if (bezt->f2 & SELECT) {
+ bezt->h1 = bezt->h2 = HD_VECT;
}
- if (bezt->f3 & SELECT) {
- bezt->h2 = HD_VECT;
+ else {
+ if (bezt->f1 & SELECT) {
+ bezt->h1 = HD_VECT;
+ }
+ if (bezt->f3 & SELECT) {
+ bezt->h2 = HD_VECT;
+ }
}
+
return 0;
}
@@ -1114,24 +1137,38 @@ static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
/* Sets selected bezier handles to type 'align' */
static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- if (bezt->f1 & SELECT) {
- bezt->h1 = HD_ALIGN;
+ /* If the key is selected, always apply to both handles. */
+ if (bezt->f2 & SELECT) {
+ bezt->h1 = bezt->h2 = HD_ALIGN;
}
- if (bezt->f3 & SELECT) {
- bezt->h2 = HD_ALIGN;
+ else {
+ if (bezt->f1 & SELECT) {
+ bezt->h1 = HD_ALIGN;
+ }
+ if (bezt->f3 & SELECT) {
+ bezt->h2 = HD_ALIGN;
+ }
}
+
return 0;
}
/* Sets selected bezier handles to type 'free' */
static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- if (bezt->f1 & SELECT) {
- bezt->h1 = HD_FREE;
+ /* If the key is selected, always apply to both handles. */
+ if (bezt->f2 & SELECT) {
+ bezt->h1 = bezt->h2 = HD_FREE;
}
- if (bezt->f3 & SELECT) {
- bezt->h2 = HD_FREE;
+ else {
+ if (bezt->f1 & SELECT) {
+ bezt->h1 = HD_FREE;
+ }
+ if (bezt->f3 & SELECT) {
+ bezt->h2 = HD_FREE;
+ }
}
+
return 0;
}
@@ -1422,8 +1459,13 @@ KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
{
+ /* Only act on visible items, so check handle visiblity state. */
+ const bool handles_visible = ked && ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ?
+ (BEZT_ISSEL_ANY(bezt)) :
+ true);
+
/* if we've got info on what to select, use it, otherwise select all */
- if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
+ if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES) && handles_visible) {
if (ked->curflags & KEYFRAME_OK_KEY) {
bezt->f2 |= SELECT;
}
@@ -1443,8 +1485,13 @@ static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
{
+ /* Only act on visible items, so check handle visiblity state. */
+ const bool handles_visible = ked && ((ked->iterflags & KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE) ?
+ (BEZT_ISSEL_ANY(bezt)) :
+ true);
+
/* if we've got info on what to deselect, use it, otherwise deselect all */
- if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
+ if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES) && handles_visible) {
if (ked->curflags & KEYFRAME_OK_KEY) {
bezt->f2 &= ~SELECT;
}
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 621a325eabd..8181cebfe3c 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -141,6 +141,12 @@ typedef enum eKeyframeIterFlags {
/* Perform NLA time remapping (global -> strip) for the "f2" parameter */
KED_F2_NLA_UNMAP = (1 << 2),
+
+ /* Set this when handles aren't visible by default and you want to perform additional checks to
+ * get the actual visibility state. E.g. in some cases handles are only drawn if either a handle
+ * or their control point is selected. The selection state will have to be checked in the
+ * iterator callbacks then. */
+ KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE = (1 << 3),
} eKeyframeIterFlags;
/* --- Generic Properties for Keyframe Edit Tools ----- */
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 33cb1cb0075..6c95e74e834 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -281,7 +281,7 @@ static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bez
bezt->h2 = HD_ALIGN;
}
else {
- BKE_nurb_bezt_handle_test(bezt, true);
+ BKE_nurb_bezt_handle_test(bezt, SELECT, true);
}
/* now call standard updates */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 4bd738fca95..9c1d63ef68a 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -552,6 +552,10 @@ static void box_select_graphkeys(bAnimContext *ac,
ked.data = &scaled_rectf;
}
+ if (sipo->flag & SIPO_SELVHANDLESONLY) {
+ ked.iterflags |= KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE;
+ }
+
/* treat handles separately? */
if (incl_handles) {
ked.iterflags |= KEYFRAME_ITER_INCL_HANDLES;
@@ -722,7 +726,7 @@ void GRAPH_OT_select_box(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
RNA_def_boolean(ot->srna,
"include_handles",
- 0,
+ true,
"Include Handles",
"Are handles tested individually against the selection criteria");
@@ -1417,23 +1421,42 @@ void GRAPH_OT_select_leftright(wmOperatorType *ot)
*/
/* option 1) select keyframe directly under mouse */
-static void mouse_graph_keys(bAnimContext *ac,
- const int mval[2],
- short select_mode,
- const bool deselect_all,
- const bool curves_only)
+static int mouse_graph_keys(bAnimContext *ac,
+ const int mval[2],
+ eEditKeyframes_Select select_mode,
+ const bool deselect_all,
+ const bool curves_only,
+ bool wait_to_deselect_others)
{
SpaceGraph *sipo = (SpaceGraph *)ac->sl;
tNearestVertInfo *nvi;
BezTriple *bezt = NULL;
+ bool run_modal = false;
/* find the beztriple that we're selecting, and the handle that was clicked on */
nvi = find_nearest_fcurve_vert(ac, mval);
+ if (select_mode != SELECT_REPLACE) {
+ /* The modal execution to delay deselecting other items is only needed for normal click
+ * selection, i.e. for SELECT_REPLACE. */
+ wait_to_deselect_others = false;
+ }
+
+ sipo->runtime.flag &= ~(SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT |
+ SIPO_RUNTIME_FLAG_TWEAK_HANDLES_RIGHT);
+
+ const bool already_selected =
+ (nvi != NULL) && (((nvi->hpoint == NEAREST_HANDLE_KEY) && (nvi->bezt->f2 & SELECT)) ||
+ ((nvi->hpoint == NEAREST_HANDLE_LEFT) && (nvi->bezt->f1 & SELECT)) ||
+ ((nvi->hpoint == NEAREST_HANDLE_RIGHT) && (nvi->bezt->f3 & SELECT)));
+
+ if (wait_to_deselect_others && nvi && already_selected) {
+ run_modal = true;
+ }
/* For replacing selection, if we have something to select, we have to clear existing selection.
* The same goes if we found nothing to select, and deselect_all is true
* (deselect on nothing behavior). */
- if ((nvi != NULL && select_mode == SELECT_REPLACE) || (nvi == NULL && deselect_all)) {
+ else if ((nvi != NULL && select_mode == SELECT_REPLACE) || (nvi == NULL && deselect_all)) {
/* reset selection mode */
select_mode = SELECT_ADD;
@@ -1450,7 +1473,7 @@ static void mouse_graph_keys(bAnimContext *ac,
}
if (nvi == NULL) {
- return;
+ return deselect_all ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
/* if points can be selected on this F-Curve */
@@ -1461,17 +1484,9 @@ static void mouse_graph_keys(bAnimContext *ac,
bezt = nvi->bezt; /* used to check bezt seletion is set */
/* depends on selection mode */
if (select_mode == SELECT_INVERT) {
- /* keyframe - invert select of all */
if (nvi->hpoint == NEAREST_HANDLE_KEY) {
- if (BEZT_ISSEL_ANY(bezt)) {
- BEZT_DESEL_ALL(bezt);
- }
- else {
- BEZT_SEL_ALL(bezt);
- }
+ bezt->f2 ^= SELECT;
}
-
- /* handles - toggle selection of relevant handle */
else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
/* toggle selection */
bezt->f1 ^= SELECT;
@@ -1482,11 +1497,9 @@ static void mouse_graph_keys(bAnimContext *ac,
}
}
else {
- /* if the keyframe was clicked on, select all verts of given beztriple */
if (nvi->hpoint == NEAREST_HANDLE_KEY) {
- BEZT_SEL_ALL(bezt);
+ bezt->f2 |= SELECT;
}
- /* otherwise, select the handle that applied */
else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
bezt->f1 |= SELECT;
}
@@ -1547,8 +1560,17 @@ static void mouse_graph_keys(bAnimContext *ac,
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
}
+ if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
+ sipo->runtime.flag |= SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT;
+ }
+ else if (nvi->hpoint == NEAREST_HANDLE_RIGHT) {
+ sipo->runtime.flag |= SIPO_RUNTIME_FLAG_TWEAK_HANDLES_RIGHT;
+ }
+
/* free temp sample data for filtering */
MEM_freeN(nvi);
+
+ return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
}
/* Option 2) Selects all the keyframes on either side of the current frame
@@ -1556,11 +1578,15 @@ static void mouse_graph_keys(bAnimContext *ac,
/* (see graphkeys_select_leftright) */
/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
-static void graphkeys_mselect_column(bAnimContext *ac, const int mval[2], short select_mode)
+static int graphkeys_mselect_column(bAnimContext *ac,
+ const int mval[2],
+ eEditKeyframes_Select select_mode,
+ bool wait_to_deselect_others)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+ bool run_modal = false;
KeyframeEditFunc select_cb, ok_cb;
KeyframeEditData ked;
@@ -1572,15 +1598,22 @@ static void graphkeys_mselect_column(bAnimContext *ac, const int mval[2], short
/* check if anything to select */
if (nvi == NULL) {
- return;
+ return OPERATOR_CANCELLED;
}
/* get frame number on which elements should be selected */
// TODO: should we restrict to integer frames only?
selx = nvi->frame;
- /* if select mode is replace, deselect all keyframes first */
- if (select_mode == SELECT_REPLACE) {
+ if (select_mode != SELECT_REPLACE) {
+ /* Doesn't need to deselect anything -> Pass. */
+ }
+ else if (wait_to_deselect_others && (nvi->bezt->f2 & SELECT)) {
+ run_modal = true;
+ }
+ /* If select mode is replace (and we don't do delayed deselection on mouse release), deselect all
+ * keyframes first. */
+ else {
/* reset selection mode to add to selection */
select_mode = SELECT_ADD;
@@ -1622,12 +1655,14 @@ static void graphkeys_mselect_column(bAnimContext *ac, const int mval[2], short
MEM_freeN(nvi);
BLI_freelistN(&ked.list);
ANIM_animdata_freelist(&anim_data);
+
+ return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED;
}
/* ------------------- */
/* handle clicking */
-static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int graphkeys_clickselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -1639,27 +1674,37 @@ static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEve
/* select mode is either replace (deselect all, then add) or add/extend */
const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ /* See #WM_operator_properties_generic_select() for a detailed description of the how and why of
+ * this. */
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
+ int mval[2];
+ int ret_val;
+
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
/* figure out action to take */
if (RNA_boolean_get(op->ptr, "column")) {
/* select all keyframes in the same frame as the one that was under the mouse */
- graphkeys_mselect_column(&ac, event->mval, selectmode);
+ ret_val = graphkeys_mselect_column(&ac, mval, selectmode, wait_to_deselect_others);
}
else if (RNA_boolean_get(op->ptr, "curves")) {
/* select all keyframes in the same F-Curve as the one under the mouse */
- mouse_graph_keys(&ac, event->mval, selectmode, deselect_all, true);
+ ret_val = mouse_graph_keys(&ac, mval, selectmode, deselect_all, true, wait_to_deselect_others);
}
else {
/* select keyframe under mouse */
- mouse_graph_keys(&ac, event->mval, selectmode, deselect_all, false);
+ ret_val = mouse_graph_keys(
+ &ac, mval, selectmode, deselect_all, false, wait_to_deselect_others);
}
- /* set notifier that keyframe selection (and also channel selection in some cases) has changed */
+ /* set notifier that keyframe selection (and also channel selection in some cases) has
+ * changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
/* for tweak grab to work */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_val | OPERATOR_PASS_THROUGH;
}
void GRAPH_OT_clickselect(wmOperatorType *ot)
@@ -1672,19 +1717,22 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
ot->description = "Select keyframes by clicking on them";
/* callbacks */
- ot->invoke = graphkeys_clickselect_invoke;
ot->poll = graphop_visible_keyframes_poll;
+ ot->exec = graphkeys_clickselect_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
- prop = RNA_def_boolean(
- ot->srna,
- "extend",
- 0,
- "Extend Select",
- "Toggle keyframe selection instead of leaving newly selected keyframes only"); // SHIFTKEY
+ WM_operator_properties_generic_select(ot);
+ prop = RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend Select",
+ "Toggle keyframe selection instead of leaving newly selected "
+ "keyframes only"); // SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
@@ -1694,12 +1742,12 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
"Deselect all when nothing under the cursor");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(
- ot->srna,
- "column",
- 0,
- "Column Select",
- "Select all keyframes that occur on the same frame as the one under the mouse"); // ALTKEY
+ prop = RNA_def_boolean(ot->srna,
+ "column",
+ 0,
+ "Column Select",
+ "Select all keyframes that occur on the same frame as the one under "
+ "the mouse"); // ALTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 95ad56a35e6..b8d9d3b791f 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -796,6 +796,9 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
ED_area_tag_redraw(sa);
}
+ sipo->runtime.flag &= ~(SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT |
+ SIPO_RUNTIME_FLAG_TWEAK_HANDLES_RIGHT);
+
/* init/adjust F-Curve colors */
graph_refresh_fcurve_colors(C);
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index b493bbe8867..f3d26f85471 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2359,6 +2359,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* Needed to translate tweak events to mouse buttons. */
t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
+ t->is_launch_event_tweak = event ? ISTWEAK(event->type) : false;
/* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate
* (which can have type = 0) */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 0264069c368..e5e7be025e4 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -213,7 +213,8 @@ typedef struct TransData2D {
float ih1[2], ih2[2];
} TransData2D;
-/** Used to store 2 handles for each #TransData in case the other handle wasn't selected. */
+/** Used to store 2 handles for each #TransData in case the other handle wasn't selected. Also to
+ * unset temporary flags. */
typedef struct TransDataCurveHandleFlags {
char ih1, ih2;
char *h1, *h2;
@@ -631,6 +632,9 @@ typedef struct TransInfo {
/*************** NEW STUFF *********************/
/** event type used to launch transform. */
short launch_event;
+ /** Is the actual launch event a tweak event? (launch_event above is set to the corresponding
+ * mouse button then.) */
+ bool is_launch_event_tweak;
struct {
/** Orientation type when when we're not constrained.
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 0c49d67f7a2..db8f36883f8 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -921,10 +921,17 @@ typedef struct tRetainedKeyframe {
size_t del_count; /* number of keyframes of this sort that have been deleted so far */
} tRetainedKeyframe;
-/* Called during special_aftertrans_update to make sure selected keyframes replace
+/**
+ * Called during special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on
+ * selection).
*/
-static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
+static void posttrans_fcurve_clean(FCurve *fcu,
+ const eBezTriple_Flag sel_flag,
+ const bool use_handle)
{
/* NOTE: We assume that all keys are sorted */
ListBase retained_keys = {NULL, NULL};
@@ -1036,7 +1043,7 @@ static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
}
/* 3) Recalculate handles */
- testhandles_fcurve(fcu, use_handle);
+ testhandles_fcurve(fcu, sel_flag, use_handle);
/* cleanup */
BLI_freelistN(&retained_keys);
@@ -1064,11 +1071,11 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
+ posttrans_fcurve_clean(ale->key_data, SELECT, false); /* only use handles in graph editor */
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
+ posttrans_fcurve_clean(ale->key_data, SELECT, false); /* only use handles in graph editor */
}
}
@@ -1090,7 +1097,7 @@ typedef struct BeztMap {
/* This function converts an FCurve's BezTriple array to a BeztMap array
* NOTE: this allocates memory that will need to get freed later
*/
-static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert, const short UNUSED(use_handle))
+static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert)
{
BezTriple *bezt = bezts;
BezTriple *prevbezt = NULL;
@@ -1118,7 +1125,7 @@ static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert, const short UNUS
}
/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
-static void sort_time_beztmaps(BeztMap *bezms, int totvert, const short UNUSED(use_handle))
+static void sort_time_beztmaps(BeztMap *bezms, int totvert)
{
BeztMap *bezm;
int i, ok = 1;
@@ -1163,8 +1170,7 @@ static void sort_time_beztmaps(BeztMap *bezms, int totvert, const short UNUSED(u
}
/* This function firstly adjusts the pointers that the transdata has to each BezTriple */
-static void beztmap_to_data(
- TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert, const short UNUSED(use_handle))
+static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert)
{
BezTriple *bezts = fcu->bezt;
BeztMap *bezm;
@@ -1270,9 +1276,9 @@ void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
/* adjust transform-data pointers */
/* note, none of these functions use 'use_handle', it could be removed */
- bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert, use_handle);
- sort_time_beztmaps(bezm, fcu->totvert, use_handle);
- beztmap_to_data(t, fcu, bezm, fcu->totvert, use_handle);
+ bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert);
+ sort_time_beztmaps(bezm, fcu->totvert);
+ beztmap_to_data(t, fcu, bezm, fcu->totvert);
/* free mapping stuff */
MEM_freeN(bezm);
@@ -1281,7 +1287,7 @@ void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
sort_time_fcurve(fcu);
/* make sure handles are all set correctly */
- testhandles_fcurve(fcu, use_handle);
+ testhandles_fcurve(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
}
}
}
@@ -1959,11 +1965,11 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
+ posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
}
else {
- posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
+ posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
}
}
}
@@ -2103,11 +2109,11 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if ((sipo->flag & SIPO_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, use_handle);
+ posttrans_fcurve_clean(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
}
else {
- posttrans_fcurve_clean(fcu, use_handle);
+ posttrans_fcurve_clean(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index f3d7592127c..f6f982e854a 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -156,21 +156,55 @@ static bool graph_edit_use_local_center(TransInfo *t)
return ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (graph_edit_is_translation_mode(t) == false));
}
+/**
+ * Get the effective selection of a triple for transform, i.e. return if the left handle, right
+ * handle and/or the center point should be affected by transform.
+ */
+static void graph_bezt_get_transform_selection(const TransInfo *t,
+ const BezTriple *bezt,
+ const bool use_handle,
+ bool *r_left_handle,
+ bool *r_key,
+ bool *r_right_handle)
+{
+ SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ bool key = (bezt->f2 & SELECT) != 0;
+ bool left = use_handle ? ((bezt->f1 & SELECT) != 0) : key;
+ bool right = use_handle ? ((bezt->f3 & SELECT) != 0) : key;
+
+ if (use_handle && t->is_launch_event_tweak) {
+ if (sipo->runtime.flag & SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT) {
+ key = right = false;
+ }
+ else if (sipo->runtime.flag & SIPO_RUNTIME_FLAG_TWEAK_HANDLES_RIGHT) {
+ left = key = false;
+ }
+ }
+
+ /* Whenever we move the key, we also move both handles. */
+ if (key) {
+ left = right = true;
+ }
+
+ *r_key = key;
+ *r_left_handle = left;
+ *r_right_handle = right;
+}
+
static void graph_key_shortest_dist(
TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
{
int j = 0;
TransData *td_iter = td_start;
+ bool sel_key, sel_left, sel_right;
td->dist = FLT_MAX;
for (; j < fcu->totvert; j++) {
BezTriple *bezt = fcu->bezt + j;
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+ graph_bezt_get_transform_selection(t, bezt, use_handle, &sel_left, &sel_key, &sel_right);
- if (sel1 || sel2 || sel3) {
+ if (sel_left || sel_key || sel_right) {
td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
}
@@ -179,6 +213,15 @@ static void graph_key_shortest_dist(
}
}
+/**
+ * It is important to note that this doesn't always act on the selection (like it's usually done),
+ * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
+ * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
+ * selected left or right handles accordingly.
+ * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
+ * functions may need to be made aware of this. It's ugly that these act based on selection state
+ * anyway.
+ */
void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
@@ -198,11 +241,11 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
BezTriple *bezt;
int count = 0, i;
float mtx[3][3], smtx[3][3];
- const bool is_translation_mode = graph_edit_is_translation_mode(t);
const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
const bool use_local_center = graph_edit_use_local_center(t);
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
+ bool sel_key, sel_left, sel_right;
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -253,33 +296,29 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
cfra = (float)CFRA;
}
- /* Only include BezTriples whose 'keyframe'
- * occurs on the same side of the current frame as mouse. */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ /* Only include BezTriples whose 'keyframe'
+ * occurs on the same side of the current frame as mouse. */
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+ graph_bezt_get_transform_selection(t, bezt, use_handle, &sel_left, &sel_key, &sel_right);
if (is_prop_edit) {
curvecount += 3;
- if (sel2 || sel1 || sel3) {
+ if (sel_key || sel_left || sel_right) {
selected = true;
}
}
else {
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- count++;
- }
+ if (sel_left) {
+ count++;
+ }
- if (sel3) {
- count++;
- }
+ if (sel_right) {
+ count++;
}
/* only include main vert if selected */
- if (sel2 && !use_local_center) {
+ if (sel_key && !use_local_center) {
count++;
}
}
@@ -366,19 +405,21 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
unit_scale = ANIM_unit_mapping_get_factor(
ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
- /* only include BezTriples whose 'keyframe' occurs on the same side
- * of the current frame as mouse (if applicable) */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+ /* Ensure temp flag is cleared for all triples, we use it. */
+ bezt->f1 &= ~BEZT_FLAG_TEMP_TAG;
+ bezt->f2 &= ~BEZT_FLAG_TEMP_TAG;
+ bezt->f3 &= ~BEZT_FLAG_TEMP_TAG;
+ /* only include BezTriples whose 'keyframe' occurs on the same side
+ * of the current frame as mouse (if applicable) */
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
TransDataCurveHandleFlags *hdata = NULL;
- /* short h1=1, h2=1; */ /* UNUSED */
+
+ graph_bezt_get_transform_selection(t, bezt, use_handle, &sel_left, &sel_key, &sel_right);
if (is_prop_edit) {
- bool is_sel = (sel2 || sel1 || sel3);
+ bool is_sel = (sel_key || sel_left || sel_right);
/* we always select all handles for proportional editing if central handle is selected */
initTransDataCurveHandles(td, bezt);
bezt_to_transdata(td++,
@@ -422,69 +463,69 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
smtx,
unit_scale,
offset);
+
+ if (is_sel) {
+ bezt->f1 |= BEZT_FLAG_TEMP_TAG;
+ bezt->f2 |= BEZT_FLAG_TEMP_TAG;
+ bezt->f3 |= BEZT_FLAG_TEMP_TAG;
+ }
}
else {
/* only include handles if selected, irrespective of the interpolation modes.
* also, only treat handles specially if the center point isn't selected.
*/
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 0,
- sel1,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* h1 = 0; */ /* UNUSED */
- }
+ if (sel_left) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 0,
+ sel_left,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ bezt->f1 |= BEZT_FLAG_TEMP_TAG;
+ }
- if (sel3) {
- if (hdata == NULL) {
- hdata = initTransDataCurveHandles(td, bezt);
- }
- bezt_to_transdata(td++,
- td2d++,
- tdg++,
- adt,
- bezt,
- 2,
- sel3,
- true,
- intvals,
- mtx,
- smtx,
- unit_scale,
- offset);
- }
- else {
- /* h2 = 0; */ /* UNUSED */
+ if (sel_right) {
+ if (hdata == NULL) {
+ hdata = initTransDataCurveHandles(td, bezt);
}
+ bezt_to_transdata(td++,
+ td2d++,
+ tdg++,
+ adt,
+ bezt,
+ 2,
+ sel_right,
+ true,
+ intvals,
+ mtx,
+ smtx,
+ unit_scale,
+ offset);
+ bezt->f3 |= BEZT_FLAG_TEMP_TAG;
}
/* only include main vert if selected */
- if (sel2 && !use_local_center) {
+ if (sel_key && !use_local_center) {
/* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) {
+ if (graph_edit_is_translation_mode(t)) {
+ if (sel_left) {
td->flag |= TD_MOVEHANDLE1;
}
- if (sel3) {
+ if (sel_right) {
td->flag |= TD_MOVEHANDLE2;
}
}
/* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
+ if (!(sel_left) || !(sel_right)) {
if (hdata == NULL) {
hdata = initTransDataCurveHandles(td, bezt);
}
@@ -496,13 +537,14 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
adt,
bezt,
1,
- sel2,
+ sel_key,
false,
intvals,
mtx,
smtx,
unit_scale,
offset);
+ bezt->f2 |= BEZT_FLAG_TEMP_TAG;
}
/* Special hack (must be done after #initTransDataCurveHandles(),
* as that stores handle settings to restore...):
@@ -513,7 +555,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
*/
if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
- if (hdata && (sel1) && (sel3)) {
+ if (hdata && (sel_left) && (sel_right)) {
bezt->h1 = HD_ALIGN;
bezt->h2 = HD_ALIGN;
}
@@ -523,7 +565,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
}
/* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
+ testhandles_fcurve(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
}
if (is_prop_edit) {
@@ -551,15 +593,13 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
cfra = (float)CFRA;
}
- /* only include BezTriples whose 'keyframe' occurs on the
- * same side of the current frame as mouse (if applicable) */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ /* only include BezTriples whose 'keyframe' occurs on the
+ * same side of the current frame as mouse (if applicable) */
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = (bezt->f2 & SELECT) != 0;
- const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
- const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+ graph_bezt_get_transform_selection(t, bezt, use_handle, &sel_left, &sel_key, &sel_right);
- if (sel1 || sel2) {
+ if (sel_left || sel_key) {
td->dist = td->rdist = 0.0f;
}
else {
@@ -567,7 +607,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
}
td++;
- if (sel2) {
+ if (sel_key) {
td->dist = td->rdist = 0.0f;
}
else {
@@ -575,7 +615,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
}
td++;
- if (sel3 || sel2) {
+ if (sel_right || sel_key) {
td->dist = td->rdist = 0.0f;
}
else {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 0df0b70a56a..548944e2d74 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -448,7 +448,7 @@ static void recalcData_graphedit(TransInfo *t)
dosort++;
}
else {
- calchandles_fcurve(fcu);
+ calchandles_fcurve_ex(fcu, BEZT_FLAG_TEMP_TAG);
}
/* set refresh tags for objects using this animation,