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:
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py34
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/intern/scene.c3
-rw-r--r--source/blender/blenloader/intern/versioning_300.c33
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/transform.c4
-rw-r--r--source/blender/editors/transform/transform.h5
-rw-r--r--source/blender/editors/transform/transform_convert.h4
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c62
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c22
-rw-r--r--source/blender/editors/transform/transform_snap.c100
-rw-r--r--source/blender/editors/transform/transform_snap.h7
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c266
-rw-r--r--source/blender/makesdna/DNA_scene_types.h30
-rw-r--r--source/blender/makesrna/intern/rna_scene.c39
-rw-r--r--source/blender/sequencer/SEQ_iterator.h1
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h3
-rw-r--r--source/blender/sequencer/intern/iterator.c8
-rw-r--r--source/blender/sequencer/intern/sequencer.c20
19 files changed, 526 insertions, 118 deletions
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 13a8e46e2b8..ab05461f185 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -162,6 +162,14 @@ class SEQUENCER_HT_header(Header):
if tool_settings.use_proportional_edit:
row.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
+ if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
+ tool_settings = context.tool_settings
+ row = layout.row(align=True)
+ row.prop(tool_settings, "use_snap_sequencer", text="")
+ sub = row.row(align=True)
+ sub.popover(panel="SEQUENCER_PT_snapping")
+ layout.separator_spacer()
+
row = layout.row(align=True)
row.prop(st, "show_strip_overlay", text="", icon='OVERLAY')
sub = row.row(align=True)
@@ -2264,6 +2272,30 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
bl_category = "Strip"
+class SEQUENCER_PT_snapping(Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = ""
+
+ def draw(self, context):
+ tool_settings = context.tool_settings
+ sequencer_tool_settings = tool_settings.sequencer_tool_settings
+
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ col = layout.column(heading="Snap to", align=True)
+ col.prop(sequencer_tool_settings, "snap_seq_element", expand=True)
+
+ col = layout.column(heading="Ignore", align=True)
+ 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, "snap_distance", slider=True, text="Distance")
+
+
classes = (
SEQUENCER_MT_change,
SEQUENCER_HT_tool_header,
@@ -2333,6 +2365,8 @@ classes = (
SEQUENCER_PT_annotation,
SEQUENCER_PT_annotation_onion,
+
+ SEQUENCER_PT_snapping,
)
if __name__ == "__main__": # only for live edit.
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 110b9fc4252..d5baeb08ccc 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 6
+#define BLENDER_FILE_SUBVERSION 7
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 791116682c8..84741038164 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -228,7 +228,10 @@ static void scene_init_data(ID *id)
/* Curve Profile */
scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
+
+ /* Sequencer */
scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init();
+ scene->toolsettings->snap_flag |= SCE_SNAP_SEQ;
for (size_t i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
scene->orientation_slots[i].index_custom = -1;
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 84021755cef..cc350528518 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -44,6 +44,8 @@
#include "readfile.h"
#include "versioning_common.h"
+#include "SEQ_sequencer.h"
+
#include "MEM_guardedalloc.h"
#include "versioning_common.h"
@@ -430,6 +432,37 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 7)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ tool_settings->snap_flag |= SCE_SNAP_SEQ;
+ short snap_mode = tool_settings->snap_mode;
+ short snap_node_mode = tool_settings->snap_node_mode;
+ tool_settings->snap_mode &= ~((1 << 4) | (1 << 5) | (1 << 6));
+ tool_settings->snap_node_mode &= ~((1 << 5) | (1 << 6));
+ if (snap_mode & (1 << 4)) {
+ tool_settings->snap_mode |= (1 << 6); /* SCE_SNAP_MODE_INCREMENT */
+ }
+ if (snap_mode & (1 << 5)) {
+ tool_settings->snap_mode |= (1 << 4); /* SCE_SNAP_MODE_EDGE_MIDPOINT */
+ }
+ if (snap_mode & (1 << 6)) {
+ tool_settings->snap_mode |= (1 << 5); /* SCE_SNAP_MODE_EDGE_PERPENDICULAR */
+ }
+ if (snap_node_mode & (1 << 5)) {
+ tool_settings->snap_node_mode |= (1 << 0); /* SCE_SNAP_MODE_NODE_X */
+ }
+ if (snap_node_mode & (1 << 6)) {
+ tool_settings->snap_node_mode |= (1 << 1); /* SCE_SNAP_MODE_NODE_Y */
+ }
+
+ SequencerToolSettings *sequencer_tool_settings = SEQ_tool_settings_ensure(scene);
+ sequencer_tool_settings->snap_mode = SEQ_SNAP_TO_STRIPS | SEQ_SNAP_TO_PLAYHEAD |
+ SEQ_SNAP_TO_STRIP_HOLD;
+ sequencer_tool_settings->snap_distance = 15;
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index b0bc5c6abda..ad0a330f0f4 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -102,6 +102,7 @@ set(SRC
transform_orientations.c
transform_snap.c
transform_snap_object.c
+ transform_snap_sequencer.c
transform.h
transform_constraints.h
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index b03fb2c370f..02a5dcbc622 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1727,6 +1727,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->draw_handle_cursor = WM_paint_cursor_activate(
SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
+ else if (t->spacetype == SPACE_SEQ) {
+ t->draw_handle_view = ED_region_draw_cb_activate(
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ }
createTransData(C, t); /* Make #TransData structs from selection. */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4f97c3b6713..bd0ee1a51c6 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -335,7 +335,10 @@ typedef struct TransSnap {
/**
* Re-usable snap context data.
*/
- struct SnapObjectContext *object_context;
+ union {
+ struct SnapObjectContext *object_context;
+ struct TransSeqSnapData *seq_context;
+ };
} TransSnap;
typedef struct TransCon {
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 918ce0739ed..971c23b8c69 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -48,8 +48,8 @@ void clipUVData(TransInfo *t);
void transform_convert_mesh_customdatacorrect_init(TransInfo *t);
/* transform_convert_sequencer.c */
-int transform_convert_sequencer_get_snap_bound(TransInfo *t);
-void transform_convert_sequencer_channel_clamp(TransInfo *t);
+void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2]);
+
/********************* intern **********************/
/* transform_convert.c */
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 2cb0e3c8589..51914004e70 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -63,9 +63,6 @@ typedef struct TransDataSeq {
*/
typedef struct TransSeq {
TransDataSeq *tdseq;
- int min;
- int max;
- bool snap_left;
int selection_channel_range_min;
int selection_channel_range_max;
} TransSeq;
@@ -252,42 +249,6 @@ static int SeqToTransData_build(
return tot;
}
-static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
-{
- Sequence *seq;
- int count, flag;
- int max = INT32_MIN, min = INT32_MAX;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
-
- /* just to get the flag since there are corner cases where this isn't totally obvious */
- SeqTransInfo(t, seq, &count, &flag);
-
- /* use 'flag' which is derived from seq->flag but modified for special cases */
- if (flag & SELECT) {
- if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- if (flag & SEQ_LEFTSEL) {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->startdisp, max);
- }
- if (flag & SEQ_RIGHTSEL) {
- min = min_ii(seq->enddisp, min);
- max = max_ii(seq->enddisp, max);
- }
- }
- else {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->enddisp, max);
- }
- }
- }
-
- if (ts) {
- ts->max = max;
- ts->min = min;
- }
-}
-
static void free_transform_custom_data(TransCustomData *custom_data)
{
if ((custom_data->data != NULL) && custom_data->use_free) {
@@ -544,15 +505,6 @@ void createTransSeqData(TransInfo *t)
/* loop 2: build transdata array */
SeqToTransData_build(t, ed->seqbasep, td, td2d, tdsq);
- SeqTransDataBounds(t, ed->seqbasep, ts);
-
- if (t->flag & T_MODAL) {
- /* set the snap mode based on how close the mouse is at the end/start points */
- int xmouse = (int)UI_view2d_region_to_view_x((View2D *)t->view, t->mouse.imval[0]);
- if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
- ts->snap_left = true;
- }
- }
ts->selection_channel_range_min = MAXSEQ + 1;
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
@@ -719,25 +671,19 @@ void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t)
}
}
-void transform_convert_sequencer_channel_clamp(TransInfo *t)
+void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2])
{
const TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
- const int channel_offset = round_fl_to_int(t->values[1]);
+ const int channel_offset = round_fl_to_int(r_val[1]);
const int min_channel_after_transform = ts->selection_channel_range_min + channel_offset;
const int max_channel_after_transform = ts->selection_channel_range_max + channel_offset;
if (max_channel_after_transform > MAXSEQ) {
- t->values[1] -= max_channel_after_transform - MAXSEQ;
+ r_val[1] -= max_channel_after_transform - MAXSEQ;
}
if (min_channel_after_transform < 1) {
- t->values[1] -= min_channel_after_transform - 1;
+ r_val[1] -= min_channel_after_transform - 1;
}
}
-int transform_convert_sequencer_get_snap_bound(TransInfo *t)
-{
- TransSeq *ts = TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
- return ts->snap_left ? ts->min : ts->max;
-}
-
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
index 7e7b79c9f90..1b054696930 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -23,8 +23,10 @@
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_unit.h"
@@ -37,6 +39,10 @@
#include "UI_interface.h"
#include "UI_view2d.h"
+#include "SEQ_iterator.h"
+#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
+
#include "BLT_translation.h"
#include "transform.h"
@@ -102,13 +108,11 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
}
}
-static void applySeqSlide(TransInfo *t, const int mval[2])
+static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
float values_final[3] = {0.0f};
- snapSequenceBounds(t, mval);
- transform_convert_sequencer_channel_clamp(t);
if (applyNumInput(&t->num, values_final)) {
if (t->con.mode & CON_APPLY) {
if (t->con.mode & CON_AXIS0) {
@@ -119,11 +123,14 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
}
}
}
- else if (t->con.mode & CON_APPLY) {
- t->con.applyVec(t, NULL, NULL, t->values, values_final);
- }
else {
copy_v2_v2(values_final, t->values);
+ applySnapping(t, values_final);
+ transform_convert_sequencer_channel_clamp(t, values_final);
+
+ if (t->con.mode & CON_APPLY) {
+ t->con.applyVec(t, NULL, NULL, t->values, values_final);
+ }
}
values_final[0] = floorf(values_final[0] + 0.5f);
@@ -164,4 +171,5 @@ void initSeqSlide(TransInfo *t)
t->custom.mode.data = (void *)WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index b6e0f07cc70..34a380f9199 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -41,9 +41,6 @@
#include "RNA_access.h"
-#include "SEQ_sequencer.h"
-#include "SEQ_time.h"
-
#include "WM_types.h"
#include "ED_gizmo_library.h"
@@ -55,6 +52,10 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "SEQ_iterator.h"
+#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
+
#include "MEM_guardedalloc.h"
#include "transform.h"
@@ -164,10 +165,7 @@ bool transformModeUseSnap(const TransInfo *t)
if (t->mode == TFM_RESIZE) {
return (ts->snap_transform_mode_flag & SCE_SNAP_TRANSFORM_MODE_SCALE) != 0;
}
- if (t->mode == TFM_VERT_SLIDE) {
- return true;
- }
- if (t->mode == TFM_EDGE_SLIDE) {
+ if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE, TFM_SEQ_SLIDE)) {
return true;
}
@@ -295,6 +293,21 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
GPU_blend(GPU_BLEND_NONE);
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ if (validSnap(t)) {
+ const ARegion *region = CTX_wm_region(C);
+ GPU_blend(GPU_BLEND_ALPHA);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, t->tsnap.snapPoint[0], region->v2d.cur.ymin);
+ immVertex2f(pos, t->tsnap.snapPoint[0], region->v2d.cur.ymax);
+ immEnd();
+ immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
+ }
+ }
}
eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
@@ -476,11 +489,14 @@ void applySnapping(TransInfo *t, float *vec)
/* TODO: add exception for object mode, no need to slow it down then. */
if (current - t->tsnap.last >= 0.01) {
t->tsnap.calcSnap(t, vec);
- t->tsnap.targetSnap(t);
-
- t->tsnap.last = current;
+ if (t->tsnap.targetSnap) {
+ t->tsnap.targetSnap(t);
+ }
}
- if (validSnap(t)) {
+
+ t->tsnap.last = current;
+
+ if (t->tsnap.applySnap && validSnap(t)) {
t->tsnap.applySnap(t, vec);
}
}
@@ -567,6 +583,9 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = ts->snap_uv_mode;
}
+ else if (t->spacetype == SPACE_SEQ) {
+ t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene);
+ }
else {
/* force project off when not supported */
if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) {
@@ -626,16 +645,12 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
}
- else if (t->spacetype == SPACE_NODE) {
+ else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
setSnappingCallback(t);
t->tsnap.modeSelect = SNAP_NOT_SELECTED;
}
- else if (t->spacetype == SPACE_SEQ) {
- /* We do our own snapping currently, so nothing here */
- t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */
- }
else {
- /* Always increment outside of 3D view */
+ /* Fallback. */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
@@ -656,6 +671,11 @@ static void initSnappingMode(TransInfo *t)
}
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ if (t->tsnap.seq_context == NULL) {
+ t->tsnap.seq_context = transform_snap_sequencer_data_alloc(t);
+ }
+ }
}
void initSnapping(TransInfo *t, wmOperator *op)
@@ -708,6 +728,9 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) != 0);
t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) != 0);
}
+ else if ((t->spacetype == SPACE_SEQ) && (ts->snap_flag & SCE_SNAP_SEQ)) {
+ t->modifiers |= MOD_SNAP;
+ }
}
t->tsnap.target = snap_target;
@@ -717,7 +740,11 @@ void initSnapping(TransInfo *t, wmOperator *op)
void freeSnapping(TransInfo *t)
{
- if (t->tsnap.object_context) {
+ if ((t->spacetype == SPACE_SEQ) && t->tsnap.seq_context) {
+ transform_snap_sequencer_data_free(t->tsnap.seq_context);
+ t->tsnap.seq_context = NULL;
+ }
+ else if (t->tsnap.object_context) {
ED_transform_snap_object_context_destroy(t->tsnap.object_context);
t->tsnap.object_context = NULL;
}
@@ -727,6 +754,11 @@ static void setSnappingCallback(TransInfo *t)
{
t->tsnap.calcSnap = CalcSnapGeometry;
+ if (t->spacetype == SPACE_SEQ) {
+ /* The target is calculated along with the snap point. */
+ return;
+ }
+
switch (t->tsnap.target) {
case SCE_SNAP_TARGET_CLOSEST:
t->tsnap.targetSnap = TargetSnapClosest;
@@ -849,7 +881,7 @@ void getSnapPoint(const TransInfo *t, float vec[3])
/** \name Calc Snap (Generic)
* \{ */
-static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
+static void CalcSnapGeometry(TransInfo *t, float *vec)
{
if (t->spacetype == SPACE_VIEW3D) {
float loc[3];
@@ -930,6 +962,14 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ if (transform_snap_sequencer_apply(t, vec, t->tsnap.snapPoint)) {
+ t->tsnap.status |= (POINT_INIT | TARGET_INIT);
+ }
+ else {
+ t->tsnap.status &= ~(POINT_INIT | TARGET_INIT);
+ }
+ }
}
/** \} */
@@ -1441,28 +1481,6 @@ void snapFrameTransform(TransInfo *t,
*r_val = (float)val;
}
-/*================================================================*/
-
-void snapSequenceBounds(TransInfo *t, const int mval[2])
-{
- /* Reuse increment, strictly speaking could be another snap mode, but leave as is. */
- if (!(t->modifiers & MOD_SNAP_INVERT)) {
- return;
- }
-
- /* Convert to frame range. */
- float xmouse, ymouse;
- UI_view2d_region_to_view(&t->region->v2d, mval[0], mval[1], &xmouse, &ymouse);
- const int frame_curr = round_fl_to_int(xmouse);
-
- /* Now find the closest sequence. */
- const int frame_near = SEQ_time_find_next_prev_edit(
- t->scene, frame_curr, SEQ_SIDE_BOTH, true, false, true);
-
- const int frame_snap = transform_convert_sequencer_get_snap_bound(t);
- t->values[0] = frame_near - frame_snap;
-}
-
static void snap_grid_apply(
TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3])
{
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index bf14e564380..e0989418c1c 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -58,8 +58,6 @@ bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float
bool transform_snap_increment(const TransInfo *t, float *val);
bool transform_snap_grid(TransInfo *t, float *val);
-void snapSequenceBounds(TransInfo *t, const int mval[2]);
-
bool activeSnap(const TransInfo *t);
bool activeSnap_with_project(const TransInfo *t);
@@ -82,3 +80,8 @@ eRedrawFlag updateSelectedSnapPoint(TransInfo *t);
void removeSnapPoint(TransInfo *t);
float transform_snap_distance_len_squared_fn(TransInfo *t, const float p1[3], const float p2[3]);
+
+/* transform_snap_sequencer.c */
+struct TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t);
+void transform_snap_sequencer_data_free(struct TransSeqSnapData *data);
+bool transform_snap_sequencer_apply(struct TransInfo *t, float *vec, float *snap_point);
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
new file mode 100644
index 00000000000..22d738e75ca
--- /dev/null
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -0,0 +1,266 @@
+/*
+ * 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+
+#include "UI_view2d.h"
+
+#include "SEQ_iterator.h"
+#include "SEQ_sequencer.h"
+
+#include "transform.h"
+#include "transform_snap.h"
+
+typedef struct TransSeqSnapData {
+ int *source_snap_points;
+ int *target_snap_points;
+ int source_snap_point_count;
+ int target_snap_point_count;
+ int final_snap_frame;
+} TransSeqSnapData;
+
+/* -------------------------------------------------------------------- */
+/** \name Snap sources
+ * \{ */
+
+static int seq_get_snap_source_points_count(SeqCollection *snap_sources)
+{
+ return SEQ_collection_count(snap_sources) * 2;
+}
+
+static void seq_snap_source_points_alloc(TransSeqSnapData *snap_data, SeqCollection *snap_sources)
+{
+ const size_t point_count = seq_get_snap_source_points_count(snap_sources);
+ snap_data->source_snap_points = MEM_callocN(sizeof(int) * point_count, __func__);
+ memset(snap_data->source_snap_points, 0, sizeof(int));
+ snap_data->source_snap_point_count = point_count;
+}
+
+static int cmp_fn(const void *a, const void *b)
+{
+ return (*(int *)a - *(int *)b);
+}
+
+static void seq_snap_source_points_build(const TransInfo *t,
+ TransSeqSnapData *snap_data,
+ SeqCollection *snap_sources)
+{
+ int i = 0;
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, snap_sources) {
+ int left = 0, right = 0;
+ if (seq->flag & SEQ_LEFTSEL) {
+ left = right = seq->startdisp;
+ }
+ else if (seq->flag & SEQ_RIGHTSEL) {
+ left = right = seq->enddisp;
+ }
+ else {
+ left = seq->startdisp;
+ right = seq->enddisp;
+ }
+
+ snap_data->source_snap_points[i] = left;
+ snap_data->source_snap_points[i + 1] = right;
+ i += 2;
+ BLI_assert(i <= snap_data->source_snap_point_count);
+ }
+
+ qsort(snap_data->source_snap_points, snap_data->source_snap_point_count, sizeof(int), cmp_fn);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap targets
+ * \{ */
+
+static SeqCollection *query_snap_targets(const TransInfo *t)
+{
+ const ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false));
+ const short snap_flag = SEQ_tool_settings_snap_flag_get(t->scene);
+ SeqCollection *collection = SEQ_collection_create();
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if ((seq->flag & SELECT)) {
+ continue; /* Selected are being transformed. */
+ }
+ if ((seq->flag & SEQ_MUTE) && (snap_flag & SEQ_SNAP_IGNORE_MUTED)) {
+ continue;
+ }
+ if (seq->type == SEQ_TYPE_SOUND_RAM && (snap_flag & SEQ_SNAP_IGNORE_SOUND)) {
+ continue;
+ }
+ SEQ_collection_append_strip(seq, collection);
+ }
+ return collection;
+}
+
+static int seq_get_snap_target_points_count(const TransInfo *t,
+ TransSeqSnapData *snap_data,
+ SeqCollection *snap_targets)
+{
+ const short snap_mode = t->tsnap.mode;
+
+ int count = 2; /* Strip start and end are always used. */
+
+ if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
+ count += 2;
+ }
+
+ count *= SEQ_collection_count(snap_targets);
+
+ if (snap_mode & SEQ_SNAP_TO_PLAYHEAD) {
+ count++;
+ }
+
+ return count;
+}
+
+static void seq_snap_target_points_alloc(const TransInfo *t,
+ TransSeqSnapData *snap_data,
+ SeqCollection *snap_targets)
+{
+ const size_t point_count = seq_get_snap_target_points_count(t, snap_data, snap_targets);
+ snap_data->target_snap_points = MEM_callocN(sizeof(int) * point_count, __func__);
+ memset(snap_data->target_snap_points, 0, sizeof(int));
+ snap_data->target_snap_point_count = point_count;
+}
+
+static void seq_snap_target_points_build(const TransInfo *t,
+ TransSeqSnapData *snap_data,
+ SeqCollection *snap_targets)
+{
+ const Scene *scene = t->scene;
+ const short snap_mode = t->tsnap.mode;
+
+ int i = 0;
+
+ if (snap_mode & SEQ_SNAP_TO_PLAYHEAD) {
+ snap_data->target_snap_points[i] = CFRA;
+ i++;
+ }
+
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, snap_targets) {
+ snap_data->target_snap_points[i] = seq->startdisp;
+ snap_data->target_snap_points[i + 1] = seq->enddisp;
+ i += 2;
+
+ if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
+ int content_start = min_ii(seq->enddisp, seq->start);
+ int content_end = max_ii(seq->startdisp, seq->start + seq->len);
+ if (seq->anim_startofs == 0) {
+ content_start = seq->startdisp;
+ }
+ if (seq->anim_endofs == 0) {
+ content_end = seq->enddisp;
+ }
+ snap_data->target_snap_points[i] = content_start;
+ snap_data->target_snap_points[i + 1] = content_end;
+ i += 2;
+ }
+ }
+ BLI_assert(i <= snap_data->target_snap_point_count);
+ qsort(snap_data->target_snap_points, snap_data->target_snap_point_count, sizeof(int), cmp_fn);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap utilities
+ * \{ */
+
+static int seq_snap_threshold_get_frame_distance(const TransInfo *t)
+{
+ const int snap_distance = SEQ_tool_settings_snap_distance_get(t->scene);
+ const struct View2D *v2d = &t->region->v2d;
+ return round_fl_to_int(UI_view2d_region_to_view_x(v2d, snap_distance) -
+ UI_view2d_region_to_view_x(v2d, 0));
+}
+
+/** \} */
+
+TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
+{
+ TransSeqSnapData *snap_data = MEM_callocN(sizeof(TransSeqSnapData), __func__);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene, false));
+
+ /* Build arrays of snap points. */
+ SeqCollection *snap_sources = SEQ_query_selected_strips(seqbase);
+ seq_snap_source_points_alloc(snap_data, snap_sources);
+ seq_snap_source_points_build(t, snap_data, snap_sources);
+ SEQ_collection_free(snap_sources);
+
+ SeqCollection *snap_targets = query_snap_targets(t);
+ seq_snap_target_points_alloc(t, snap_data, snap_targets);
+ seq_snap_target_points_build(t, snap_data, snap_targets);
+ SEQ_collection_free(snap_targets);
+ return snap_data;
+}
+
+void transform_snap_sequencer_data_free(TransSeqSnapData *data)
+{
+ MEM_freeN(data->source_snap_points);
+ MEM_freeN(data->target_snap_points);
+ MEM_freeN(data);
+}
+
+bool transform_snap_sequencer_apply(TransInfo *t, float *vec, float *snap_point)
+{
+ const TransSeqSnapData *snap_data = t->tsnap.seq_context;
+ int best_dist = MAXFRAME, best_target_frame = 0, best_source_frame = 0;
+ *snap_point = 0;
+
+ for (int i = 0; i < snap_data->source_snap_point_count; i++) {
+ int snap_source_frame = snap_data->source_snap_points[i] + round_fl_to_int(t->values[0]);
+ for (int j = 0; j < snap_data->target_snap_point_count; j++) {
+ int snap_target_frame = snap_data->target_snap_points[j];
+
+ int dist = abs(snap_target_frame - snap_source_frame);
+ if (dist > best_dist) {
+ continue;
+ }
+
+ best_dist = dist;
+ best_target_frame = snap_target_frame;
+ best_source_frame = snap_source_frame;
+ }
+ }
+
+ if (best_dist > seq_snap_threshold_get_frame_distance(t)) {
+ return false;
+ }
+
+ *snap_point = best_target_frame;
+ *vec += best_target_frame - best_source_frame;
+ return true;
+}
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 4da2bbb58c0..f13105ce559 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1336,6 +1336,12 @@ typedef struct MeshStatVis {
typedef struct SequencerToolSettings {
/* eSeqImageFitMethod */
int fit_method;
+ short snap_mode;
+ short snap_flag;
+ int _pad0;
+ /** When there are many snap points, 0-1 range corresponds to resolution from boundbox to all
+ * possible snap points. */
+ int snap_distance;
} SequencerToolSettings;
typedef enum eSeqImageFitMethod {
@@ -2039,6 +2045,7 @@ enum {
#define SCE_SNAP_NO_SELF (1 << 4)
#define SCE_SNAP_ABS_GRID (1 << 5)
#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
+#define SCE_SNAP_SEQ (1 << 7)
/** #ToolSettings.snap_target */
#define SCE_SNAP_TARGET_CLOSEST 0
@@ -2051,15 +2058,26 @@ enum {
#define SCE_SNAP_MODE_EDGE (1 << 1)
#define SCE_SNAP_MODE_FACE (1 << 2)
#define SCE_SNAP_MODE_VOLUME (1 << 3)
-#define SCE_SNAP_MODE_INCREMENT (1 << 4)
-#define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 5)
-#define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 6)
+#define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4)
+#define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5)
+
+/** #SequencerToolSettings.snap_mode */
+#define SEQ_SNAP_TO_STRIPS (1 << 0)
+#define SEQ_SNAP_TO_PLAYHEAD (1 << 1)
+#define SEQ_SNAP_TO_STRIP_HOLD (1 << 2)
+
+/** #SequencerToolSettings.snap_flag */
+#define SEQ_SNAP_IGNORE_MUTED (1 << 0)
+#define SEQ_SNAP_IGNORE_SOUND (1 << 1)
/** #ToolSettings.snap_node_mode */
-#define SCE_SNAP_MODE_NODE_X (1 << 5)
-#define SCE_SNAP_MODE_NODE_Y (1 << 6)
+#define SCE_SNAP_MODE_NODE_X (1 << 0)
+#define SCE_SNAP_MODE_NODE_Y (1 << 1)
-/** #ToolSettings.snap_mode and #ToolSettings.snap_node_mode */
+/**
+ * #ToolSettings.snap_mode and #ToolSettings.snap_node_mode
+ */
+#define SCE_SNAP_MODE_INCREMENT (1 << 6)
#define SCE_SNAP_MODE_GRID (1 << 7)
/** #ToolSettings.snap_transform_mode_flag */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index ceeec13b09d..1b8fc692611 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -190,6 +190,12 @@ const EnumPropertyItem rna_enum_snap_node_element_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_snap_seq_element_items[] = {
+ {SEQ_SNAP_TO_PLAYHEAD, "PLAYHEAD", ICON_NONE, "Playhead", "Snap to current frame"},
+ {SEQ_SNAP_TO_STRIP_HOLD, "STRIP_HOLD", ICON_NONE, "Hold Offset", "Snap to strip hold offset"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem snap_uv_element_items[] = {
{SCE_SNAP_MODE_INCREMENT,
@@ -3111,6 +3117,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "use_snap_sequencer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_SEQ);
+ RNA_def_property_ui_text(prop, "Use Snapping", "Snap to strip edges or current frame");
+ RNA_def_property_ui_icon(prop, ICON_SNAP_OFF, 1);
+ RNA_def_property_boolean_default(prop, true);
+
prop = RNA_def_property(srna, "snap_elements", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_element_items);
@@ -3505,9 +3517,36 @@ static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_SequencerToolSettings_path");
RNA_def_struct_ui_text(srna, "Sequencer Tool Settings", "");
+ /* Add strip settings. */
prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, scale_fit_methods);
RNA_def_property_ui_text(prop, "Fit Method", "Scale fit method");
+
+ /* Transform snapping. */
+
+ /* Sequencer editor uses own set of snap modes */
+ prop = RNA_def_property(srna, "snap_seq_element", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
+ RNA_def_property_enum_items(prop, rna_enum_snap_seq_element_items);
+ RNA_def_property_ui_text(prop, "Snap To", "Type of element to snap to");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "snap_ignore_muted", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SEQ_SNAP_IGNORE_MUTED);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Ignore Muted Strips", "Don't snap to hidden strips");
+
+ prop = RNA_def_property(srna, "snap_ignore_sound", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SEQ_SNAP_IGNORE_SOUND);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Ignore Sound Strips", "Don't snap to sound strips");
+
+ 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);
+ RNA_def_property_ui_range(prop, 0, 50, 1, 1);
+ RNA_def_property_ui_text(prop, "Snapping Distance", "Maximum distance for snapping in pixels");
}
static void rna_def_unified_paint_settings(BlenderRNA *brna)
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index c7c2dc275ee..39d8a7241fb 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -71,6 +71,7 @@ bool SEQ_iterator_ensure(SeqCollection *collection,
struct Sequence *SEQ_iterator_yield(SeqIterator *iterator);
SeqCollection *SEQ_collection_create(void);
+uint SEQ_collection_count(SeqCollection *collection);
bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *data);
bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *data);
void SEQ_collection_free(SeqCollection *collection);
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index fd4181a5a54..706f4064bf3 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -55,6 +55,9 @@ struct SequencerToolSettings *SEQ_tool_settings_ensure(struct Scene *scene);
void SEQ_tool_settings_free(struct SequencerToolSettings *tool_settings);
eSeqImageFitMethod SEQ_tool_settings_fit_method_get(struct Scene *scene);
void SEQ_tool_settings_fit_method_set(struct Scene *scene, eSeqImageFitMethod fit_method);
+short SEQ_tool_settings_snap_flag_get(struct Scene *scene);
+short SEQ_tool_settings_snap_mode_get(struct Scene *scene);
+int SEQ_tool_settings_snap_distance_get(struct Scene *scene);
struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings);
struct Editing *SEQ_editing_get(struct Scene *scene, bool alloc);
struct Editing *SEQ_editing_ensure(struct Scene *scene);
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index 9bbc5362f18..4df92ce7df4 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -115,6 +115,14 @@ SeqCollection *SEQ_collection_create(void)
}
/**
+ * Return number of items in collection.
+ */
+uint SEQ_collection_count(SeqCollection *collection)
+{
+ return BLI_gset_len(collection->set);
+}
+
+/**
* Query strips from seqbase. seq_reference is used by query function as filter condition.
*
* \param seq_reference: reference strip for query function
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 8cd67195c30..f6b37bdb3ab 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -311,6 +311,8 @@ SequencerToolSettings *SEQ_tool_settings_init(void)
SequencerToolSettings *tool_settings = MEM_callocN(sizeof(SequencerToolSettings),
"Sequencer tool settings");
tool_settings->fit_method = SEQ_SCALE_TO_FIT;
+ tool_settings->snap_mode = SEQ_SNAP_TO_STRIPS | SEQ_SNAP_TO_PLAYHEAD | SEQ_SNAP_TO_STRIP_HOLD;
+ tool_settings->snap_distance = 15;
return tool_settings;
}
@@ -336,6 +338,24 @@ eSeqImageFitMethod SEQ_tool_settings_fit_method_get(Scene *scene)
return tool_settings->fit_method;
}
+short SEQ_tool_settings_snap_mode_get(Scene *scene)
+{
+ const SequencerToolSettings *tool_settings = SEQ_tool_settings_ensure(scene);
+ return tool_settings->snap_mode;
+}
+
+short SEQ_tool_settings_snap_flag_get(Scene *scene)
+{
+ const SequencerToolSettings *tool_settings = SEQ_tool_settings_ensure(scene);
+ return tool_settings->snap_flag;
+}
+
+int SEQ_tool_settings_snap_distance_get(Scene *scene)
+{
+ const SequencerToolSettings *tool_settings = SEQ_tool_settings_ensure(scene);
+ return tool_settings->snap_distance;
+}
+
void SEQ_tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_method)
{
SequencerToolSettings *tool_settings = SEQ_tool_settings_ensure(scene);