VSE: Use snapping settings for scrubbing

Use "Snap Playhead to Strips" option to enable playhead snapping.
Change behavior of CTRL key to invert snapping similar to transform operator.

Currently this option is disabled by default. It makes editing quite unpleasant
for me personally, but ideally I should gather feedback from more users.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D11745
This commit is contained in:
Richard Antalik 2021-07-07 03:20:59 +02:00
parent c5b2381703
commit 4e80573a76
4 changed files with 86 additions and 5 deletions

View File

@ -2293,6 +2293,9 @@ class SEQUENCER_PT_snapping(Panel):
col.prop(sequencer_tool_settings, "snap_ignore_muted", text="Muted Strips")
col.prop(sequencer_tool_settings, "snap_ignore_sound", text="Sound Strips")
col = layout.column()
col.prop(sequencer_tool_settings, "use_snap_current_frame_to_strips")
classes = (
SEQUENCER_MT_change,

View File

@ -51,8 +51,10 @@
#include "DEG_depsgraph.h"
#include "SEQ_iterator.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
#include "SEQ_transform.h"
#include "anim_intern.h"
@ -81,6 +83,49 @@ static bool change_frame_poll(bContext *C)
return false;
}
static int seq_snap_threshold_get_frame_distance(bContext *C)
{
const int snap_distance = SEQ_tool_settings_snap_distance_get(CTX_data_scene(C));
const ARegion *region = CTX_wm_region(C);
return round_fl_to_int(UI_view2d_region_to_view_x(&region->v2d, snap_distance) -
UI_view2d_region_to_view_x(&region->v2d, 0));
}
static void seq_frame_snap_update_best(const int position,
const int timeline_frame,
int *r_best_frame,
int *r_best_distance)
{
if (abs(position - timeline_frame) < *r_best_distance) {
*r_best_distance = abs(position - timeline_frame);
*r_best_frame = position;
}
}
static int seq_frame_apply_snap(bContext *C, Scene *scene, const int timeline_frame)
{
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene, false));
SeqCollection *strips = SEQ_query_all_strips(seqbase);
int best_frame = 0;
int best_distance = MAXFRAME;
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
seq_frame_snap_update_best(
SEQ_transform_get_left_handle_frame(seq), timeline_frame, &best_frame, &best_distance);
seq_frame_snap_update_best(
SEQ_transform_get_right_handle_frame(seq), timeline_frame, &best_frame, &best_distance);
}
SEQ_collection_free(strips);
if (best_distance < seq_snap_threshold_get_frame_distance(C)) {
return best_frame;
}
return timeline_frame;
}
/* Set the new frame number */
static void change_frame_apply(bContext *C, wmOperator *op)
{
@ -90,7 +135,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
if (do_snap) {
if (CTX_wm_space_seq(C)) {
frame = SEQ_time_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false);
frame = seq_frame_apply_snap(C, scene, frame);
}
else {
frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame);
@ -181,6 +226,18 @@ static void change_frame_seq_preview_end(bContext *C)
}
}
static bool use_sequencer_snapping(bContext *C)
{
if (!CTX_wm_space_seq(C)) {
return false;
}
Scene *scene = CTX_data_scene(C);
short snap_flag = SEQ_tool_settings_snap_flag_get(scene);
return (scene->toolsettings->snap_flag & SCE_SNAP_SEQ) &&
(snap_flag & SEQ_SNAP_CURRENT_FRAME_TO_STRIPS);
}
/* Modal Operator init */
static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
@ -190,6 +247,10 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
*/
RNA_float_set(op->ptr, "frame", frame_from_event(C, event));
if (use_sequencer_snapping(C)) {
RNA_boolean_set(op->ptr, "snap", true);
}
change_frame_seq_preview_begin(C, event);
change_frame_apply(C, op);
@ -231,11 +292,22 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY:
if (event->val == KM_RELEASE) {
RNA_boolean_set(op->ptr, "snap", false);
/* Use Ctrl key to invert snapping in sequencer. */
if (use_sequencer_snapping(C)) {
if (event->val == KM_RELEASE) {
RNA_boolean_set(op->ptr, "snap", true);
}
else if (event->val == KM_PRESS) {
RNA_boolean_set(op->ptr, "snap", false);
}
}
else if (event->val == KM_PRESS) {
RNA_boolean_set(op->ptr, "snap", true);
else {
if (event->val == KM_RELEASE) {
RNA_boolean_set(op->ptr, "snap", false);
}
else if (event->val == KM_PRESS) {
RNA_boolean_set(op->ptr, "snap", true);
}
}
break;
}

View File

@ -2069,6 +2069,7 @@ enum {
/** #SequencerToolSettings.snap_flag */
#define SEQ_SNAP_IGNORE_MUTED (1 << 0)
#define SEQ_SNAP_IGNORE_SOUND (1 << 1)
#define SEQ_SNAP_CURRENT_FRAME_TO_STRIPS (1 << 2)
/** #ToolSettings.snap_node_mode */
#define SCE_SNAP_MODE_NODE_X (1 << 0)

View File

@ -3535,6 +3535,11 @@ static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SEQ_SNAP_IGNORE_SOUND);
RNA_def_property_ui_text(prop, "Ignore Sound Strips", "Don't snap to sound strips");
prop = RNA_def_property(srna, "use_snap_current_frame_to_strips", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SEQ_SNAP_CURRENT_FRAME_TO_STRIPS);
RNA_def_property_ui_text(
prop, "Snap Current Frame to Strips", "Snap current frame to strip start or end");
prop = RNA_def_property(srna, "snap_distance", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "snap_distance");
RNA_def_property_int_default(prop, 15);