VSE: Use edge panning

Add edge panning feature to transform operator. It works in same way as
in node editor, but Y axis is limited by usable range up to 128
channels.

Reviewed By: Severin

Differential Revision: https://developer.blender.org/D14310
This commit is contained in:
Richard Antalik 2022-04-04 14:25:13 +02:00
parent 3ce6c5adfc
commit e49fef45ce
Notes: blender-bot 2023-02-14 02:13:08 +01:00
Referenced by commit d5f5788b10, Keymap: remove reference to missing view2d_edge_pan property
5 changed files with 83 additions and 10 deletions

View File

@ -2893,10 +2893,12 @@ def km_sequencer(params):
("sequencer.slip", {"type": 'S', "value": 'PRESS'}, None),
("wm.context_set_int", {"type": 'O', "value": 'PRESS'},
{"properties": [("data_path", 'scene.sequence_editor.overlay_frame'), ("value", 0)]}),
("transform.seq_slide", {"type": 'G', "value": 'PRESS'}, None),
("transform.seq_slide", {"type": params.select_mouse, "value": 'CLICK_DRAG'}, None),
("transform.seq_slide", {"type": 'G', "value": 'PRESS'},
{"properties": [("view2d_edge_pan", True)]}),
("transform.seq_slide", {"type": params.select_mouse, "value": 'CLICK_DRAG'},
{"properties": [("view2d_edge_pan", True)]}),
("transform.transform", {"type": 'E', "value": 'PRESS'},
{"properties": [("mode", 'TIME_EXTEND')]}),
{"properties": [("mode", 'TIME_EXTEND'), ("view2d_edge_pan", True)]}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
("sequencer.select_side_of_frame", {"type": 'LEFT_BRACKET', "value": 'PRESS'},

View File

@ -447,6 +447,8 @@ typedef struct View2DEdgePanData {
struct ARegion *region;
/** View2d we're operating in. */
struct View2D *v2d;
/* Limit maximum pannable area */
struct rctf limit;
/** Panning should only start once being in the inside rect once (e.g. adding nodes can happen
* outside). */
@ -492,6 +494,12 @@ void UI_view2d_edge_pan_init(struct bContext *C,
float delay,
float zoom_influence);
/**
* Set area which can be panned
*/
void UI_view2d_edge_pan_set_limits(
struct View2DEdgePanData *vpd, float xmin, float xmax, float ymin, float ymax);
void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd);
/**

View File

@ -67,6 +67,7 @@ void UI_view2d_edge_pan_init(bContext *C,
vpd->area = CTX_wm_area(C);
vpd->region = CTX_wm_region(C);
vpd->v2d = &vpd->region->v2d;
BLI_rctf_init(&vpd->limit, -FLT_MAX, FLT_MAX, -FLT_MAX, FLT_MAX);
BLI_assert(speed_ramp > 0.0f);
vpd->inside_pad = inside_pad;
@ -87,6 +88,12 @@ void UI_view2d_edge_pan_init(bContext *C,
UI_view2d_edge_pan_reset(vpd);
}
void UI_view2d_edge_pan_set_limits(
View2DEdgePanData *vpd, float xmin, float xmax, float ymin, float ymax)
{
BLI_rctf_init(&vpd->limit, xmin, xmax, ymin, ymax);
}
void UI_view2d_edge_pan_reset(View2DEdgePanData *vpd)
{
vpd->edge_pan_start_time_x = 0.0;
@ -220,20 +227,23 @@ void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, const int xy[
vpd->enabled = true;
}
rctf *cur = &vpd->v2d->cur;
rctf *limit = &vpd->limit;
int pan_dir_x = 0;
int pan_dir_y = 0;
if (vpd->enabled && ((vpd->outside_pad == 0) || BLI_rcti_isect_pt_v(&outside_rect, xy))) {
/* Find whether the mouse is beyond X and Y edges. */
if (xy[0] > inside_rect.xmax) {
if (xy[0] > inside_rect.xmax && cur->xmax < limit->xmax) {
pan_dir_x = 1;
}
else if (xy[0] < inside_rect.xmin) {
else if (xy[0] < inside_rect.xmin && cur->xmin > limit->xmin) {
pan_dir_x = -1;
}
if (xy[1] > inside_rect.ymax) {
if (xy[1] > inside_rect.ymax && cur->ymax < limit->ymax) {
pan_dir_y = 1;
}
else if (xy[1] < inside_rect.ymin) {
else if (xy[1] < inside_rect.ymin && cur->ymin > limit->ymin) {
pan_dir_y = -1;
}
}

View File

@ -35,6 +35,13 @@
#include "transform.h"
#include "transform_convert.h"
#define SEQ_EDGE_PAN_INSIDE_PAD 2
#define SEQ_EDGE_PAN_OUTSIDE_PAD 0 /* Disable clamping for panning, use whole screen. */
#define SEQ_EDGE_PAN_SPEED_RAMP 1
#define SEQ_EDGE_PAN_MAX_SPEED 4 /* In UI units per second, slower than default. */
#define SEQ_EDGE_PAN_DELAY 1.0f
#define SEQ_EDGE_PAN_ZOOM_INFLUENCE 0.5f
/** Used for sequencer transform. */
typedef struct TransDataSeq {
struct Sequence *seq;
@ -55,6 +62,10 @@ typedef struct TransSeq {
TransDataSeq *tdseq;
int selection_channel_range_min;
int selection_channel_range_max;
/* Initial rect of the view2d, used for computing offset during edge panning */
rctf initial_v2d_cur;
View2DEdgePanData edge_pan;
} TransSeq;
/* -------------------------------------------------------------------- */
@ -673,6 +684,18 @@ void createTransSeqData(TransInfo *t)
td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
/* Custom data to enable edge panning during transformation. */
UI_view2d_edge_pan_init(t->context,
&ts->edge_pan,
SEQ_EDGE_PAN_INSIDE_PAD,
SEQ_EDGE_PAN_OUTSIDE_PAD,
SEQ_EDGE_PAN_SPEED_RAMP,
SEQ_EDGE_PAN_MAX_SPEED,
SEQ_EDGE_PAN_DELAY,
SEQ_EDGE_PAN_ZOOM_INFLUENCE);
UI_view2d_edge_pan_set_limits(&ts->edge_pan, -FLT_MAX, FLT_MAX, 1, MAXSEQ + 1);
ts->initial_v2d_cur = t->region->v2d.cur;
/* loop 2: build transdata array */
SeqToTransData_build(t, ed->seqbasep, td, td2d, tdsq);
@ -710,8 +733,36 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s
}
}
static void view2d_edge_pan_loc_compensate(TransInfo *t, float loc_in[2], float r_loc[2])
{
TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
/* Initial and current view2D rects for additional transform due to view panning and zooming */
const rctf *rect_src = &ts->initial_v2d_cur;
const rctf *rect_dst = &t->region->v2d.cur;
copy_v2_v2(r_loc, loc_in);
/* Additional offset due to change in view2D rect. */
BLI_rctf_transform_pt_v(rect_dst, rect_src, r_loc, r_loc);
}
static void flushTransSeq(TransInfo *t)
{
TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
if (t->options & CTX_VIEW2D_EDGE_PAN) {
if (t->state == TRANS_CANCEL) {
UI_view2d_edge_pan_cancel(t->context, &ts->edge_pan);
}
else {
/* Edge panning functions expect window coordinates, mval is relative to region */
const int xy[2] = {
t->region->winrct.xmin + t->mval[0],
t->region->winrct.ymin + t->mval[1],
};
UI_view2d_edge_pan_apply(t->context, &ts->edge_pan, xy);
}
}
/* Editing null check already done */
ListBase *seqbasep = seqbase_active_get(t);
@ -727,7 +778,9 @@ static void flushTransSeq(TransInfo *t)
for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
new_frame = round_fl_to_int(td2d->loc[0]);
float loc[2];
view2d_edge_pan_loc_compensate(t, td->loc, loc);
new_frame = round_fl_to_int(loc[0]);
switch (tdsq->sel_flag) {
case SELECT:
@ -735,7 +788,7 @@ static void flushTransSeq(TransInfo *t)
const int offset = new_frame - tdsq->start_offset - seq->start;
SEQ_transform_translate_sequence(t->scene, seq, offset);
}
seq->machine = round_fl_to_int(td2d->loc[1]);
seq->machine = round_fl_to_int(loc[1]);
CLAMP(seq->machine, 1, MAXSEQ);
break;

View File

@ -1255,7 +1255,7 @@ static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot)
WM_operatortype_props_advanced_begin(ot);
Transform_Properties(ot, P_SNAP);
Transform_Properties(ot, P_SNAP | P_VIEW2D_EDGE_PAN);
}
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot)