diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index 961acac5e..b73bf2438 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -97,6 +97,7 @@ GraphEditor::GraphEditor(QWidget* parent) : QDockWidget(parent), row(NULL) { QWidget* central_value_widget = new QWidget(); value_layout = new QHBoxLayout(); value_layout->setMargin(0); + value_layout->addWidget(new QLabel("")); // a spacer so the layout doesn't jump central_value_widget->setLayout(value_layout); values->addWidget(central_value_widget); @@ -193,11 +194,11 @@ void GraphEditor::set_row(EffectRow *r) { current_row_desc->setText(0); } view->set_row(row); - update_panel(); + update_panel(); } bool GraphEditor::view_is_focused() { - return view->hasFocus() || header->hasFocus(); + return view->hasFocus() || header->hasFocus(); } void GraphEditor::set_key_button_enabled(bool e, int type) { diff --git a/project/effectrow.cpp b/project/effectrow.cpp index a9b7fd0f1..da203fd74 100644 --- a/project/effectrow.cpp +++ b/project/effectrow.cpp @@ -112,13 +112,11 @@ void EffectRow::toggle_key() { set_keyframe_now(ca); } else { for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); } } undo_stack.push(ca); - panel_effect_controls->update_keyframes(); - panel_sequence_viewer->viewer_widget->update(); + update_ui(false); } void EffectRow::goto_next_key() { diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 7bbd9b85e..0118a95fd 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include "panels/panels.h" #include "panels/timeline.h" @@ -42,6 +44,60 @@ GraphView::GraphView(QWidget* parent) : { setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); +} + +void GraphView::show_context_menu(const QPoint& pos) { + QMenu menu(this); + + QAction* reset_action = menu.addAction("Reset View"); + connect(reset_action, SIGNAL(triggered(bool)), this, SLOT(reset_view())); + + menu.exec(mapToGlobal(pos)); +} + +void GraphView::reset_view() { + zoom = 1.0; + set_scroll_x(0); + set_scroll_y(0); + emit zoom_changed(zoom); + update(); +} + +void GraphView::draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos) { + // draws last line's text + QString str = QString::number(line_no*GRAPH_SIZE); + int text_sz = vert ? fontMetrics().height() : fontMetrics().width(str); + if (text_sz < (next_line_pos - line_pos)) { + QRect text_rect = vert ? QRect(0, line_pos-50, 50, 50) : QRect(line_pos, height()-50, 50, 50); + p.drawText(text_rect, Qt::AlignBottom | Qt::AlignLeft, str); + } +} + +void GraphView::draw_lines(QPainter& p, bool vert) { + int last_line = INT_MIN; + int last_line_x = INT_MIN; + int lim = vert ? height() : width(); + int scroll = vert ? y_scroll : x_scroll; + for (int i=0;iseq != NULL) { // draw grid lines - //int graph_size = GRAPH_SIZE*zoom; - bool draw_text = true;//(fontMetrics().height() < graph_size && fontMetrics().width("0000") < graph_size); - p.setPen(Qt::gray); - int i = 0; - while (true) { - int line_x = (i*GRAPH_SIZE*zoom) - x_scroll; - if (line_x >= width()) { - break; - } - if (line_x >= 0) { - if (line_x > 0) p.drawLine(line_x, 0, line_x, height()); - if (draw_text) p.drawText(QRect(line_x, height()-50, 50, 50), Qt::AlignBottom | Qt::AlignLeft, QString::number(i*GRAPH_SIZE)); - } - i++; - } - i = 0; - while (true) { - int line_y = height() - (i*GRAPH_SIZE*zoom) + y_scroll; - if (line_y <= 0) { - break; - } - if (line_y <= height()) { - if (line_y < height()) p.drawLine(0, line_y, width(), line_y); - if (draw_text) p.drawText(QRect(0, line_y-50, 50, 50), Qt::AlignBottom | Qt::AlignLeft, QString::number(i*GRAPH_SIZE)); - } - i++; - } + + draw_lines(p, true); + draw_lines(p, false); // draw keyframes if (row != NULL) { QPen line_pen; line_pen.setWidth(2); - for (int i=0;ifieldCount();i++) { + for (int i=row->fieldCount()-1;i>=0;i--) { EffectField* field = row->field(i); if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { @@ -129,14 +161,14 @@ void GraphView::paintEvent(QPaintEvent *event) { if (last_key.type == KEYFRAME_TYPE_BEZIER && key.type == KEYFRAME_TYPE_BEZIER) { // cubic bezier bezier_path.cubicTo( - QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y+last_key.post_handle_y*zoom), + QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom), QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom), QPointF(key_x, key_y) ); } else if (key.type == KEYFRAME_TYPE_LINEAR) { // quadratic bezier // last keyframe is the bezier one bezier_path.quadTo( - QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y+last_key.post_handle_y*zoom), + QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom), QPointF(key_x, key_y) ); } else { @@ -205,10 +237,6 @@ void GraphView::mousePressEvent(QMouseEvent *event) { // selecting int sel_key = -1; int sel_key_field = -1; - if (!(event->modifiers() & Qt::ShiftModifier)) { - selected_keys.clear(); - selected_keys_fields.clear(); - } current_handle = BEZIER_HANDLE_NONE; if (row != NULL) { for (int i=0;ifieldCount();i++) { @@ -227,7 +255,7 @@ void GraphView::mousePressEvent(QMouseEvent *event) { break; } else { // selecting a handle - QPointF pre_point(key_x + key.pre_handle_x*zoom, key_y + key.pre_handle_y*zoom); + QPointF pre_point(key_x + key.pre_handle_x*zoom, key_y - key.pre_handle_y*zoom); if (event->pos().x() > pre_point.x()-BEZIER_HANDLE_SIZE && event->pos().x() < pre_point.x()+BEZIER_HANDLE_SIZE && event->pos().y() > pre_point.y()-BEZIER_HANDLE_SIZE @@ -239,7 +267,7 @@ void GraphView::mousePressEvent(QMouseEvent *event) { current_handle = BEZIER_HANDLE_PRE; break; } else { - QPointF post_point(key_x + key.post_handle_x*zoom, key_y + key.post_handle_y*zoom); + QPointF post_point(key_x + key.post_handle_x*zoom, key_y - key.post_handle_y*zoom); if (event->pos().x() > post_point.x()-BEZIER_HANDLE_SIZE && event->pos().x() < post_point.x()+BEZIER_HANDLE_SIZE && event->pos().y() > post_point.y()-BEZIER_HANDLE_SIZE @@ -255,11 +283,29 @@ void GraphView::mousePressEvent(QMouseEvent *event) { } } } + if (sel_key > -1) break; } } - if (sel_key > -1) { - selected_keys.append(sel_key); - selected_keys_fields.append(sel_key_field); + 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(); + } + if (sel_key > -1) { + selected_keys.append(sel_key); + selected_keys_fields.append(sel_key_field); + } } selected_keys_old_vals.clear(); @@ -293,24 +339,37 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { start_y = event->pos().y(); update(); } else { + bool shift = (event->modifiers() & Qt::ShiftModifier); switch (current_handle) { case BEZIER_HANDLE_NONE: for (int i=0;ifield(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].time = qRound(selected_keys_old_vals.at(i) + (double(event->pos().x() - start_x)/zoom)); - row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = qRound(selected_keys_old_doubles.at(i) + (double(start_y - event->pos().y())/zoom)); + if (shift) { + row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = selected_keys_old_doubles.at(i); + } else { + row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = qRound(selected_keys_old_doubles.at(i) + (double(start_y - event->pos().y())/zoom)); + } } moved_keys = true; update_ui(false); break; case BEZIER_HANDLE_PRE: row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].pre_handle_x = old_handle_x + double(event->pos().x() - start_x)/zoom; - row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].pre_handle_y = old_handle_y + double(start_y - event->pos().y())/zoom; + if (shift) { + row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].pre_handle_y = old_handle_y; + } else { + row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].pre_handle_y = old_handle_y + double(start_y - event->pos().y())/zoom; + } moved_keys = true; update_ui(false); break; case BEZIER_HANDLE_POST: row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].post_handle_x = old_handle_x + double(event->pos().x() - start_x)/zoom; - row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].post_handle_y = old_handle_y + double(start_y - event->pos().y())/zoom; + if (shift) { + row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].post_handle_y = old_handle_y; + } else { + row->field(selected_keys_fields.last())->keyframes[selected_keys.last()].post_handle_y = old_handle_y + double(start_y - event->pos().y())/zoom; + } moved_keys = true; update_ui(false); break; @@ -366,9 +425,13 @@ void GraphView::wheelEvent(QWheelEvent *event) { // set zoom if (event->angleDelta().y() != 0) { double zoom_diff = (GRAPH_ZOOM_SPEED*zoom); - if (event->angleDelta().y() < 0) zoom_diff = -zoom_diff; - zoom += zoom_diff; - emit zoom_changed(zoom); + double new_zoom = (event->angleDelta().y() < 0) ? zoom - zoom_diff : zoom + zoom_diff; + + // center zoom on screen + set_scroll_x(qRound(x_scroll + double(event->pos().x())*new_zoom - double(event->pos().x())*zoom)); + set_scroll_y(qRound(y_scroll + double(height()-event->pos().y())*new_zoom - double(height()-event->pos().y())*zoom)); + + set_zoom(new_zoom); redraw = true; } } @@ -379,17 +442,19 @@ void GraphView::wheelEvent(QWheelEvent *event) { } void GraphView::set_row(EffectRow *r) { - selected_keys.clear(); - selected_keys_fields.clear(); - selected_keys_old_vals.clear(); - selected_keys_old_doubles.clear(); - emit selection_changed(false, -1); - row = r; - if (row != NULL) { - field_visibility.resize(row->fieldCount()); - field_visibility.fill(true); + if (row != r) { + selected_keys.clear(); + selected_keys_fields.clear(); + selected_keys_old_vals.clear(); + selected_keys_old_doubles.clear(); + emit selection_changed(false, -1); + row = r; + if (row != NULL) { + field_visibility.resize(row->fieldCount()); + field_visibility.fill(true); + } + update(); } - update(); } void GraphView::set_selected_keyframe_type(int type) { @@ -419,6 +484,11 @@ void GraphView::set_scroll_y(int s) { emit y_scroll_changed(y_scroll); } +void GraphView::set_zoom(double z) { + zoom = z; + emit zoom_changed(zoom); +} + int GraphView::get_screen_x(double d) { return (d*zoom) - x_scroll; } diff --git a/ui/graphview.h b/ui/graphview.h index d7511184b..474ffee91 100644 --- a/ui/graphview.h +++ b/ui/graphview.h @@ -38,6 +38,7 @@ private: void set_scroll_x(int s); void set_scroll_y(int s); + void set_zoom(double z); int get_screen_x(double); int get_screen_y(double); @@ -56,7 +57,13 @@ private: int current_handle; + void draw_lines(QPainter &p, bool vert); + void draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos); + EffectRow* row; +private slots: + void show_context_menu(const QPoint& pos); + void reset_view(); }; #endif // GRAPHVIEW_H diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 4137f68e2..6db4164cf 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -252,6 +252,20 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { if (keyframe_index > -1) { selected_fields.append(rows.at(row_index)->field(field_index)); selected_keyframes.append(keyframe_index); + + // find other field with keyframes at the same time + long comp_time = rows.at(row_index)->field(field_index)->keyframes.at(keyframe_index).time; + for (int i=0;ifieldCount();i++) { + if (i != field_index) { + EffectField* f = rows.at(row_index)->field(i); + for (int j=0;jkeyframes.size();j++) { + if (f->keyframes.at(j).time == comp_time) { + selected_fields.append(f); + selected_keyframes.append(j); + } + } + } + } } }