Animation: Move Snapping to Scene #109015

Merged
Christoph Lendenfeld merged 35 commits from ChrisLend/blender:frame_snapping into main 2023-09-05 10:07:02 +02:00
22 changed files with 239 additions and 180 deletions

View File

@ -277,7 +277,14 @@ class DOPESHEET_HT_editor_buttons:
# Grease Pencil mode doesn't need snapping, as it's frame-aligned only
if st.mode != 'GPENCIL':
layout.prop(st, "auto_snap", text="")
row = layout.row(align=True)
row.prop(tool_settings, "use_snap_anim", text="")
sub = row.row(align=True)
sub.popover(
panel="DOPESHEET_PT_snapping",
icon='NONE',
text="Modes",
)
row = layout.row(align=True)
row.prop(tool_settings, "use_proportional_action", text="", icon_only=True)
@ -292,6 +299,21 @@ class DOPESHEET_HT_editor_buttons:
)
class DOPESHEET_PT_snapping(Panel):
bl_space_type = 'DOPESHEET_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Snapping"
def draw(self, context):
layout = self.layout
col = layout.column()
col.label(text="Snap To")
tool_settings = context.tool_settings
col.prop(tool_settings, "snap_anim_element", expand=True)
if tool_settings.snap_anim_element not in ('MARKER', ):
col.prop(tool_settings, "use_snap_time_absolute")
class DOPESHEET_PT_proportional_edit(Panel):
bl_space_type = 'DOPESHEET_EDITOR'
bl_region_type = 'HEADER'
@ -872,6 +894,7 @@ classes = (
DOPESHEET_PT_gpencil_layer_relations,
DOPESHEET_PT_gpencil_layer_display,
DOPESHEET_PT_custom_props_action,
DOPESHEET_PT_snapping
)
if __name__ == "__main__": # only for live edit.

View File

@ -49,7 +49,14 @@ class GRAPH_HT_header(Header):
layout.prop(st, "pivot_point", icon_only=True)
layout.prop(st, "auto_snap", text="")
row = layout.row(align=True)
row.prop(tool_settings, "use_snap_anim", text="")
sub = row.row(align=True)
sub.popover(
panel="GRAPH_PT_snapping",
icon='NONE',
text="Modes",
)
row = layout.row(align=True)
row.prop(tool_settings, "use_proportional_fcurve", text="", icon_only=True)
@ -94,6 +101,20 @@ class GRAPH_PT_filters(DopesheetFilterPopoverBase, Panel):
layout.separator()
DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
class GRAPH_PT_snapping(Panel):
bl_space_type = 'GRAPH_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Snapping"
def draw(self, context):
layout = self.layout
col = layout.column()
col.label(text="Snap To")
tool_settings = context.tool_settings
col.prop(tool_settings, "snap_anim_element", expand=True)
if tool_settings.snap_anim_element not in ('MARKER', ):
col.prop(tool_settings, "use_snap_time_absolute")
class GRAPH_MT_editor_menus(Menu):
bl_idname = "GRAPH_MT_editor_menus"
@ -527,6 +548,7 @@ classes = (
GRAPH_MT_snap_pie,
GRAPH_MT_view_pie,
GRAPH_PT_filters,
GRAPH_PT_snapping,
)
if __name__ == "__main__": # only for live edit.

View File

@ -33,7 +33,30 @@ class NLA_HT_header(Header):
icon='FILTER',
)
layout.prop(st, "auto_snap", text="")
row = layout.row(align=True)
tool_settings = context.tool_settings
row.prop(tool_settings, "use_snap_anim", text="")
sub = row.row(align=True)
sub.popover(
panel="NLA_PT_snapping",
icon='NONE',
text="Modes",
)
class NLA_PT_snapping(Panel):
bl_space_type = 'NLA_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Snapping"
def draw(self, context):
layout = self.layout
col = layout.column()
col.label(text="Snap To")
tool_settings = context.tool_settings
col.prop(tool_settings, "snap_anim_element", expand=True)
if tool_settings.snap_anim_element not in ('MARKER', ):
col.prop(tool_settings, "use_snap_time_absolute")
class NLA_PT_filters(DopesheetFilterPopoverBase, Panel):
@ -350,6 +373,7 @@ classes = (
NLA_MT_channel_context_menu,
NLA_PT_filters,
NLA_PT_action,
NLA_PT_snapping,
)
if __name__ == "__main__": # only for live edit.

