numerous keyframe improvements

This commit is contained in:
itsmattkc
2019-01-04 21:01:36 +11:00
parent b36f54c11d
commit a2eef2e829
13 changed files with 217 additions and 64 deletions
+5
View File
@@ -206,6 +206,7 @@ MainWindow::MainWindow(QWidget *parent) :
autorecovery_filename = data_dir + "/autorecovery.ove";
if (QFile::exists(autorecovery_filename)) {
if (QMessageBox::question(NULL, "Auto-recovery", "Olive didn't close properly and an autorecovery file was detected. Would you like to open it?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
enable_launch_with_project = false;
open_project_worker(autorecovery_filename, true);
}
}
@@ -258,12 +259,16 @@ void MainWindow::delete_slot() {
panel_project->delete_selected_media();
} else if (panel_effect_controls->keyframe_focus()) {
panel_effect_controls->delete_selected_keyframes();
} else if (panel_graph_editor->view_is_focused()) {
panel_graph_editor->delete_selected_keys();
}
}
void MainWindow::select_all() {
if (panel_timeline->focused()) {
panel_timeline->select_all();
} else if (panel_graph_editor->view_is_focused()) {
panel_graph_editor->select_all();
}
}
+8
View File
@@ -202,6 +202,14 @@ bool GraphEditor::view_is_focused() {
return view->hasFocus() || header->hasFocus();
}
void GraphEditor::delete_selected_keys() {
view->delete_selected_keys();
}
void GraphEditor::select_all() {
view->select_all();
}
void GraphEditor::set_key_button_enabled(bool e, int type) {
linear_button->setEnabled(e);
linear_button->setChecked(type == KEYFRAME_TYPE_LINEAR);
+3 -1
View File
@@ -18,7 +18,9 @@ public:
GraphEditor(QWidget* parent = 0);
void update_panel();
void set_row(EffectRow* r);
bool view_is_focused();
bool view_is_focused();
void delete_selected_keys();
void select_all();
private:
GraphView* view;
TimelineHeader* header;
-1
View File
@@ -23,7 +23,6 @@ class QXmlStreamWriter;
class Effect;
class EffectRow;
class CheckboxEx;
class KeyframeDelete;
struct EffectMeta {
QString name;
+2 -3
View File
@@ -8,7 +8,6 @@ class Effect;
class QGridLayout;
class EffectField;
class QLabel;
class KeyframeDelete;
class QPushButton;
class ComboAction;
class QHBoxLayout;
@@ -23,8 +22,8 @@ public:
EffectField* add_field(int type, const QString &id, int colspan = 1);
EffectField* field(int i);
int fieldCount();
void set_keyframe_now(ComboAction *ca);
void delete_keyframe_at_time(ComboAction *ca, long time);
void set_keyframe_now(ComboAction *ca);
void delete_keyframe_at_time(ComboAction *ca, long time);
ClickableLabel* label;
Effect* parent_effect;
bool savable;
+37
View File
@@ -1,5 +1,10 @@
#include "keyframe.h"
#include <QVector>
#include "effectfield.h"
#include "undo.h"
#include "panels/panels.h"
EffectKeyframe::EffectKeyframe() {
pre_handle_x = -40;
@@ -7,3 +12,35 @@ EffectKeyframe::EffectKeyframe() {
post_handle_x = 40;
post_handle_y = 0;
}
void delete_keyframes(QVector<EffectField *>& selected_key_fields, QVector<int> &selected_keys) {
QVector<EffectField*> fields;
QVector<int> key_indices;
for (int i=0;i<selected_keys.size();i++) {
bool added = false;
for (int j=0;j<key_indices.size();j++) {
if (key_indices.at(j) < selected_keys.at(i)) {
key_indices.insert(j, selected_keys.at(i));
fields.insert(j, selected_key_fields.at(i));
added = true;
break;
}
}
if (!added) {
key_indices.append(selected_keys.at(i));
fields.append(selected_key_fields.at(i));
}
}
if (fields.size() > 0) {
ComboAction* ca = new ComboAction();
for (int i=0;i<key_indices.size();i++) {
ca->append(new KeyframeDelete(fields.at(i), key_indices.at(i)));
}
undo_stack.push(ca);
selected_keys.clear();
selected_key_fields.clear();
update_ui(false);
}
}
+4
View File
@@ -3,6 +3,8 @@
#include <QVariant>
class EffectField;
class EffectKeyframe {
public:
EffectKeyframe();
@@ -18,4 +20,6 @@ public:
double post_handle_y;
};
void delete_keyframes(QVector<EffectField *> &selected_key_fields, QVector<int> &selected_keys);
#endif // KEYFRAME_H
+94
View File
@@ -56,6 +56,18 @@ GraphView::GraphView(QWidget* parent) :
void GraphView::show_context_menu(const QPoint& pos) {
QMenu menu(this);
QAction* zoom_to_selection = menu.addAction("Zoom to Selection");
if (selected_keys.size() == 0) {
zoom_to_selection->setEnabled(false);
} else {
connect(zoom_to_selection, SIGNAL(triggered(bool)), this, SLOT(set_view_to_selection()));
}
QAction* zoom_to_all = menu.addAction("Zoom to Show All");
connect(zoom_to_all, SIGNAL(triggered(bool)), this, SLOT(set_view_to_all()));
menu.addSeparator();
QAction* reset_action = menu.addAction("Reset View");
connect(reset_action, SIGNAL(triggered(bool)), this, SLOT(reset_view()));
@@ -70,6 +82,61 @@ void GraphView::reset_view() {
update();
}
void GraphView::set_view_to_selection() {
if (selected_keys.size() > 0) {
long min_time = LONG_MAX;
long max_time = LONG_MIN;
double min_dbl = DBL_MAX;
double max_dbl = DBL_MIN;
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));
min_time = qMin(key.time, min_time);
max_time = qMax(key.time, max_time);
min_dbl = qMin(key.data.toDouble(), min_dbl);
max_dbl = qMax(key.data.toDouble(), max_dbl);
}
set_view_to_rect(min_time, min_dbl, max_time, max_dbl);
}
}
void GraphView::set_view_to_all() {
bool can_set = false;
long min_time = LONG_MAX;
long max_time = LONG_MIN;
double min_dbl = DBL_MAX;
double max_dbl = DBL_MIN;
for (int i=0;i<row->fieldCount();i++) {
for (int j=0;j<row->field(i)->keyframes.size();j++) {
const EffectKeyframe& key = row->field(i)->keyframes.at(j);
min_time = qMin(key.time, min_time);
max_time = qMax(key.time, max_time);
min_dbl = qMin(key.data.toDouble(), min_dbl);
max_dbl = qMax(key.data.toDouble(), max_dbl);
can_set = true;
}
}
if (can_set) {
set_view_to_rect(min_time, min_dbl, max_time, max_dbl);
}
}
void GraphView::set_view_to_rect(int x1, double y1, int x2, double y2) {
double padding = 1.5;
double inverse_padding = 1.0/padding;
double x_diff = double(x2 - x1);
double y_diff = (y2 - y1);
double x_diff_padded = x_diff*padding;
double y_diff_padded = y_diff*padding;
set_zoom(qMin(double(width()) / x_diff_padded, double(height()) / y_diff_padded));
set_scroll_x(qRound((double(x1) - ((x_diff_padded-x_diff)/2))*zoom));
set_scroll_y(qRound((double(y1) - ((y_diff_padded-y_diff)/2))*zoom));
//set_scroll_y(height() - y1);
}
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);
@@ -520,12 +587,39 @@ void GraphView::set_field_visibility(int field, bool b) {
update();
}
void GraphView::delete_selected_keys() {
if (row != NULL) {
QVector<EffectField*> fields;
for (int i=0;i<selected_keys_fields.size();i++) {
fields.append(row->field(selected_keys_fields.at(i)));
}
delete_keyframes(fields, selected_keys);
}
}
void GraphView::select_all() {
if (row != NULL) {
selected_keys.clear();
selected_keys_fields.clear();
for (int i=0;i<row->fieldCount();i++) {
EffectField* field = row->field(i);
for (int j=0;j<field->keyframes.size();j++) {
selected_keys.append(j);
selected_keys_fields.append(i);
}
}
selection_update();
}
}
void GraphView::set_scroll_x(int s) {
x_scroll = s;
emit x_scroll_changed(x_scroll);
}
void GraphView::set_scroll_y(int s) {
dout << s << height() << zoom;
y_scroll = s;
emit y_scroll_changed(y_scroll);
}
+6
View File
@@ -23,6 +23,9 @@ public:
void set_selected_keyframe_type(int type);
void set_field_visibility(int field, bool b);
void delete_selected_keys();
void select_all();
signals:
void x_scroll_changed(int);
void y_scroll_changed(int);
@@ -75,6 +78,9 @@ private:
private slots:
void show_context_menu(const QPoint& pos);
void reset_view();
void set_view_to_selection();
void set_view_to_all();
void set_view_to_rect(int x1, double y1, int x2, double y2);
};
#endif // GRAPHVIEW_H
+8 -4
View File
@@ -4,10 +4,14 @@
#define KEYFRAME_POINT_COUNT 4
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker) {
int color = (darker) ? 100 : 160;
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r, int g, int b) {
if (darker) {
r *= 0.625;
g *= 0.625;
b *= 0.625;
}
p.setPen(QColor(0, 0, 0));
p.setBrush(QColor(color, color, color));
p.setBrush(QColor(r, g, b));
switch (type) {
case KEYFRAME_TYPE_LINEAR:
@@ -24,5 +28,5 @@ void draw_keyframe(QPainter &p, int type, int x, int y, bool darker) {
break;
}
p.setBrush(Qt::NoBrush);
p.setBrush(Qt::NoBrush);
}
+2 -1
View File
@@ -4,7 +4,8 @@
#include <QPainter>
#define KEYFRAME_SIZE 6
#define KEYFRAME_COLOR 160
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker);
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r = KEYFRAME_COLOR, int g = KEYFRAME_COLOR, int b = KEYFRAME_COLOR);
#endif // KEYFRAMEDRAWING_H
+45 -52
View File
@@ -16,6 +16,7 @@
#include "ui/clickablelabel.h"
#include "ui/resizablescrollbar.h"
#include "ui/rectangleselect.h"
#include "project/keyframe.h"
#include <QMouseEvent>
#include <QtMath>
@@ -165,23 +166,7 @@ void KeyframeView::update_keys() {
}
void KeyframeView::delete_selected_keyframes() {
ComboAction* ca = new ComboAction();
bool del = false;
for (int i=0;i<selected_keyframes.size();i++) {
// TODO these need to be sorted
ca->append(new KeyframeDelete(selected_fields.at(i), selected_keyframes.at(i)));
del = true;
}
if (del) {
undo_stack.push(ca);
selected_keyframes.clear();
selected_fields.clear();
update_keys();
panel_sequence_viewer->viewer_widget->update();
} else {
delete ca;
}
delete_keyframes(selected_fields, selected_keyframes);
}
void KeyframeView::set_x_scroll(int s) {
@@ -201,6 +186,8 @@ void KeyframeView::resize_move(double d) {
void KeyframeView::mousePressEvent(QMouseEvent *event) {
rect_select_x = event->x();
rect_select_y = event->y();
rect_select_w = 0;
rect_select_h = 0;
if (panel_timeline->tool == TIMELINE_TOOL_HAND || event->buttons() & Qt::MiddleButton) {
scroll_drag = true;
@@ -244,7 +231,11 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
}
bool already_selected = false;
keys_selected = false;
if (keyframe_index > -1) already_selected = keyframeIsSelected(rows.at(row_index)->field(field_index), keyframe_index);
if (keyframe_index > -1) {
already_selected = keyframeIsSelected(rows.at(row_index)->field(field_index), keyframe_index);
} else {
select_rect = true;
}
if (!already_selected) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
selected_fields.clear();
@@ -274,10 +265,11 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
for (int i=0;i<selected_fields.size();i++) {
old_key_vals.append(selected_fields.at(i)->keyframes.at(selected_keyframes.at(i)).time);
}
keys_selected = true;
}
rect_select_offset = selected_fields.size();
update_keys();
if (event->button() == Qt::LeftButton) {
@@ -298,7 +290,40 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
rect_select_y = event->pos().y();
} else if (mousedown) {
int mouse_x = event->x() + x_scroll;
if (keys_selected) {
if (select_rect) {
// do a rect select
selected_fields.resize(rect_select_offset);
selected_keyframes.resize(rect_select_offset);
rect_select_w = event->x() - rect_select_x;
rect_select_h = event->y() - rect_select_y;
int min_row = qMin(rect_select_y, event->y())-KEYFRAME_SIZE;
int max_row = qMax(rect_select_y, event->y())+KEYFRAME_SIZE;
long frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, rect_select_x+x_scroll);
long frame_end = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x);
long min_frame = qMin(frame_start, frame_end)-KEYFRAME_SIZE;
long max_frame = qMax(frame_start, frame_end)+KEYFRAME_SIZE;
for (int i=0;i<rowY.size();i++) {
if (rowY.at(i) >= min_row && rowY.at(i) <= max_row) {
EffectRow* row = rows.at(i);
for (int k=0;k<row->fieldCount();k++) {
EffectField* field = row->field(k);
for (int j=0;j<field->keyframes.size();j++) {
long keyframe_frame = adjust_row_keyframe(row, field->keyframes.at(j).time);
if (!keyframeIsSelected(field, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) {
selected_fields.append(field);
selected_keyframes.append(j);
}
}
}
}
}
update_keys();
} else if (keys_selected) {
// move keyframes
long frame_diff = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x) - drag_frame_start;
@@ -345,38 +370,6 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
dragging = true;
update_ui(false);
} else {
// do a rect select
rect_select_w = event->x() - rect_select_x;
rect_select_h = event->y() - rect_select_y;
int min_row = qMin(rect_select_y, event->y())-KEYFRAME_SIZE;
int max_row = qMax(rect_select_y, event->y())+KEYFRAME_SIZE;
long frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, rect_select_x+x_scroll);
long frame_end = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x);
long min_frame = qMin(frame_start, frame_end)-KEYFRAME_SIZE;
long max_frame = qMax(frame_start, frame_end)+KEYFRAME_SIZE;
for (int i=0;i<rowY.size();i++) {
if (rowY.at(i) >= min_row && rowY.at(i) <= max_row) {
EffectRow* row = rows.at(i);
for (int k=0;k<row->fieldCount();k++) {
EffectField* field = row->field(k);
for (int j=0;j<field->keyframes.size();j++) {
long keyframe_frame = adjust_row_keyframe(row, field->keyframes.at(j).time);
if (!keyframeIsSelected(field, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) {
selected_fields.append(field);
selected_keyframes.append(j);
}
}
}
}
}
select_rect = true;
update_keys();
}
}
}
+3 -2
View File
@@ -27,7 +27,7 @@ public slots:
void resize_move(double d);
private:
long adjust_row_keyframe(EffectRow* row, long time);
QVector<EffectField*> selected_fields;
QVector<EffectField*> selected_fields;
QVector<int> selected_keyframes;
QVector<int> rowY;
QVector<EffectRow*> rows;
@@ -42,7 +42,7 @@ private:
bool select_rect;
bool scroll_drag;
bool keyframeIsSelected(EffectField *field, int keyframe);
bool keyframeIsSelected(EffectField *field, int keyframe);
long drag_frame_start;
long last_frame_diff;
@@ -50,6 +50,7 @@ private:
int rect_select_y;
int rect_select_w;
int rect_select_h;
int rect_select_offset;
int x_scroll;
int y_scroll;