rect select for graph editor

This commit is contained in:
itsmattkc
2019-01-04 16:33:07 +11:00
parent 6c8ec756d8
commit 28fbab2d78
9 changed files with 161 additions and 75 deletions
+4 -2
View File
@@ -110,7 +110,8 @@ SOURCES += \
ui/graphview.cpp \ ui/graphview.cpp \
ui/keyframedrawing.cpp \ ui/keyframedrawing.cpp \
ui/clickablelabel.cpp \ ui/clickablelabel.cpp \
project/keyframe.cpp project/keyframe.cpp \
ui/rectangleselect.cpp
HEADERS += \ HEADERS += \
mainwindow.h \ mainwindow.h \
@@ -195,7 +196,8 @@ HEADERS += \
ui/graphview.h \ ui/graphview.h \
ui/keyframedrawing.h \ ui/keyframedrawing.h \
ui/clickablelabel.h \ ui/clickablelabel.h \
project/keyframe.h project/keyframe.h \
ui/rectangleselect.h
FORMS += FORMS +=
+14 -20
View File
@@ -43,12 +43,6 @@ long refactor_frame_number(long framenumber, double source_frame_rate, double ta
return qRound(((double)framenumber/source_frame_rate)*target_frame_rate); return qRound(((double)framenumber/source_frame_rate)*target_frame_rate);
} }
void draw_selection_rectangle(QPainter& painter, const QRect& rect) {
painter.setPen(QColor(204, 204, 204));
painter.setBrush(QColor(0, 0, 0, 32));
painter.drawRect(rect);
}
Timeline::Timeline(QWidget *parent) : Timeline::Timeline(QWidget *parent) :
QDockWidget(parent), QDockWidget(parent),
cursor_frame(0), cursor_frame(0),
@@ -184,7 +178,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
can_import = m->ready; can_import = m->ready;
if (m->using_inout) { if (m->using_inout) {
double source_fr = 30; double source_fr = 30;
if (m->video_tracks.size() > 0 && !qIsNull(m->video_tracks.at(0).video_frame_rate)) source_fr = m->video_tracks.at(0).video_frame_rate; if (m->video_tracks.size() > 0 && !qIsNull(m->video_tracks.at(0).video_frame_rate)) source_fr = m->video_tracks.at(0).video_frame_rate;
default_clip_in = refactor_frame_number(m->in, source_fr, seq->frame_rate); default_clip_in = refactor_frame_number(m->in, source_fr, seq->frame_rate);
default_clip_out = refactor_frame_number(m->out, source_fr, seq->frame_rate); default_clip_out = refactor_frame_number(m->out, source_fr, seq->frame_rate);
} }
@@ -216,7 +210,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
switch (medium->get_type()) { switch (medium->get_type()) {
case MEDIA_TYPE_FOOTAGE: case MEDIA_TYPE_FOOTAGE:
// is video source a still image? // is video source a still image?
if (m->video_tracks.size() > 0 && m->video_tracks.at(0).infinite_length && m->audio_tracks.size() == 0) { if (m->video_tracks.size() > 0 && m->video_tracks.at(0).infinite_length && m->audio_tracks.size() == 0) {
g.out = g.in + 100; g.out = g.in + 100;
} else { } else {
long length = m->get_length_in_frames(seq->frame_rate); long length = m->get_length_in_frames(seq->frame_rate);
@@ -227,20 +221,20 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
} }
for (int j=0;j<m->audio_tracks.size();j++) { for (int j=0;j<m->audio_tracks.size();j++) {
if (m->audio_tracks.at(j).enabled) { if (m->audio_tracks.at(j).enabled) {
g.track = j; g.track = j;
g.media_stream = m->audio_tracks.at(j).file_index; g.media_stream = m->audio_tracks.at(j).file_index;
ghosts.append(g); ghosts.append(g);
audio_ghosts = true; audio_ghosts = true;
} }
} }
for (int j=0;j<m->video_tracks.size();j++) { for (int j=0;j<m->video_tracks.size();j++) {
if (m->video_tracks.at(j).enabled) { if (m->video_tracks.at(j).enabled) {
g.track = -1-j; g.track = -1-j;
g.media_stream = m->video_tracks.at(j).file_index; g.media_stream = m->video_tracks.at(j).file_index;
ghosts.append(g); ghosts.append(g);
video_ghosts = true; video_ghosts = true;
} }
} }
break; break;
case MEDIA_TYPE_SEQUENCE: case MEDIA_TYPE_SEQUENCE:
-1
View File
@@ -38,7 +38,6 @@ struct FootageStream;
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate); long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
int getScreenPointFromFrame(double zoom, long frame); int getScreenPointFromFrame(double zoom, long frame);
long getFrameFromScreenPoint(double zoom, int x); long getFrameFromScreenPoint(double zoom, int x);
void draw_selection_rectangle(QPainter& painter, const QRect& rect);
bool selection_contains_transition(const Selection& s, Clip* c, int type); bool selection_contains_transition(const Selection& s, Clip* c, int type);
void move_clip(ComboAction *ca, Clip *c, long iin, long iout, long iclip_in, int itrack, bool verify_transitions = true, bool relative = false); void move_clip(ComboAction *ca, Clip *c, long iin, long iout, long iclip_in, int itrack, bool verify_transitions = true, bool relative = false);
void ripple_clips(ComboAction *ca, Sequence* s, long point, long length, const QVector<int>& ignore = QVector<int>()); void ripple_clips(ComboAction *ca, Sequence* s, long point, long length, const QVector<int>& ignore = QVector<int>());
+115 -50
View File
@@ -14,12 +14,14 @@
#include "ui/keyframedrawing.h" #include "ui/keyframedrawing.h"
#include "project/undo.h" #include "project/undo.h"
#include "project/effect.h" #include "project/effect.h"
#include "ui/rectangleselect.h"
#include "debug.h" #include "debug.h"
#define GRAPH_ZOOM_SPEED 0.05 #define GRAPH_ZOOM_SPEED 0.05
#define GRAPH_SIZE 100 #define GRAPH_SIZE 100
#define BEZIER_HANDLE_SIZE 3 #define BEZIER_HANDLE_SIZE 3
#define BEZIER_LINE_SIZE 2
#define BEZIER_HANDLE_NONE 1 #define BEZIER_HANDLE_NONE 1
#define BEZIER_HANDLE_PRE 2 #define BEZIER_HANDLE_PRE 2
@@ -40,7 +42,8 @@ GraphView::GraphView(QWidget* parent) :
zoom(1.0), zoom(1.0),
row(NULL), row(NULL),
moved_keys(false), moved_keys(false),
current_handle(BEZIER_HANDLE_NONE) current_handle(BEZIER_HANDLE_NONE),
rect_select(false)
{ {
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
@@ -114,7 +117,7 @@ void GraphView::paintEvent(QPaintEvent *event) {
// draw keyframes // draw keyframes
if (row != NULL) { if (row != NULL) {
QPen line_pen; QPen line_pen;
line_pen.setWidth(2); line_pen.setWidth(BEZIER_LINE_SIZE);
for (int i=row->fieldCount()-1;i>=0;i--) { for (int i=row->fieldCount()-1;i>=0;i--) {
EffectField* field = row->field(i); EffectField* field = row->field(i);
@@ -209,7 +212,15 @@ void GraphView::paintEvent(QPaintEvent *event) {
p.drawEllipse(post_point, BEZIER_HANDLE_SIZE, BEZIER_HANDLE_SIZE); p.drawEllipse(post_point, BEZIER_HANDLE_SIZE, BEZIER_HANDLE_SIZE);
} }
draw_keyframe(p, key.type, key_x, key_y, (selected_keys.contains(sorted_keys.at(j)) && selected_keys_fields.contains(i))); bool selected = false;
for (int k=0;k<selected_keys.size();k++) {
if (selected_keys.at(k) == sorted_keys.at(j) && selected_keys_fields.at(k) == i) {
selected = true;
break;
}
}
draw_keyframe(p, key.type, key_x, key_y, selected);
} }
} }
} }
@@ -219,6 +230,11 @@ void GraphView::paintEvent(QPaintEvent *event) {
p.setPen(Qt::red); p.setPen(Qt::red);
int playhead_x = get_screen_x(panel_sequence_viewer->seq->playhead); int playhead_x = get_screen_x(panel_sequence_viewer->seq->playhead);
p.drawLine(playhead_x, 0, playhead_x, height()); p.drawLine(playhead_x, 0, playhead_x, height());
if (rect_select) {
draw_selection_rectangle(p, QRect(rect_select_x, rect_select_y, rect_select_w, rect_select_h));
p.setBrush(Qt::NoBrush);
}
} }
p.setPen(Qt::white); p.setPen(Qt::white);
@@ -230,15 +246,16 @@ void GraphView::paintEvent(QPaintEvent *event) {
} }
void GraphView::mousePressEvent(QMouseEvent *event) { void GraphView::mousePressEvent(QMouseEvent *event) {
mousedown = true;
start_x = event->pos().x();
start_y = event->pos().y();
// selecting
int sel_key = -1;
int sel_key_field = -1;
current_handle = BEZIER_HANDLE_NONE;
if (row != NULL) { if (row != NULL) {
mousedown = true;
start_x = event->pos().x();
start_y = event->pos().y();
// selecting
int sel_key = -1;
int sel_key_field = -1;
current_handle = BEZIER_HANDLE_NONE;
for (int i=0;i<row->fieldCount();i++) { for (int i=0;i<row->fieldCount();i++) {
EffectField* field = row->field(i); EffectField* field = row->field(i);
if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
@@ -285,49 +302,40 @@ void GraphView::mousePressEvent(QMouseEvent *event) {
} }
if (sel_key > -1) break; if (sel_key > -1) break;
} }
}
bool already_selected = false; bool already_selected = false;
for (int i=0;i<selected_keys.size();i++) {
if (selected_keys.at(i) == sel_key && selected_keys_fields.at(i) == sel_key_field) {
if ((event->modifiers() & Qt::ShiftModifier)) {
selected_keys.removeAt(i);
selected_keys_fields.removeAt(i);
}
already_selected = true;
break;
}
}
if (!already_selected) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
selected_keys.clear();
selected_keys_fields.clear();
}
if (sel_key > -1) { if (sel_key > -1) {
selected_keys.append(sel_key); for (int i=0;i<selected_keys.size();i++) {
selected_keys_fields.append(sel_key_field); if (selected_keys.at(i) == sel_key && selected_keys_fields.at(i) == sel_key_field) {
if ((event->modifiers() & Qt::ShiftModifier)) {
selected_keys.removeAt(i);
selected_keys_fields.removeAt(i);
}
already_selected = true;
break;
}
}
} }
} if (!already_selected) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
selected_keys_old_vals.clear(); selected_keys.clear();
selected_keys_old_doubles.clear(); selected_keys_fields.clear();
}
int selected_key_type = -1; if (sel_key > -1) {
selected_keys.append(sel_key);
for (int i=0;i<selected_keys.size();i++) { selected_keys_fields.append(sel_key_field);
const EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i)); } else {
selected_keys_old_vals.append(key.time); rect_select = true;
selected_keys_old_doubles.append(key.data.toDouble()); rect_select_x = event->pos().x();
rect_select_y = event->pos().y();
if (selected_key_type == -1) { rect_select_w = 0;
selected_key_type = key.type; rect_select_h = 0;
} else if (selected_key_type != key.type) { rect_select_offset = selected_keys.size();
selected_key_type = -2; }
} }
selection_update();
} }
update();
emit selection_changed(selected_keys.size() > 0, selected_key_type);
} }
void GraphView::mouseMoveEvent(QMouseEvent *event) { void GraphView::mouseMoveEvent(QMouseEvent *event) {
@@ -338,6 +346,35 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) {
start_x = event->pos().x(); start_x = event->pos().x();
start_y = event->pos().y(); start_y = event->pos().y();
update(); update();
} else if (rect_select) {
rect_select_w = event->pos().x() - rect_select_x;
rect_select_h = event->pos().y() - rect_select_y;
selected_keys.resize(rect_select_offset);
selected_keys_fields.resize(rect_select_offset);
for (int i=0;i<row->fieldCount();i++) {
EffectField* f = row->field(i);
for (int j=0;j<f->keyframes.size();j++) {
bool already_selected = false;
for (int k=0;k<selected_keys.size();k++) {
if (selected_keys.at(k) == j && selected_keys_fields.at(k) == i) {
already_selected = true;
break;
}
}
if (!already_selected) {
QPoint key_screen_point(get_screen_x(f->keyframes.at(j).time), get_screen_y(f->keyframes.at(j).data.toDouble()));
QRect select_rect(rect_select_x, rect_select_y, rect_select_w, rect_select_h);
if (select_rect.contains(key_screen_point)) {
selected_keys.append(j);
selected_keys_fields.append(i);
}
}
}
}
update();
} else { } else {
bool shift = (event->modifiers() & Qt::ShiftModifier); bool shift = (event->modifiers() & Qt::ShiftModifier);
switch (current_handle) { switch (current_handle) {
@@ -409,6 +446,11 @@ void GraphView::mouseReleaseEvent(QMouseEvent *event) {
} }
moved_keys = false; moved_keys = false;
mousedown = false; mousedown = false;
if (rect_select) {
rect_select = false;
selection_update();
update();
}
} }
void GraphView::wheelEvent(QWheelEvent *event) { void GraphView::wheelEvent(QWheelEvent *event) {
@@ -496,3 +538,26 @@ int GraphView::get_screen_x(double d) {
int GraphView::get_screen_y(double d) { int GraphView::get_screen_y(double d) {
return height() + y_scroll - d*zoom; return height() + y_scroll - d*zoom;
} }
void GraphView::selection_update() {
selected_keys_old_vals.clear();
selected_keys_old_doubles.clear();
int selected_key_type = -1;
for (int i=0;i<selected_keys.size();i++) {
const EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
selected_keys_old_vals.append(key.time);
selected_keys_old_doubles.append(key.data.toDouble());
if (selected_key_type == -1) {
selected_key_type = key.type;
} else if (selected_key_type != key.type) {
selected_key_type = -2;
}
}
update();
emit selection_changed(selected_keys.size() > 0, selected_key_type);
}
+9
View File
@@ -43,6 +43,8 @@ private:
int get_screen_x(double); int get_screen_x(double);
int get_screen_y(double); int get_screen_y(double);
void selection_update();
QVector<bool> field_visibility; QVector<bool> field_visibility;
QVector<int> selected_keys; QVector<int> selected_keys;
@@ -61,6 +63,13 @@ private:
void draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos); void draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos);
EffectRow* row; EffectRow* row;
bool rect_select;
int rect_select_x;
int rect_select_y;
int rect_select_w;
int rect_select_h;
int rect_select_offset;
private slots: private slots:
void show_context_menu(const QPoint& pos); void show_context_menu(const QPoint& pos);
void reset_view(); void reset_view();
+1
View File
@@ -15,6 +15,7 @@
#include "ui/keyframedrawing.h" #include "ui/keyframedrawing.h"
#include "ui/clickablelabel.h" #include "ui/clickablelabel.h"
#include "ui/resizablescrollbar.h" #include "ui/resizablescrollbar.h"
#include "ui/rectangleselect.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QtMath> #include <QtMath>
+7
View File
@@ -0,0 +1,7 @@
#include "rectangleselect.h"
void draw_selection_rectangle(QPainter& painter, const QRect& rect) {
painter.setPen(QColor(204, 204, 204));
painter.setBrush(QColor(0, 0, 0, 32));
painter.drawRect(rect);
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef RECTANGLESELECT_H
#define RECTANGLESELECT_H
#include <QPainter>
void draw_selection_rectangle(QPainter& painter, const QRect& rect);
#endif // RECTANGLESELECT_H
+3 -2
View File
@@ -21,6 +21,7 @@
#include "ui/resizablescrollbar.h" #include "ui/resizablescrollbar.h"
#include "dialogs/newsequencedialog.h" #include "dialogs/newsequencedialog.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "ui/rectangleselect.h"
#include "debug.h" #include "debug.h"
#include "project/effect.h" #include "project/effect.h"
@@ -1272,9 +1273,9 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
Clip* c = NULL; Clip* c = NULL;
if (g.clip != -1) c = sequence->clips.at(g.clip); if (g.clip != -1) c = sequence->clips.at(g.clip);
const FootageStream* ms = NULL; const FootageStream* ms = NULL;
if (g.clip != -1 && c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) { if (g.clip != -1 && c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) {
ms = c->media->to_footage()->get_stream_from_file_index(c->track < 0, c->media_stream); ms = c->media->to_footage()->get_stream_from_file_index(c->track < 0, c->media_stream);
} }
// validate ghosts for trimming // validate ghosts for trimming