2023-05-31 16:19:06 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2021-06-29 20:12:19 +02:00
|
|
|
|
|
|
|
/** \file
|
|
|
|
* \ingroup edtransform
|
|
|
|
*/
|
|
|
|
|
2023-07-22 03:27:25 +02:00
|
|
|
#include <cstdlib>
|
2021-06-29 20:12:19 +02:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "ED_screen.hh"
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_transform.hh"
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "UI_view2d.hh"
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2023-11-02 01:05:06 +01:00
|
|
|
#include "SEQ_channels.hh"
|
|
|
|
#include "SEQ_effects.hh"
|
|
|
|
#include "SEQ_iterator.hh"
|
|
|
|
#include "SEQ_relations.hh"
|
|
|
|
#include "SEQ_render.hh"
|
|
|
|
#include "SEQ_sequencer.hh"
|
|
|
|
#include "SEQ_time.hh"
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2023-07-13 17:59:52 +02:00
|
|
|
#include "transform.hh"
|
|
|
|
#include "transform_convert.hh"
|
|
|
|
#include "transform_snap.hh"
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2023-07-13 17:59:52 +02:00
|
|
|
struct TransSeqSnapData {
|
2023-11-13 23:30:52 +01:00
|
|
|
blender::Array<int> source_snap_points;
|
|
|
|
blender::Array<int> target_snap_points;
|
|
|
|
|
|
|
|
#ifdef WITH_CXX_GUARDEDALLOC
|
|
|
|
MEM_CXX_CLASS_ALLOC_FUNCS("TransSeqSnapData")
|
|
|
|
#endif
|
2023-07-13 17:59:52 +02:00
|
|
|
};
|
2021-06-29 20:12:19 +02:00
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Snap sources
|
|
|
|
* \{ */
|
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
static int seq_get_snap_source_points_len(blender::Span<Sequence *> snap_sources)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2023-11-06 01:36:44 +01:00
|
|
|
return snap_sources.size() * 2;
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int cmp_fn(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
return (*(int *)a - *(int *)b);
|
|
|
|
}
|
|
|
|
|
2023-11-13 23:30:52 +01:00
|
|
|
static bool seq_snap_source_points_build(const Scene *scene,
|
2022-06-29 12:45:59 +02:00
|
|
|
TransSeqSnapData *snap_data,
|
2023-11-06 01:36:44 +01:00
|
|
|
blender::Span<Sequence *> snap_sources)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2023-11-13 23:30:52 +01:00
|
|
|
const size_t point_count_source = seq_get_snap_source_points_len(snap_sources);
|
|
|
|
if (point_count_source == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
snap_data->source_snap_points.reinitialize(point_count_source);
|
2021-06-29 20:12:19 +02:00
|
|
|
int i = 0;
|
2023-11-06 01:36:44 +01:00
|
|
|
for (Sequence *seq : snap_sources) {
|
2021-06-29 20:12:19 +02:00
|
|
|
int left = 0, right = 0;
|
|
|
|
if (seq->flag & SEQ_LEFTSEL) {
|
2022-06-29 12:45:59 +02:00
|
|
|
left = right = SEQ_time_left_handle_frame_get(scene, seq);
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
else if (seq->flag & SEQ_RIGHTSEL) {
|
2022-06-29 12:45:59 +02:00
|
|
|
left = right = SEQ_time_right_handle_frame_get(scene, seq);
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
else {
|
2022-06-29 12:45:59 +02:00
|
|
|
left = SEQ_time_left_handle_frame_get(scene, seq);
|
|
|
|
right = SEQ_time_right_handle_frame_get(scene, seq);
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
snap_data->source_snap_points[i] = left;
|
|
|
|
snap_data->source_snap_points[i + 1] = right;
|
|
|
|
i += 2;
|
2023-11-13 23:30:52 +01:00
|
|
|
BLI_assert(i <= snap_data->source_snap_points.size());
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
2023-11-13 23:30:52 +01:00
|
|
|
qsort(snap_data->source_snap_points.data(),
|
|
|
|
snap_data->source_snap_points.size(),
|
|
|
|
sizeof(int),
|
|
|
|
cmp_fn);
|
|
|
|
|
|
|
|
return true;
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Snap targets
|
|
|
|
* \{ */
|
|
|
|
|
2021-07-26 14:55:14 +02:00
|
|
|
/* Add effect strips directly or indirectly connected to `seq_reference` to `collection`. */
|
2022-06-29 12:45:59 +02:00
|
|
|
static void query_strip_effects_fn(const Scene *scene,
|
|
|
|
Sequence *seq_reference,
|
2021-07-26 14:55:14 +02:00
|
|
|
ListBase *seqbase,
|
2023-11-06 01:36:44 +01:00
|
|
|
blender::VectorSet<Sequence *> &strips)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2023-11-06 01:36:44 +01:00
|
|
|
if (strips.contains(seq_reference)) {
|
2021-07-26 14:55:14 +02:00
|
|
|
return; /* Strip is already in set, so all effects connected to it are as well. */
|
|
|
|
}
|
2023-11-06 01:36:44 +01:00
|
|
|
strips.add(seq_reference);
|
2021-07-26 14:55:14 +02:00
|
|
|
|
|
|
|
/* Find all strips connected to `seq_reference`. */
|
|
|
|
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
|
2022-04-21 01:57:55 +02:00
|
|
|
if (SEQ_relation_is_effect_of_strip(seq_test, seq_reference)) {
|
2023-11-06 01:36:44 +01:00
|
|
|
query_strip_effects_fn(scene, seq_test, seqbase, strips);
|
2021-07-26 14:55:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
static blender::VectorSet<Sequence *> query_snap_targets(Scene *scene,
|
|
|
|
blender::Span<Sequence *> snap_sources,
|
|
|
|
bool exclude_selected)
|
2021-07-26 14:55:14 +02:00
|
|
|
{
|
2022-04-28 12:50:22 +02:00
|
|
|
Editing *ed = SEQ_editing_get(scene);
|
2022-04-04 12:52:48 +02:00
|
|
|
ListBase *seqbase = SEQ_active_seqbase_get(ed);
|
|
|
|
ListBase *channels = SEQ_channels_displayed_get(ed);
|
2022-04-28 12:50:22 +02:00
|
|
|
const short snap_flag = SEQ_tool_settings_snap_flag_get(scene);
|
2023-11-06 01:36:44 +01:00
|
|
|
|
|
|
|
/* Effects will always change position with strip to which they are connected and they don't have
|
|
|
|
* to be selected. Remove such strips from `snap_targets` collection. */
|
|
|
|
blender::VectorSet effects_of_snap_sources = snap_sources;
|
|
|
|
SEQ_iterator_set_expand(scene, seqbase, effects_of_snap_sources, query_strip_effects_fn);
|
|
|
|
effects_of_snap_sources.remove_if(
|
|
|
|
[&](Sequence *seq) { return SEQ_effect_get_num_inputs(seq->type) == 0; });
|
|
|
|
|
|
|
|
blender::VectorSet<Sequence *> snap_targets;
|
2021-06-29 20:12:19 +02:00
|
|
|
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
|
2022-04-28 12:50:22 +02:00
|
|
|
if (exclude_selected && seq->flag & SELECT) {
|
2021-06-29 20:12:19 +02:00
|
|
|
continue; /* Selected are being transformed. */
|
|
|
|
}
|
2022-04-04 12:52:48 +02:00
|
|
|
if (SEQ_render_is_muted(channels, seq) && (snap_flag & SEQ_SNAP_IGNORE_MUTED)) {
|
2021-06-29 20:12:19 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (seq->type == SEQ_TYPE_SOUND_RAM && (snap_flag & SEQ_SNAP_IGNORE_SOUND)) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-11-06 01:36:44 +01:00
|
|
|
if (effects_of_snap_sources.contains(seq)) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-26 14:55:14 +02:00
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
snap_targets.add(seq);
|
|
|
|
}
|
2021-07-26 14:55:14 +02:00
|
|
|
|
|
|
|
return snap_targets;
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
static int seq_get_snap_target_points_count(short snap_mode,
|
|
|
|
blender::Span<Sequence *> snap_targets)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
|
|
|
int count = 2; /* Strip start and end are always used. */
|
|
|
|
|
|
|
|
if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
|
|
|
|
count += 2;
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
count *= snap_targets.size();
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2021-07-01 03:02:30 +02:00
|
|
|
if (snap_mode & SEQ_SNAP_TO_CURRENT_FRAME) {
|
2021-06-29 20:12:19 +02:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2023-11-13 23:30:52 +01:00
|
|
|
static bool seq_snap_target_points_build(Scene *scene,
|
2022-04-28 12:50:22 +02:00
|
|
|
short snap_mode,
|
2021-06-29 20:12:19 +02:00
|
|
|
TransSeqSnapData *snap_data,
|
2023-11-06 01:36:44 +01:00
|
|
|
blender::Span<Sequence *> snap_targets)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2023-11-13 23:30:52 +01:00
|
|
|
const size_t point_count_target = seq_get_snap_target_points_count(snap_mode, snap_targets);
|
|
|
|
if (point_count_target == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
snap_data->target_snap_points.reinitialize(point_count_target);
|
2021-06-29 20:12:19 +02:00
|
|
|
int i = 0;
|
|
|
|
|
2021-07-01 03:02:30 +02:00
|
|
|
if (snap_mode & SEQ_SNAP_TO_CURRENT_FRAME) {
|
2022-06-30 18:36:42 +02:00
|
|
|
snap_data->target_snap_points[i] = scene->r.cfra;
|
2021-06-29 20:12:19 +02:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
for (Sequence *seq : snap_targets) {
|
2022-06-29 12:45:59 +02:00
|
|
|
snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(scene, seq);
|
|
|
|
snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(scene, seq);
|
2021-06-29 20:12:19 +02:00
|
|
|
i += 2;
|
|
|
|
|
|
|
|
if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
|
2022-10-04 19:50:13 +02:00
|
|
|
int content_start = min_ii(SEQ_time_left_handle_frame_get(scene, seq),
|
2022-10-05 20:24:37 +02:00
|
|
|
SEQ_time_start_frame_get(seq));
|
2022-10-04 19:50:13 +02:00
|
|
|
int content_end = max_ii(SEQ_time_right_handle_frame_get(scene, seq),
|
2022-10-05 20:24:37 +02:00
|
|
|
SEQ_time_content_end_frame_get(scene, seq));
|
2021-07-26 14:55:14 +02:00
|
|
|
/* Effects and single image strips produce incorrect content length. Skip these strips. */
|
|
|
|
if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->len == 1) {
|
2022-06-29 12:45:59 +02:00
|
|
|
content_start = SEQ_time_left_handle_frame_get(scene, seq);
|
|
|
|
content_end = SEQ_time_right_handle_frame_get(scene, seq);
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
2021-10-25 04:24:41 +02:00
|
|
|
|
2022-06-02 01:39:40 +02:00
|
|
|
CLAMP(content_start,
|
2022-06-29 12:45:59 +02:00
|
|
|
SEQ_time_left_handle_frame_get(scene, seq),
|
|
|
|
SEQ_time_right_handle_frame_get(scene, seq));
|
|
|
|
CLAMP(content_end,
|
|
|
|
SEQ_time_left_handle_frame_get(scene, seq),
|
|
|
|
SEQ_time_right_handle_frame_get(scene, seq));
|
2021-10-25 04:24:41 +02:00
|
|
|
|
2021-06-29 20:12:19 +02:00
|
|
|
snap_data->target_snap_points[i] = content_start;
|
|
|
|
snap_data->target_snap_points[i + 1] = content_end;
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
}
|
2023-11-13 23:30:52 +01:00
|
|
|
BLI_assert(i <= snap_data->target_snap_points.size());
|
|
|
|
qsort(snap_data->target_snap_points.data(),
|
|
|
|
snap_data->target_snap_points.size(),
|
|
|
|
sizeof(int),
|
|
|
|
cmp_fn);
|
|
|
|
return true;
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \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);
|
2023-06-03 00:36:28 +02:00
|
|
|
const View2D *v2d = &t->region->v2d;
|
2021-06-29 20:12:19 +02:00
|
|
|
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)
|
|
|
|
{
|
VSE: Improve retiming UI
Currently retiming is quite awkward, when you need to retime multiple
strips strips in sync. It is possible to use meta strips, but this is
still not great. This is resolved by implementing selection.
General changes:
Gizmos are removed, since they are designed to operate only on active
strip and don't support selection.
Transform operator code is implemented for retiming data, which allows
more sophisticated manipulation.
Instead of drawing marker-like symbols, keyframes are drawn to
represent retiming data. Retiming handles are now called keys. To have
consistent names, DNA structures have been renamed.
Retiming data is drawn on strip as overlay.
UI changes:
Retiming tool is removed. To edit retiming data, press Ctrl + R, select
a key and move it. When retiming is edited, retiming menu and
context menu shows more relevant features, like making transitions.
Strip and retiming key selection can not be combined. It is possible to
use box select operator to select keys, if any key is selected.
Otherwise strips are selected.
Adding retiming keys is possible with I shortcut or from menu.
Retiming keys are always drawn at strip left and right boundary. These
keys do not really exist until they are selected. This is to simplify
retiming of strips that are resized. These keys are called "fake keys"
in code.
API changes:
Functions, properties and types related to retiming handles are renamed
to retiming keys:
retiming_handle_add() -> retiming_key_add()
retiming_handle_move() -> retiming_key_move()
retiming_handle_remove() -> retiming_key_remove()
retiming_handles -> retiming_keys
RetimingHandle -> RetimingKey
Retiming editing "mode" is activated by setting `Sequence.show_retiming_keys`.
Pull Request: https://projects.blender.org/blender/blender/pulls/109044
2023-09-27 01:45:59 +02:00
|
|
|
if (ELEM(t->data_type, &TransConvertType_SequencerImage, &TransConvertType_SequencerRetiming)) {
|
2023-07-13 17:59:52 +02:00
|
|
|
return nullptr;
|
2021-09-21 09:38:30 +02:00
|
|
|
}
|
|
|
|
|
2023-11-13 23:30:52 +01:00
|
|
|
TransSeqSnapData *snap_data = MEM_new<TransSeqSnapData>(__func__);
|
|
|
|
|
2022-04-28 12:50:22 +02:00
|
|
|
Scene *scene = t->scene;
|
|
|
|
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
|
2023-11-13 23:30:52 +01:00
|
|
|
short snap_mode = t->tsnap.mode;
|
2021-06-29 20:12:19 +02:00
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
blender::VectorSet<Sequence *> snap_sources = SEQ_query_selected_strips(seqbase);
|
|
|
|
blender::VectorSet<Sequence *> snap_targets = query_snap_targets(scene, snap_sources, true);
|
2021-07-26 14:55:14 +02:00
|
|
|
|
2023-11-13 23:30:52 +01:00
|
|
|
/* Build arrays of snap points. */
|
|
|
|
if (!seq_snap_source_points_build(scene, snap_data, snap_sources) ||
|
|
|
|
!seq_snap_target_points_build(scene, snap_mode, snap_data, snap_targets))
|
|
|
|
{
|
|
|
|
MEM_delete(snap_data);
|
2023-07-13 17:59:52 +02:00
|
|
|
return nullptr;
|
2021-07-26 14:55:14 +02:00
|
|
|
}
|
|
|
|
|
2021-06-29 20:12:19 +02:00
|
|
|
return snap_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void transform_snap_sequencer_data_free(TransSeqSnapData *data)
|
|
|
|
{
|
2023-11-13 23:30:52 +01:00
|
|
|
MEM_delete(data);
|
2021-06-29 20:12:19 +02:00
|
|
|
}
|
|
|
|
|
2021-06-29 23:08:41 +02:00
|
|
|
bool transform_snap_sequencer_calc(TransInfo *t)
|
2021-06-29 20:12:19 +02:00
|
|
|
{
|
2021-07-26 14:55:14 +02:00
|
|
|
const TransSeqSnapData *snap_data = t->tsnap.seq_context;
|
2023-07-13 17:59:52 +02:00
|
|
|
if (snap_data == nullptr) {
|
2021-07-26 14:55:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-07-14 13:22:40 +02:00
|
|
|
/* Prevent snapping when constrained to Y axis. */
|
|
|
|
if (t->con.mode & CON_APPLY && t->con.mode & CON_AXIS1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-29 20:12:19 +02:00
|
|
|
int best_dist = MAXFRAME, best_target_frame = 0, best_source_frame = 0;
|
|
|
|
|
2023-11-13 23:30:52 +01:00
|
|
|
for (int frame_src : snap_data->source_snap_points) {
|
|
|
|
int snap_source_frame = frame_src + round_fl_to_int(t->values[0]);
|
|
|
|
for (int snap_target_frame : snap_data->target_snap_points) {
|
2021-06-29 20:12:19 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-12 14:16:25 +01:00
|
|
|
t->tsnap.snap_target[0] = best_target_frame;
|
|
|
|
t->tsnap.snap_source[0] = best_source_frame;
|
2021-06-29 20:12:19 +02:00
|
|
|
return true;
|
|
|
|
}
|
2021-06-29 23:08:41 +02:00
|
|
|
|
|
|
|
void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec)
|
|
|
|
{
|
2023-01-12 14:16:25 +01:00
|
|
|
*vec += t->tsnap.snap_target[0] - t->tsnap.snap_source[0];
|
2021-06-29 23:08:41 +02:00
|
|
|
}
|
2022-04-28 12:50:22 +02:00
|
|
|
|
|
|
|
static int transform_snap_sequencer_to_closest_strip_ex(TransInfo *t, int frame_1, int frame_2)
|
|
|
|
{
|
|
|
|
Scene *scene = t->scene;
|
2023-11-13 23:30:52 +01:00
|
|
|
TransSeqSnapData *snap_data = MEM_new<TransSeqSnapData>(__func__);
|
2022-04-28 12:50:22 +02:00
|
|
|
|
2023-11-06 01:36:44 +01:00
|
|
|
blender::VectorSet<Sequence *> empty_col;
|
|
|
|
blender::VectorSet<Sequence *> snap_targets = query_snap_targets(scene, empty_col, false);
|
2022-04-28 12:50:22 +02:00
|
|
|
|
|
|
|
BLI_assert(frame_1 <= frame_2);
|
2023-11-13 23:30:52 +01:00
|
|
|
snap_data->source_snap_points.reinitialize(2);
|
2022-04-28 12:50:22 +02:00
|
|
|
snap_data->source_snap_points[0] = frame_1;
|
|
|
|
snap_data->source_snap_points[1] = frame_2;
|
|
|
|
|
|
|
|
short snap_mode = t->tsnap.mode;
|
2023-11-13 23:30:52 +01:00
|
|
|
|
2022-04-28 12:50:22 +02:00
|
|
|
/* Build arrays of snap points. */
|
|
|
|
seq_snap_target_points_build(scene, snap_mode, snap_data, snap_targets);
|
|
|
|
|
|
|
|
t->tsnap.seq_context = snap_data;
|
|
|
|
bool snap_success = transform_snap_sequencer_calc(t);
|
|
|
|
transform_snap_sequencer_data_free(snap_data);
|
2023-07-13 17:59:52 +02:00
|
|
|
t->tsnap.seq_context = nullptr;
|
2022-04-28 12:50:22 +02:00
|
|
|
|
|
|
|
float snap_offset = 0;
|
|
|
|
if (snap_success) {
|
2023-01-12 14:16:25 +01:00
|
|
|
t->tsnap.status |= (SNAP_TARGET_FOUND | SNAP_SOURCE_FOUND);
|
2022-04-28 12:50:22 +02:00
|
|
|
transform_snap_sequencer_apply_translate(t, &snap_offset);
|
|
|
|
}
|
|
|
|
else {
|
2023-01-12 14:16:25 +01:00
|
|
|
t->tsnap.status &= ~(SNAP_TARGET_FOUND | SNAP_SOURCE_FOUND);
|
2022-04-28 12:50:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return snap_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ED_transform_snap_sequencer_to_closest_strip_calc(Scene *scene,
|
|
|
|
ARegion *region,
|
|
|
|
int frame_1,
|
|
|
|
int frame_2,
|
|
|
|
int *r_snap_distance,
|
|
|
|
float *r_snap_frame)
|
|
|
|
{
|
2023-08-25 02:15:38 +02:00
|
|
|
TransInfo t = {nullptr};
|
2022-04-28 12:50:22 +02:00
|
|
|
t.scene = scene;
|
|
|
|
t.region = region;
|
|
|
|
t.values[0] = 0;
|
2022-07-22 04:44:39 +02:00
|
|
|
t.data_type = &TransConvertType_Sequencer;
|
2022-04-28 12:50:22 +02:00
|
|
|
|
2023-07-13 17:59:52 +02:00
|
|
|
t.tsnap.mode = eSnapMode(SEQ_tool_settings_snap_mode_get(scene));
|
2022-04-28 12:50:22 +02:00
|
|
|
*r_snap_distance = transform_snap_sequencer_to_closest_strip_ex(&t, frame_1, frame_2);
|
2023-01-12 14:16:25 +01:00
|
|
|
*r_snap_frame = t.tsnap.snap_target[0];
|
2022-04-28 12:50:22 +02:00
|
|
|
return validSnap(&t);
|
|
|
|
}
|
|
|
|
|
2023-08-25 02:25:58 +02:00
|
|
|
void ED_draw_sequencer_snap_point(ARegion *region, const float snap_point)
|
2022-04-28 12:50:22 +02:00
|
|
|
{
|
|
|
|
/* Reuse the snapping drawing code from the transform system. */
|
2023-08-25 02:15:38 +02:00
|
|
|
TransInfo t = {nullptr};
|
2022-04-28 12:50:22 +02:00
|
|
|
t.mode = TFM_SEQ_SLIDE;
|
|
|
|
t.modifiers = MOD_SNAP;
|
|
|
|
t.spacetype = SPACE_SEQ;
|
2023-08-25 02:15:38 +02:00
|
|
|
t.tsnap.flag = SCE_SNAP;
|
2023-01-12 14:16:25 +01:00
|
|
|
t.tsnap.status = (SNAP_TARGET_FOUND | SNAP_SOURCE_FOUND);
|
|
|
|
t.tsnap.snap_target[0] = snap_point;
|
2023-08-25 02:25:58 +02:00
|
|
|
t.region = region;
|
2022-04-28 12:50:22 +02:00
|
|
|
|
2023-08-25 02:25:58 +02:00
|
|
|
drawSnapping(&t);
|
2022-04-28 12:50:22 +02:00
|
|
|
}
|