diff --git a/olive.pro b/olive.pro index 66dc5ed66..234d5c5f1 100644 --- a/olive.pro +++ b/olive.pro @@ -110,7 +110,8 @@ SOURCES += \ ui/graphview.cpp \ ui/keyframedrawing.cpp \ ui/clickablelabel.cpp \ - project/keyframe.cpp + project/keyframe.cpp \ + ui/rectangleselect.cpp HEADERS += \ mainwindow.h \ @@ -195,7 +196,8 @@ HEADERS += \ ui/graphview.h \ ui/keyframedrawing.h \ ui/clickablelabel.h \ - project/keyframe.h + project/keyframe.h \ + ui/rectangleselect.h FORMS += diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 37b9dc98e..5482df7d8 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -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); } -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) : QDockWidget(parent), cursor_frame(0), @@ -184,7 +178,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector can_import = m->ready; if (m->using_inout) { 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_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()) { case MEDIA_TYPE_FOOTAGE: // 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; } else { 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;jaudio_tracks.size();j++) { - if (m->audio_tracks.at(j).enabled) { - g.track = j; - g.media_stream = m->audio_tracks.at(j).file_index; - ghosts.append(g); - audio_ghosts = true; - } + if (m->audio_tracks.at(j).enabled) { + g.track = j; + g.media_stream = m->audio_tracks.at(j).file_index; + ghosts.append(g); + audio_ghosts = true; + } } for (int j=0;jvideo_tracks.size();j++) { - if (m->video_tracks.at(j).enabled) { - g.track = -1-j; - g.media_stream = m->video_tracks.at(j).file_index; - ghosts.append(g); - video_ghosts = true; - } + if (m->video_tracks.at(j).enabled) { + g.track = -1-j; + g.media_stream = m->video_tracks.at(j).file_index; + ghosts.append(g); + video_ghosts = true; + } } break; case MEDIA_TYPE_SEQUENCE: diff --git a/panels/timeline.h b/panels/timeline.h index a76adc3a9..278aacbb3 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -38,7 +38,6 @@ struct FootageStream; long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate); int getScreenPointFromFrame(double zoom, long frame); 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); 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& ignore = QVector()); diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 0118a95fd..14ef7ddae 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -14,12 +14,14 @@ #include "ui/keyframedrawing.h" #include "project/undo.h" #include "project/effect.h" +#include "ui/rectangleselect.h" #include "debug.h" #define GRAPH_ZOOM_SPEED 0.05 #define GRAPH_SIZE 100 #define BEZIER_HANDLE_SIZE 3 +#define BEZIER_LINE_SIZE 2 #define BEZIER_HANDLE_NONE 1 #define BEZIER_HANDLE_PRE 2 @@ -40,7 +42,8 @@ GraphView::GraphView(QWidget* parent) : zoom(1.0), row(NULL), moved_keys(false), - current_handle(BEZIER_HANDLE_NONE) + current_handle(BEZIER_HANDLE_NONE), + rect_select(false) { setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); @@ -114,7 +117,7 @@ void GraphView::paintEvent(QPaintEvent *event) { // draw keyframes if (row != NULL) { QPen line_pen; - line_pen.setWidth(2); + line_pen.setWidth(BEZIER_LINE_SIZE); for (int i=row->fieldCount()-1;i>=0;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); } - 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;kseq->playhead); 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); @@ -230,15 +246,16 @@ void GraphView::paintEvent(QPaintEvent *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) { + 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;ifieldCount();i++) { EffectField* field = row->field(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; } - } - bool already_selected = false; - for (int i=0;imodifiers() & 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(); - } + + bool already_selected = false; if (sel_key > -1) { - selected_keys.append(sel_key); - selected_keys_fields.append(sel_key_field); + for (int i=0;imodifiers() & Qt::ShiftModifier)) { + selected_keys.removeAt(i); + selected_keys_fields.removeAt(i); + } + already_selected = true; + break; + } + } } - } - - selected_keys_old_vals.clear(); - selected_keys_old_doubles.clear(); - - int selected_key_type = -1; - - for (int i=0;ifield(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; + if (!already_selected) { + if (!(event->modifiers() & Qt::ShiftModifier)) { + selected_keys.clear(); + selected_keys_fields.clear(); + } + if (sel_key > -1) { + selected_keys.append(sel_key); + selected_keys_fields.append(sel_key_field); + } else { + rect_select = true; + rect_select_x = event->pos().x(); + rect_select_y = event->pos().y(); + rect_select_w = 0; + rect_select_h = 0; + rect_select_offset = selected_keys.size(); + } } + + selection_update(); } - - update(); - - emit selection_changed(selected_keys.size() > 0, selected_key_type); } void GraphView::mouseMoveEvent(QMouseEvent *event) { @@ -338,6 +346,35 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { start_x = event->pos().x(); start_y = event->pos().y(); 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;ifieldCount();i++) { + EffectField* f = row->field(i); + for (int j=0;jkeyframes.size();j++) { + bool already_selected = false; + for (int k=0;kkeyframes.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 { bool shift = (event->modifiers() & Qt::ShiftModifier); switch (current_handle) { @@ -409,6 +446,11 @@ void GraphView::mouseReleaseEvent(QMouseEvent *event) { } moved_keys = false; mousedown = false; + if (rect_select) { + rect_select = false; + selection_update(); + update(); + } } void GraphView::wheelEvent(QWheelEvent *event) { @@ -496,3 +538,26 @@ int GraphView::get_screen_x(double d) { int GraphView::get_screen_y(double d) { 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;ifield(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); +} diff --git a/ui/graphview.h b/ui/graphview.h index 474ffee91..6a694a999 100644 --- a/ui/graphview.h +++ b/ui/graphview.h @@ -43,6 +43,8 @@ private: int get_screen_x(double); int get_screen_y(double); + void selection_update(); + QVector field_visibility; QVector 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); 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: void show_context_menu(const QPoint& pos); void reset_view(); diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 6db4164cf..bbe8d7dac 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -15,6 +15,7 @@ #include "ui/keyframedrawing.h" #include "ui/clickablelabel.h" #include "ui/resizablescrollbar.h" +#include "ui/rectangleselect.h" #include #include diff --git a/ui/rectangleselect.cpp b/ui/rectangleselect.cpp new file mode 100644 index 000000000..b4a9348ce --- /dev/null +++ b/ui/rectangleselect.cpp @@ -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); +} diff --git a/ui/rectangleselect.h b/ui/rectangleselect.h new file mode 100644 index 000000000..40eee2aeb --- /dev/null +++ b/ui/rectangleselect.h @@ -0,0 +1,8 @@ +#ifndef RECTANGLESELECT_H +#define RECTANGLESELECT_H + +#include + +void draw_selection_rectangle(QPainter& painter, const QRect& rect); + +#endif // RECTANGLESELECT_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 2e11b423e..71cdca314 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -21,6 +21,7 @@ #include "ui/resizablescrollbar.h" #include "dialogs/newsequencedialog.h" #include "mainwindow.h" +#include "ui/rectangleselect.h" #include "debug.h" #include "project/effect.h" @@ -1272,9 +1273,9 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { Clip* c = NULL; 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) { - 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