View File

@ -969,6 +969,11 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
scene->eevee.gi_irradiance_pool_size = 16;
}
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->toolsettings->snap_flag_anim |= SCE_SNAP;
scene->toolsettings->snap_anim_mode |= SCE_SNAP_TO_FRAME;
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 20)) {

View File

@ -62,7 +62,6 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
saction = MEM_cnew<SpaceAction>("initaction");
saction->spacetype = SPACE_ACTION;
saction->autosnap = SACTSNAP_FRAME;
saction->mode = SACTCONT_DOPESHEET;
saction->mode_prev = SACTCONT_DOPESHEET;
saction->flag = SACTION_SHOW_INTERPOLATION | SACTION_SHOW_MARKERS;

View File

@ -62,8 +62,6 @@ static SpaceLink *graph_create(const ScrArea * /*area*/, const Scene *scene)
sipo = static_cast<SpaceGraph *>(MEM_callocN(sizeof(SpaceGraph), "init graphedit"));
sipo->spacetype = SPACE_GRAPH;
sipo->autosnap = SACTSNAP_FRAME;
/* allocate DopeSheet data for Graph Editor */
sipo->ads = static_cast<bDopeSheet *>(MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"));
sipo->ads->source = (ID *)scene;

View File

@ -57,7 +57,6 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene)
snla->ads->source = (ID *)(scene);
/* set auto-snapping settings */
snla->autosnap = SACTSNAP_FRAME;
snla->flag = SNLA_SHOW_MARKERS;
/* header */

View File

@ -820,6 +820,20 @@ static void flushTransIntFrameActionData(TransInfo *t)
}
}
static void invert_snap(eSnapMode &snap_mode)

Add a comment that explains what this 'inversion' is for. I had to read about the "CTRL key to switch between seconds & frames" behaviour of 3.6 that you put in the PR description to know this was a thing (so 👍 for putting it there), and I think it'll be helpful for future devs (including future us) if this info is actually in the source.

