Curve: extend BKE_nurb_bezt_handle_test & BKE_nurb_handles_test

Replace use_handles with an enum that optionally uses handles
except when the vertex (knot) is selected in which case it behaves
as if both handles are selected.

Needed for nurb curves not to change handle type when only the
center point is selected (as is done in the graph editor).

No functional changes.
This commit is contained in:
Campbell Barton 2023-09-06 20:00:23 +10:00
parent ccaafa318d
commit 78b6ed19f3
8 changed files with 90 additions and 49 deletions

View File

@ -50,6 +50,21 @@ typedef struct CVKeyIndex {
bool switched;
} CVKeyIndex;
typedef enum eNurbHandleTest_Mode {
/** Read the selection from each handle. */
NURB_HANDLE_TEST_EACH = 1,
/**
* When the knot (center point) is selected treat the handles as selected too.
* Otherwise use the same behavior as #NURB_HANDLE_TEST_EACH.
*/
NURB_HANDLE_TEST_KNOT_OR_EACH = 2,
/**
* When the knot is selected, treat all handles as selected, otherwise none.
* \note Typically used when handles are hidden.
*/
NURB_HANDLE_TEST_KNOT_ONLY = 3,
} eNurbHandleTest_Mode;
#define KNOTSU(nu) \
((nu)->orderu + (nu)->pntsu + (((nu)->flagu & CU_NURB_CYCLIC) ? ((nu)->orderu - 1) : 0))
#define KNOTSV(nu) \
@ -340,6 +355,15 @@ void BKE_nurb_handle_smooth_fcurve(struct BezTriple *bezt, int total, bool cycli
void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, uint8_t flag);
/**
* Return a flag for the handles to treat as "selected":
* `1 << 0`, `1 << 1`, `1 << 2` map to handles 1 2 & 3.
*/
short BKE_nurb_bezt_handle_test_calc_flag(const BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const eNurbHandleTest_Mode handle_mode);
/**
* Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
* Thereby \a sel_flag defines what qualifies as selected.
@ -349,14 +373,15 @@ void BKE_nurb_handles_autocalc(struct Nurb *nu, uint8_t flag);
*
* \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).
* \param use_handle: Check selection state of individual handles, otherwise always update both
* handles if the key is selected.
* \param handle_mode: Interpret the selection base on modes in #eNurbHandleTest_Mode.
*/
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt,
eBezTriple_Flag__Alias sel_flag,
bool use_handle,
const eNurbHandleTest_Mode handle_mode,
bool use_around_local);
void BKE_nurb_handles_test(struct Nurb *nu, bool use_handles, bool use_around_local);
void BKE_nurb_handles_test(struct Nurb *nu,
eNurbHandleTest_Mode handle_mode,
bool use_around_local);
/* **** Depsgraph evaluation **** */

View File

@ -4032,32 +4032,49 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
}
}
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const bool use_handle,
const bool use_around_local)
{
short flag = 0;
#define SEL_F1 (1 << 0)
#define SEL_F2 (1 << 1)
#define SEL_F3 (1 << 2)
if (use_handle) {
if (bezt->f1 & sel_flag) {
flag |= SEL_F1;
}
if (bezt->f2 & sel_flag) {
flag |= SEL_F2;
}
if (bezt->f3 & sel_flag) {
flag |= SEL_F3;
}
}
else {
flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
}
short BKE_nurb_bezt_handle_test_calc_flag(const BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const eNurbHandleTest_Mode handle_mode)
{
short flag = 0;
switch (handle_mode) {
case NURB_HANDLE_TEST_KNOT_ONLY: {
flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
break;
}
case NURB_HANDLE_TEST_KNOT_OR_EACH:
if (bezt->f2 & sel_flag) {
flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
break;
}
[[fallthrough]];
case NURB_HANDLE_TEST_EACH: {
if (bezt->f1 & sel_flag) {
flag |= SEL_F1;
}
if (bezt->f2 & sel_flag) {
flag |= SEL_F2;
}
if (bezt->f3 & sel_flag) {
flag |= SEL_F3;
}
break;
}
}
return flag;
}
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const eNurbHandleTest_Mode handle_mode,
const bool use_around_local)
{
short flag = BKE_nurb_bezt_handle_test_calc_flag(bezt, sel_flag, handle_mode);
if (use_around_local) {
flag &= ~SEL_F2;
}
@ -4082,13 +4099,15 @@ void BKE_nurb_bezt_handle_test(BezTriple *bezt,
}
}
}
}
#undef SEL_F1
#undef SEL_F2
#undef SEL_F3
}
void BKE_nurb_handles_test(Nurb *nu, const bool use_handle, const bool use_around_local)
void BKE_nurb_handles_test(Nurb *nu,
const eNurbHandleTest_Mode handle_mode,
const bool use_around_local)
{
BezTriple *bezt;
int a;
@ -4100,7 +4119,7 @@ void BKE_nurb_handles_test(Nurb *nu, const bool use_handle, const bool use_aroun
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
BKE_nurb_bezt_handle_test(bezt, SELECT, use_handle, use_around_local);
BKE_nurb_bezt_handle_test(bezt, SELECT, handle_mode, use_around_local);
bezt++;
}

View File

@ -1314,7 +1314,8 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
BezTriple *bezt;
uint a;
for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle, false);
BKE_nurb_bezt_handle_test(
bezt, sel_flag, use_handle ? NURB_HANDLE_TEST_EACH : NURB_HANDLE_TEST_KNOT_ONLY, false);
}
/* Recalculate handles. */