Add a comment that explains what this 'inversion' is for. I had to read about the "CTRL key to switch between seconds & frames" behaviour of 3.6 that you put in the PR description to know this was a thing (so :+1: for putting it there), and I think it'll be helpful for future devs (including future us) if this info is actually in the source.
{
/* Make snapping work like before 4.0 where pressing CTRL will switch between snapping to seconds
* and frames. */
if (snap_mode & SCE_SNAP_TO_FRAME) {
snap_mode &= ~SCE_SNAP_TO_FRAME;
snap_mode |= SCE_SNAP_TO_SECOND;
}
else if (snap_mode & SCE_SNAP_TO_SECOND) {
snap_mode &= ~SCE_SNAP_TO_SECOND;
snap_mode |= SCE_SNAP_TO_FRAME;
}
}
static void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
@ -853,13 +867,17 @@ static void recalcData_actedit(TransInfo *t)
/* Flush 2d vector. */
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
const short autosnap = getAnimEdit_SnapMode(t);
eSnapMode snap_mode = t->tsnap.mode;
if (t->modifiers & MOD_SNAP_INVERT) {
invert_snap(snap_mode);
}
TransData *td;
TransData2D *td2d;
int i = 0;
for (td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
transform_snap_anim_flush_data(t, td, eAnimEdit_AutoSnap(autosnap), td->loc);
if ((t->tsnap.flag & SCE_SNAP) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
}
/* Constrain Y. */

View File

@ -644,6 +644,18 @@ static bool fcu_test_selected(FCurve *fcu)
return false;
}
static void invert_snap(eSnapMode &snap_mode)
{
if (snap_mode & SCE_SNAP_TO_FRAME) {
snap_mode &= ~SCE_SNAP_TO_FRAME;
snap_mode |= SCE_SNAP_TO_SECOND;
}
else if (snap_mode & SCE_SNAP_TO_SECOND) {
snap_mode &= ~SCE_SNAP_TO_SECOND;
snap_mode |= SCE_SNAP_TO_FRAME;
}
}
/* This function is called on recalc_data to apply the transforms applied
* to the transdata on to the actual keyframe data
*/
@ -654,9 +666,13 @@ static void flushTransGraphData(TransInfo *t)
TransDataGraph *tdg;
int a;
const short autosnap = getAnimEdit_SnapMode(t);
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
eSnapMode snap_mode = t->tsnap.mode;
if (t->modifiers & MOD_SNAP_INVERT) {
invert_snap(snap_mode);
}
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* flush to 2d vector from internally used 3d vector */
for (a = 0,
td = tc->data,
@ -675,8 +691,8 @@ static void flushTransGraphData(TransInfo *t)
* - Only apply to keyframes (but never to handles).
* - Don't do this when canceling, or else these changes won't go away.
*/
if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
transform_snap_anim_flush_data(t, td, eAnimEdit_AutoSnap(autosnap), td->loc);
if ((t->tsnap.flag & SCE_SNAP) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) {
transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
}
/* we need to unapply the nla-mapping from the time in some situations */

View File

@ -629,6 +629,18 @@ static void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
static void invert_snap(eSnapMode &snap_mode)
{
if (snap_mode & SCE_SNAP_TO_FRAME) {
snap_mode &= ~SCE_SNAP_TO_FRAME;
snap_mode |= SCE_SNAP_TO_SECOND;
}
else if (snap_mode & SCE_SNAP_TO_SECOND) {
snap_mode &= ~SCE_SNAP_TO_SECOND;
snap_mode |= SCE_SNAP_TO_FRAME;
}
}
static void recalcData_nla(TransInfo *t)
{
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
@ -639,11 +651,14 @@ static void recalcData_nla(TransInfo *t)
* NOTE: only do this when transform is still running, or we can't restore
*/
if (t->state != TRANS_CANCEL) {
const short autosnap = getAnimEdit_SnapMode(t);
if (autosnap != SACTSNAP_OFF) {
if (t->tsnap.flag & SCE_SNAP) {
eSnapMode snap_mode = t->tsnap.mode;
if (t->modifiers & MOD_SNAP_INVERT) {
invert_snap(snap_mode);
}
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
transform_snap_anim_flush_data(t, td, eAnimEdit_AutoSnap(autosnap), td->loc);
transform_snap_anim_flush_data(t, td, snap_mode, td->loc);
}
}
}

View File

@ -43,30 +43,26 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
const short autosnap = getAnimEdit_SnapMode(t);
eSnapMode snap_mode = t->tsnap.mode;
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
float val = ival + t->values_final[0];
snapFrameTransform(t, eAnimEdit_AutoSnap(autosnap), ival, val, &val);
snapFrameTransform(t, snap_mode, ival, val, &val);
float delta_x = val - ival;
if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) {
if (snap_mode == SCE_SNAP_TO_SECOND) {
nathanvegdahl marked this conversation as resolved Outdated

Probably this can just be snap_mode == SCE_SNAP_TO_SECOND now.

Probably this can just be `snap_mode == SCE_SNAP_TO_SECOND` now.
/* Convert to seconds. */
const Scene *scene = t->scene;
const double secf = FPS;
delta_x /= secf;
val /= secf;
delta_x /= FPS;
val /= FPS;
}
if (autosnap == SACTSNAP_FRAME) {
if (snap_mode == SCE_SNAP_TO_FRAME) {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_SECOND) {
else if (snap_mode == SCE_SNAP_TO_SECOND) {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_TSTEP) {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x);
}
else {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x);
}

View File

@ -212,10 +212,10 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
/* WORKAROUND:
* Special case where snapping is done in #recalData.
* Update the header based on the #center_local. */
const short autosnap = getAnimEdit_SnapMode(t);
eSnapMode autosnap = t->tsnap.mode;
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0];
float val = ival + dvec[0];
snapFrameTransform(t, eAnimEdit_AutoSnap(autosnap), ival, val, &val);
snapFrameTransform(t, autosnap, ival, val, &val);
dvec[0] = val - ival;
}

View File

@ -128,6 +128,10 @@ bool validSnap(const TransInfo *t)
void transform_snap_flag_from_modifiers_set(TransInfo *t)
{
if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) {
/* Those spacetypes define their own invert behaviour instead of toggling it on/off. */
return;
}
SET_FLAG_FROM_TEST(t->tsnap.flag,
(((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) ||
((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT)),
@ -151,7 +155,7 @@ bool transformModeUseSnap(const TransInfo *t)
if (t->mode == TFM_RESIZE) {
return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_SCALE) != 0;
}
if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE, TFM_SEQ_SLIDE)) {
if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
return true;
}
@ -164,11 +168,6 @@ static bool doForceIncrementSnap(const TransInfo *t)
return false;
}
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
/* No incremental snapping. */
return false;
}
return !transformModeUseSnap(t);
}
@ -632,9 +631,7 @@ static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
case SPACE_GRAPH:
case SPACE_ACTION:
case SPACE_NLA:
/* These editors have their own "Auto-Snap" activation option.
* See #getAnimEdit_SnapMode. */
return eSnapFlag(0);
return eSnapFlag(ts->snap_flag_anim);
}
/* #SPACE_EMPTY.
* It can happen when the operator is called via a handle in `bpy.app.handlers`. */
@ -680,9 +677,8 @@ static eSnapMode snap_mode_from_spacetype(TransInfo *t)
return snap_mode;
}
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
/* No incremental snapping. */
return eSnapMode(0);
if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_GRAPH)) {
return eSnapMode(ts->snap_anim_mode);
}
return SCE_SNAP_TO_INCREMENT;

View File

@ -11,6 +11,7 @@
#define SNAP_MIN_DISTANCE 30
/* For enum. */
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
bool peelObjectsTransform(TransInfo *t,
@ -73,25 +74,14 @@ void transform_snap_sequencer_data_free(TransSeqSnapData *data);
bool transform_snap_sequencer_calc(TransInfo *t);
void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
/* `transform_snap_animation.cc` */
/**
* This function returns the snapping 'mode' for Animation Editors only.
* We cannot use the standard snapping due to NLA-strip scaling complexities.
*
* TODO: these modifier checks should be accessible from the key-map.
*/
short getAnimEdit_SnapMode(TransInfo *t);
void snapFrameTransform(TransInfo *t,
eAnimEdit_AutoSnap autosnap,
float val_initial,
float val_final,
float *r_val_final);
/* transform_snap_animation.cc */
void snapFrameTransform(
TransInfo *t, eSnapMode autosnap, float val_initial, float val_final, float *r_val_final);
nathanvegdahl marked this conversation as resolved
Review

Would it be worth taking the time to switch from r_val_final to just returning the value? (transform_snap_anim_flush_data() is also like this.) Maybe not—maybe better as a separate clean up PR.

Would it be worth taking the time to switch from `r_val_final` to just returning the value? (`transform_snap_anim_flush_data()` is also like this.) Maybe not—maybe better as a separate clean up PR.

yes but I agree this should be in a separate PR

yes but I agree this should be in a separate PR
/**
* This function is used by Animation Editor specific transform functions to do
* the Snap Keyframe to Nearest Frame/Marker
*/
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
eAnimEdit_AutoSnap autosnap,
eSnapMode autosnap,
float *r_val_final);

View File