View File

@ -289,7 +289,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, SELECT, true, false);
BKE_nurb_bezt_handle_test(bezt, SELECT, NURB_HANDLE_TEST_EACH, false);
}
/* now call standard updates */

View File

@ -1194,7 +1194,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (CU_IS_2D(cu)) {
BKE_nurb_project_2d(nu);
}
BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
BKE_nurb_handles_test(nu, NURB_HANDLE_TEST_EACH, false); /* test for bezier too */
}
}
else if ((ob->type == OB_LATTICE) && (apply_vcos || median_basis.lattice.weight)) {

View File

@ -33,19 +33,10 @@
* For the purpose of transform code we need to behave as if handles are selected,
* even when they aren't (see special case below).
*/
static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const bool hide_handles)
static int bezt_select_to_transform_triple_flag(const BezTriple *bezt,
const eNurbHandleTest_Mode handle_mode)
{
int flag = 0;
if (hide_handles) {
if (bezt->f2 & SELECT) {
flag = (1 << 0) | (1 << 1) | (1 << 2);
}
}
else {
flag = (((bezt->f1 & SELECT) ? (1 << 0) : 0) | ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
((bezt->f3 & SELECT) ? (1 << 2) : 0));
}
int flag = BKE_nurb_bezt_handle_test_calc_flag(bezt, SELECT, handle_mode);
/* Special case for auto & aligned handles:
* When a center point is being moved without the handles,
@ -83,6 +74,8 @@ static void createTransCurveVerts(bContext * /*C*/, TransInfo *t)
View3D *v3d = static_cast<View3D *>(t->view);
short hide_handles = (v3d != nullptr) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
false;
const eNurbHandleTest_Mode handle_mode = hide_handles ? NURB_HANDLE_TEST_KNOT_ONLY :
NURB_HANDLE_TEST_EACH;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
Curve *cu = static_cast<Curve *>(tc->obedit->data);
@ -99,7 +92,7 @@ static void createTransCurveVerts(bContext * /*C*/, TransInfo *t)
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, handle_mode);
if (bezt_tx & (SEL_F1 | SEL_F2 | SEL_F3)) {
if (bezt_tx & SEL_F1) {
countsel++;
@ -208,7 +201,7 @@ static void createTransCurveVerts(bContext * /*C*/, TransInfo *t)
}
/* Elements that will be transform (not always a match to selection). */
const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, handle_mode);
has_any_selected |= bezt_tx != 0;
if (is_prop_edit || bezt_tx & SEL_F1) {
@ -410,7 +403,7 @@ static void createTransCurveVerts(bContext * /*C*/, TransInfo *t)
ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
/* sets the handles based on their selection,
* do this after the data is copied to the TransData */
BKE_nurb_handles_test(nu, !hide_handles, use_around_origins_for_handles_test);
BKE_nurb_handles_test(nu, handle_mode, use_around_origins_for_handles_test);
}
}
}

View File

@ -357,8 +357,11 @@ static void createTransGPencil_curves(bContext *C,
/* Update the handle types so transformation is possible */
if (bezt_use && !ELEM(t->mode, TFM_GPENCIL_OPACITY, TFM_GPENCIL_SHRINKFATTEN)) {
BKE_nurb_bezt_handle_test(
bezt, SELECT, !hide_handles, use_around_origins_for_handles_test);
BKE_nurb_bezt_handle_test(bezt,
SELECT,
hide_handles ? NURB_HANDLE_TEST_KNOT_ONLY :
NURB_HANDLE_TEST_EACH,
use_around_origins_for_handles_test);
need_handle_recalc = true;
}
}

View File

@ -104,7 +104,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
if (CU_IS_2D(cu)) {
BKE_nurb_project_2d(nu);
}
BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
BKE_nurb_handles_test(nu, NURB_HANDLE_TEST_EACH, false); /* test for bezier too */
nu = nu->next;
}
}