@ -21,96 +21,59 @@
/** \name Snapping in Anim Editors
* \{ */
short getAnimEdit_SnapMode(TransInfo *t)
{
short autosnap = SACTSNAP_OFF;
if (t->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
if (saction) {
autosnap = saction->autosnap;
}
}
else if (t->spacetype == SPACE_GRAPH) {
if ((t->mode == TFM_TRANSLATION) && transform_snap_is_active(t)) {
return autosnap;
}
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
if (sipo) {
autosnap = sipo->autosnap;
}
}
else if (t->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
if (snla) {
autosnap = snla->autosnap;
}
}
else {
autosnap = SACTSNAP_OFF;
}
/* toggle autosnap on/off
* - when toggling on, prefer nearest frame over 1.0 frame increments
*/
if (t->modifiers & MOD_SNAP_INVERT) {
if (autosnap) {
autosnap = SACTSNAP_OFF;
}
else {
autosnap = SACTSNAP_FRAME;
}
}
return autosnap;
}
void snapFrameTransform(TransInfo *t,
const eAnimEdit_AutoSnap autosnap,
const eSnapMode snap_mode,
const float val_initial,
const float val_final,
float *r_val_final)
{
float deltax = val_final - val_initial;
switch (autosnap) {
case SACTSNAP_FRAME:
*r_val_final = floorf(val_final + 0.5f);
break;
case SACTSNAP_MARKER:
/* Snap to nearest marker. */
/* TODO: need some more careful checks for where data comes from. */
*r_val_final = float(ED_markers_find_nearest_marker_time(&t->scene->markers, val_final));
break;
case SACTSNAP_SECOND:
case SACTSNAP_TSTEP: {
const Scene *scene = t->scene;
const double secf = FPS;
if (autosnap == SACTSNAP_SECOND) {
*r_val_final = floorf((val_final / secf) + 0.5) * secf;
/* This is needed for the FPS macro. */
const Scene *scene = t->scene;
const eSnapFlag snap_flag = t->tsnap.flag;
switch (snap_mode) {
case SCE_SNAP_TO_FRAME: {
if (snap_flag & SCE_SNAP_ABS_TIME_STEP) {
*r_val_final = floorf(val_final + 0.5f);
}
else {
deltax = float(floor((deltax / secf) + 0.5) * secf);
deltax = floorf(deltax + 0.5f);
*r_val_final = val_initial + deltax;
}
break;
}
case SACTSNAP_STEP:
deltax = floorf(deltax + 0.5f);
*r_val_final = val_initial + deltax;
case SCE_SNAP_TO_SECOND: {
if (snap_flag & SCE_SNAP_ABS_TIME_STEP) {
*r_val_final = floorf((val_final / FPS) + 0.5) * FPS;
}
else {
deltax = float(floor((deltax / FPS) + 0.5) * FPS);
*r_val_final = val_initial + deltax;
}
break;
case SACTSNAP_OFF:
}
case SCE_SNAP_TO_MARKERS: {
/* Snap to nearest marker. */
/* TODO: need some more careful checks for where data comes from. */
const float nearest_marker_time = float(
ED_markers_find_nearest_marker_time(&t->scene->markers, val_final));
*r_val_final = nearest_marker_time;
break;
}
default: {
*r_val_final = val_final;
break;
}
}
}
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eAnimEdit_AutoSnap autosnap,
const eSnapMode snap_mode,
float *r_val_final)
{
BLI_assert(autosnap != SACTSNAP_OFF);
BLI_assert(t->tsnap.flag);
float val = td->loc[0];
float ival = td->iloc[0];
@ -123,7 +86,7 @@ void transform_snap_anim_flush_data(TransInfo *t,
ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
}
snapFrameTransform(t, autosnap, ival, val, &val);
snapFrameTransform(t, snap_mode, ival, val, &val);
/* Convert frame out of nla-action time. */
if (adt) {

View File

@ -853,8 +853,8 @@ typedef struct SpaceAction {
char mode;
/* Storage for sub-space types. */
char mode_prev;
/** Automatic keyframe snapping mode. */
char autosnap;
/* Snapping now lives on the Scene. */
char autosnap DNA_DEPRECATED;
/** (eTimeline_Cache_Flag). */
char cache_display;
char _pad1[6];
@ -917,10 +917,8 @@ typedef enum eAnimEdit_Context {
SACTCONT_TIMELINE = 6,
} eAnimEdit_Context;
/* SpaceAction AutoSnap Settings (also used by other Animation Editors) */
/* Old snapping enum that is only needed because of the versioning code. */
typedef enum eAnimEdit_AutoSnap {
/* no auto-snap */
SACTSNAP_OFF = 0,
/* snap to 1.0 frame/second intervals */
SACTSNAP_STEP = 1,
/* snap to actual frames/seconds (nla-action time) */
@ -931,7 +929,7 @@ typedef enum eAnimEdit_AutoSnap {
SACTSNAP_SECOND = 4,
/* snap to 1.0 second increments */
SACTSNAP_TSTEP = 5,
} eAnimEdit_AutoSnap;
} eAnimEdit_AutoSnap DNA_DEPRECATED;
/* SAction->cache_display */
typedef enum eTimeline_Cache_Flag {

View File

@ -365,7 +365,9 @@
.snap_mode = SCE_SNAP_TO_INCREMENT, \
.snap_node_mode = SCE_SNAP_TO_GRID, \
.snap_uv_mode = SCE_SNAP_TO_INCREMENT, \
.snap_anim_mode = SCE_SNAP_TO_FRAME, \
.snap_flag = SCE_SNAP_TO_INCLUDE_EDITED | SCE_SNAP_TO_INCLUDE_NONEDITED, \
.snap_flag_anim = SCE_SNAP, \
.snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE, \
.snap_face_nearest_steps = 1, \
\

View File

@ -1639,11 +1639,14 @@ typedef struct ToolSettings {
short snap_mode;
char snap_node_mode;
char snap_uv_mode;
short snap_anim_mode;
/** Generic flags (per space-type), #eSnapFlag. */
short snap_flag;
short snap_flag_node;
short snap_flag_seq;
short snap_flag_anim;
short snap_uv_flag;
char _pad[4];
/** Default snap source, #eSnapSourceOP. */
/**
* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
@ -2324,6 +2327,8 @@ typedef enum eSnapFlag {
/** Was `SCE_SNAP_NO_SELF`, but self should be active. */
SCE_SNAP_NOT_TO_ACTIVE = (1 << 4),
SCE_SNAP_ABS_GRID = (1 << 5),
/* Same value with different name to make it easier to understand in time based code. */
SCE_SNAP_ABS_TIME_STEP = (1 << 5),
SCE_SNAP_BACKFACE_CULLING = (1 << 6),
SCE_SNAP_KEEP_ON_SAME_OBJECT = (1 << 7),
/** see #eSnapTargetOP */
@ -2383,11 +2388,17 @@ typedef enum eSnapMode {
/** For snap individual elements. */
SCE_SNAP_INDIVIDUAL_NEAREST = (1 << 8),
SCE_SNAP_INDIVIDUAL_PROJECT = (1 << 9),
/** #ToolSettings::snap_anim_mode */
SCE_SNAP_TO_FRAME = (1 << 10),
SCE_SNAP_TO_SECOND = (1 << 11),
SCE_SNAP_TO_MARKERS = (1 << 12),
} eSnapMode;
/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
/* TODO: move this macro to a more general place. */
#ifdef ENUM_OPERATORS
ENUM_OPERATORS(eSnapMode, SCE_SNAP_INDIVIDUAL_PROJECT)
ENUM_OPERATORS(eSnapMode, SCE_SNAP_TO_MARKERS)
#endif
#define SCE_SNAP_TO_VERTEX (SCE_SNAP_TO_POINT | SCE_SNAP_TO_EDGE_ENDPOINT)

View File

@ -470,11 +470,8 @@ typedef struct SpaceGraph {
/** Mode for the Graph editor (eGraphEdit_Mode). */
short mode;
/**
* Time-transform auto-snapping settings for Graph editor
* (eAnimEdit_AutoSnap in DNA_action_types.h).
*/
short autosnap;
/* Snapping now lives on the Scene. */
short autosnap DNA_DEPRECATED;
/** Settings for Graph editor (eGraphEdit_Flag). */
int flag;

👍 for pointing to the new location.

:+1: for pointing to the new location.
@ -560,8 +557,8 @@ typedef struct SpaceNla {
char _pad0[6];
/* End 'SpaceLink' header. */
/** This uses the same settings as autosnap for Action Editor. */
short autosnap;
/* Snapping now lives on the Scene. */
short autosnap DNA_DEPRECATED;
short flag;
char _pad[4];

View File

@ -28,6 +28,7 @@ DEF_ENUM(rna_enum_proportional_falloff_curve_only_items)
DEF_ENUM(rna_enum_snap_source_items)
DEF_ENUM(rna_enum_snap_element_items)
DEF_ENUM(rna_enum_snap_node_element_items)
DEF_ENUM(rna_enum_snap_animation_element_items)
DEF_ENUM(rna_enum_curve_fit_method_items)
DEF_ENUM(rna_enum_mesh_select_mode_items)
DEF_ENUM(rna_enum_mesh_select_mode_uv_items)

View File

@ -201,6 +201,13 @@ const EnumPropertyItem rna_enum_snap_node_element_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_enum_snap_animation_element_items[] = {
{SCE_SNAP_TO_FRAME, "FRAME", 0, "Frame", "Snap to frame"},
{SCE_SNAP_TO_SECOND, "SECOND", 0, "Second", "Snap to seconds"},
{SCE_SNAP_TO_MARKERS, "MARKER", 0, "Nearest Marker", "Snap to nearest marker"},
{0, nullptr, 0, nullptr, nullptr},
};
#ifndef RNA_RUNTIME
static const EnumPropertyItem snap_uv_element_items[] = {
{SCE_SNAP_TO_INCREMENT,
@ -3449,6 +3456,24 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Snap Node Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr); /* header redraw */
prop = RNA_def_property(srna, "use_snap_anim", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag_anim", SCE_SNAP);
RNA_def_property_ui_text(prop, "Snap", "Enable snapping when transforming keyframes");
RNA_def_property_ui_icon(prop, ICON_SNAP_OFF, 1);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_time_absolute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "snap_flag_anim", SCE_SNAP_ABS_TIME_STEP);
RNA_def_property_ui_text(
prop, "Absolute Time Snap", "Absolute time alignment while translating");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr); /* header redraw */
prop = RNA_def_property(srna, "snap_anim_element", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, nullptr, "snap_anim_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_animation_element_items);
RNA_def_property_ui_text(prop, "Snap Anim Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr); /* header redraw */
/* image editor uses own set of snap modes */
prop = RNA_def_property(srna, "snap_uv_element", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, nullptr, "snap_uv_mode");

View File

@ -392,21 +392,6 @@ static const EnumPropertyItem display_channels_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
#ifndef RNA_RUNTIME
static const EnumPropertyItem autosnap_items[] = {
{SACTSNAP_OFF, "NONE", 0, "No Auto-Snap", ""},
/* {-1, "", 0, "", ""}, */
{SACTSNAP_STEP, "STEP", 0, "Frame Step", "Snap to 1.0 frame intervals"},
{SACTSNAP_TSTEP, "TIME_STEP", 0, "Second Step", "Snap to 1.0 second intervals"},
/* {-1, "", 0, "", ""}, */
{SACTSNAP_FRAME, "FRAME", 0, "Nearest Frame", "Snap to actual frames (nla-action time)"},
{SACTSNAP_SECOND, "SECOND", 0, "Nearest Second", "Snap to actual seconds (nla-action time)"},
/* {-1, "", 0, "", ""}, */
{SACTSNAP_MARKER, "MARKER", 0, "Nearest Marker", "Snap to nearest marker"},
{0, nullptr, 0, nullptr, nullptr},
};
#endif
const EnumPropertyItem rna_enum_shading_type_items[] = {
{OB_WIRE, "WIREFRAME", ICON_SHADING_WIRE, "Wireframe", "Display the object as wire edges"},
{OB_SOLID, "SOLID", ICON_SHADING_SOLID, "Solid", "Display in solid mode"},
@ -6283,14 +6268,6 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, nullptr, "ads");
RNA_def_property_ui_text(prop, "Dope Sheet", "Settings for filtering animation data");
/* autosnap */
prop = RNA_def_property(srna, "auto_snap", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "autosnap");
RNA_def_property_enum_items(prop, autosnap_items);
RNA_def_property_ui_text(
prop, "Auto Snap", "Automatic time snapping settings for transformations");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, nullptr);
/* displaying cache status */
prop = RNA_def_property(srna, "show_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "cache_display", TIME_CACHE_DISPLAY);
@ -6452,14 +6429,6 @@ static void rna_def_space_graph(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, nullptr, "ads");
RNA_def_property_ui_text(prop, "Dope Sheet", "Settings for filtering animation data");
/* Auto-snap. */
prop = RNA_def_property(srna, "auto_snap", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "autosnap");
RNA_def_property_enum_items(prop, autosnap_items);
RNA_def_property_ui_text(
prop, "Auto Snap", "Automatic time snapping settings for transformations");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, nullptr);
/* Read-only state info. */
prop = RNA_def_property(srna, "has_ghost_curves", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_SpaceGraphEditor_has_ghost_curves_get", nullptr);
@ -6539,14 +6508,6 @@ static void rna_def_space_nla(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "DopeSheet");
RNA_def_property_pointer_sdna(prop, nullptr, "ads");
RNA_def_property_ui_text(prop, "Dope Sheet", "Settings for filtering animation data");
/* autosnap */
prop = RNA_def_property(srna, "auto_snap", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "autosnap");
RNA_def_property_enum_items(prop, autosnap_items);
RNA_def_property_ui_text(
prop, "Auto Snap", "Automatic time snapping settings for transformations");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, nullptr);
}
static void rna_def_console_line(BlenderRNA *brna)