diff --git a/dialogs/aboutdialog.ui b/dialogs/aboutdialog.ui
index 8033a5596..e56d0baa1 100644
--- a/dialogs/aboutdialog.ui
+++ b/dialogs/aboutdialog.ui
@@ -6,18 +6,18 @@
0
0
- 400
- 220
+ 358
+ 422
- Dialog
+ About Olive
-
- Olive is a non-linear video editor. This software is free and protected by the GNU GPL.
+ <html><head/><body><p><img src=":/icons/olive-splash.png"/></p><p><a href="https://www.olivevideoeditor.org/"><span style=" text-decoration: underline; color:#007af4;">https://www.olivevideoeditor.org/</span></a></p><p>Olive is a non-linear video editor. This software is free and protected by the GNU GPL.</p><p>Olive Team is obliged to inform users that Olive source code is available for download from its website.</p><p>Olive uses (at least) the following libraries in accordance with the GNU GPL/LGPL:</p><p>Qt, FFmpeg, libass, libfreetype, libmp3lame, libopenjpeg, libopus, libtheora, libtwolame, libvpx, libwavpack, libwebp, libx264, libx265, lzma, bzlib, zlib, libvidstab, libvorbis.</p></body></html>
Qt::AlignCenter
diff --git a/effects/effect.cpp b/effects/effect.cpp
index be1bd5113..3e8254332 100644
--- a/effects/effect.cpp
+++ b/effects/effect.cpp
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
QVector video_effect_names;
QVector audio_effect_names;
@@ -101,7 +102,7 @@ Effect::~Effect() {
void Effect::copy_field_keyframes(Effect* e) {
for (int i=0;irows.at(i)->keyframing = rows.at(i)->keyframing;
+ e->rows.at(i)->setKeyframing(rows.at(i)->isKeyframing());
e->rows.at(i)->keyframe_times = rows.at(i)->keyframe_times;
e->rows.at(i)->keyframe_types = rows.at(i)->keyframe_types;
for (int j=0;jfieldCount();j++) {
@@ -178,11 +179,11 @@ void Effect::load(QXmlStreamReader& stream) {
for (int k=0;kkeyframing = (attr.value() == "1");
+ row->setKeyframing(attr.value() == "1");
break;
}
}
- if (row->keyframing) {
+ if (row->isKeyframing()) {
stream.readNext();
while (!stream.atEnd() && !(stream.name() == "keyframes" && stream.isEndElement())) {
if (stream.name() == "key" && stream.isStartElement()) {
@@ -248,7 +249,7 @@ void Effect::save(QXmlStreamWriter& stream) {
EffectRow* row = rows.at(i);
stream.writeStartElement("row"); // row
stream.writeStartElement("keyframes"); // keyframes
- stream.writeAttribute("enabled", QString::number(row->keyframing));
+ stream.writeAttribute("enabled", QString::number(row->isKeyframing()));
for (int j=0;jkeyframe_times.size();j++) {
stream.writeStartElement("key"); // key
stream.writeAttribute("frame", QString::number(row->keyframe_times.at(j)));
@@ -286,20 +287,44 @@ EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, in
keyframing(false),
ui(uilayout),
name(n),
- ui_row(row)
+ ui_row(row),
+ just_made_unsafe_keyframe(false)
{
label = new QLabel(name);
ui->addWidget(label, row, 0);
- // DEBUG STARTS
- QPushButton* nkf = new QPushButton();
- nkf->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
- connect(nkf, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_now()));
- ui->addWidget(nkf, row, 5);
- // DEBUG ENDS
- /*keyframe_enable = new CheckboxEx();
+ keyframe_enable = new CheckboxEx();
keyframe_enable->setToolTip("Enable Keyframes");
- ui->addWidget(keyframe_enable, row, 5);*/
+ connect(keyframe_enable, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_enabled(bool)));
+ ui->addWidget(keyframe_enable, row, 6);
+}
+
+bool EffectRow::isKeyframing() {
+ return keyframing;
+}
+
+void EffectRow::setKeyframing(bool b) {
+ keyframing = b;
+ keyframe_enable->setChecked(b);
+}
+
+void EffectRow::set_keyframe_enabled(bool enabled) {
+ if (enabled) {
+ set_keyframe_now(true);
+ } else {
+ if (QMessageBox::question(panel_effect_controls, "Disable Keyframes", "Disabling keyframes will delete all current keyframes. Are you sure you want to do this?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
+ // clear
+ KeyframeDelete* kd = new KeyframeDelete();
+ for (int i=keyframe_times.size()-1;i>=0;i--) {
+ delete_keyframe(kd, i);
+ }
+ kd->disable_keyframes_on_row = this;
+ undo_stack.push(kd);
+ panel_effect_controls->update_keyframes();
+ } else {
+ setKeyframing(true);
+ }
+ }
}
EffectField* EffectRow::add_field(int type, int colspan) {
@@ -316,27 +341,42 @@ EffectRow::~EffectRow() {
}
}
-void EffectRow::set_keyframe_now() {
- set_keyframe(panel_timeline->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in);
+void EffectRow::set_keyframe_now(bool undoable) {
+ int index = -1;
+ long time = panel_timeline->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
+ for (int i=0;iredo();
+ delete ks;
+ }
+
+ panel_effect_controls->update_keyframes();
}
-void EffectRow::set_keyframe(long time) {
- keyframing = true;
- int index = -1;
- for (int i=0;i 0) ? keyframe_types.last() : EFFECT_KEYFRAME_LINEAR);
- }
- for (int i=0;iset_keyframe_data(index);
- }
- panel_effect_controls->update_keyframes();
+void EffectRow::delete_keyframe_at_time(KeyframeDelete* kd, long time) {
+ for (int i=0;irows.append(this);
+ kd->keyframes.append(index);
}
EffectField* EffectRow::field(int i) {
@@ -421,15 +461,7 @@ void EffectField::set_current_data(const QVariant& data) {
}
}
-void EffectField::set_keyframe_data(int i) {
- if (i == -1) {
- keyframe_data.append(get_current_data());
- } else {
- keyframe_data[i] = get_current_data();
- }
-}
-
-void EffectField::get_keyframe_data(long frame, int* before, int* after, double* progress) {
+void EffectField::get_keyframe_data(long frame, int &before, int &after, double &progress) {
int before_keyframe_index = -1;
int after_keyframe_index = -1;
long before_keyframe_time = LONG_MIN;
@@ -438,8 +470,8 @@ void EffectField::get_keyframe_data(long frame, int* before, int* after, double*
for (int i=0;ikeyframe_times.size();i++) {
long eval_keyframe_time = parent_row->keyframe_times.at(i);
if (eval_keyframe_time == frame) {
- *before = i;
- *after = i;
+ before = i;
+ after = i;
return;
} else if (eval_keyframe_time < frame && eval_keyframe_time > before_keyframe_time) {
before_keyframe_index = i;
@@ -448,40 +480,40 @@ void EffectField::get_keyframe_data(long frame, int* before, int* after, double*
after_keyframe_index = i;
after_keyframe_time = eval_keyframe_time;
}
- }
+ }
if (type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) {
if (before_keyframe_index > -1 && after_keyframe_index > -1) {
// interpolate
- *before = before_keyframe_index;
- *after = after_keyframe_index;
- *progress = (double)(frame-before_keyframe_time)/(double)(after_keyframe_time-before_keyframe_time);
+ before = before_keyframe_index;
+ after = after_keyframe_index;
+ progress = (double)(frame-before_keyframe_time)/(double)(after_keyframe_time-before_keyframe_time);
// TODO routines for bezier - currently this is purely linear
} else if (before_keyframe_index > -1) {
- *before = before_keyframe_index;
- *after = before_keyframe_index;
+ before = before_keyframe_index;
+ after = before_keyframe_index;
} else if (after_keyframe_index > -1) {
- *before = after_keyframe_index;
- *after = after_keyframe_index;
+ before = after_keyframe_index;
+ after = after_keyframe_index;
}
} else {
if (before_keyframe_index > -1) {
- *before = before_keyframe_index;
- *after = before_keyframe_index;
+ before = before_keyframe_index;
+ after = before_keyframe_index;
} else {
- *before = after_keyframe_time;
- *after = after_keyframe_time;
+ before = after_keyframe_index;
+ after = after_keyframe_index;
}
}
}
void EffectField::validate_keyframe_data(long frame) {
- if (parent_row->keyframing) {
+ if (parent_row->isKeyframing()) {
int before_keyframe;
int after_keyframe;
double progress;
- get_keyframe_data(frame, &before_keyframe, &after_keyframe, &progress);
+ get_keyframe_data(frame, before_keyframe, after_keyframe, progress);
const QVariant& before_data = keyframe_data.at(before_keyframe);
switch (type) {
@@ -524,14 +556,12 @@ void EffectField::validate_keyframe_data(long frame) {
static_cast(ui_element)->setCurrentTextEx(before_data.toString());
break;
}
-
-
}
}
void EffectField::uiElementChange() {
- if (parent_row->keyframing) {
- parent_row->set_keyframe_now();
+ if (parent_row->isKeyframing()) {
+ parent_row->set_keyframe_now(!(type == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()));
}
emit changed();
}
diff --git a/effects/effect.h b/effects/effect.h
index 5a7b90cdd..60b9adcda 100644
--- a/effects/effect.h
+++ b/effects/effect.h
@@ -17,6 +17,7 @@ class QXmlStreamWriter;
class Effect;
class EffectRow;
class CheckboxEx;
+class KeyframeDelete;
enum VideoEffects {
VIDEO_TRANSFORM_EFFECT,
@@ -81,9 +82,8 @@ public:
int type;
QVariant get_current_data();
- void set_current_data(const QVariant&);
- void set_keyframe_data(int i);
- void get_keyframe_data(long frame, int* before, int *after, double* d);
+ void set_current_data(const QVariant&);
+ void get_keyframe_data(long frame, int& before, int& after, double& d);
void validate_keyframe_data(long frame);
// QVariant get_keyframe_data(long p);
// bool is_keyframed(long p);
@@ -116,8 +116,8 @@ public:
QWidget* get_ui_element();
void set_enabled(bool e);
QVector keyframe_data;
+ QWidget* ui_element;
private:
- QWidget* ui_element;
private slots:
void uiElementChange();
signals:
@@ -133,24 +133,29 @@ public:
EffectField* add_field(int type, int colspan = 1);
EffectField* field(int i);
int fieldCount();
- void set_keyframe(long time);
- void move_keyframe(long from, long to);
- void delete_keyframe(long time);
+ void set_keyframe_now(bool undoable);
+ void delete_keyframe(KeyframeDelete *kd, int index);
+ void delete_keyframe_at_time(KeyframeDelete* kd, long time);
QLabel* label;
Effect* parent_effect;
- bool keyframing;
+ bool isKeyframing();
+ void setKeyframing(bool);
+
QVector keyframe_times;
QVector keyframe_types;
-public slots:
- void set_keyframe_now();
+private slots:
+ void set_keyframe_enabled(bool);
private:
+ bool keyframing;
QGridLayout* ui;
QString name;
int ui_row;
QVector fields;
CheckboxEx* keyframe_enable;
+
+ bool just_made_unsafe_keyframe;
};
class Effect : public QObject {
diff --git a/effects/video/shakeeffect.cpp b/effects/video/shakeeffect.cpp
index 6800d82d5..73a40b649 100644
--- a/effects/video/shakeeffect.cpp
+++ b/effects/video/shakeeffect.cpp
@@ -49,7 +49,7 @@ void ShakeEffect::refresh() {
}
}
-void ShakeEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) {
+void ShakeEffect::process_gl(long frame, QOpenGLShaderProgram&, GLTextureCoords&) {
if (shake_progress > shake_limit) {
double ival = intensity_val->get_double_value(frame);
if ((int)ival > 0) {
diff --git a/effects/video/transformeffect.cpp b/effects/video/transformeffect.cpp
index 1d5c21737..01f9de90c 100644
--- a/effects/video/transformeffect.cpp
+++ b/effects/video/transformeffect.cpp
@@ -128,14 +128,14 @@ void TransformEffect::process_gl(long frame, QOpenGLShaderProgram&, GLTextureCoo
// anchor point
int anchor_x_offset = (anchor_x_box->get_double_value(frame)-default_anchor_x);
int anchor_y_offset = (anchor_y_box->get_double_value(frame)-default_anchor_y);
- coords.vertexTopLeftX += anchor_x_offset;
- coords.vertexTopRightX += anchor_x_offset;
- coords.vertexBottomLeftX += anchor_x_offset;
- coords.vertexBottomRightX += anchor_x_offset;
- coords.vertexTopLeftY += anchor_y_offset;
- coords.vertexTopRightY += anchor_y_offset;
- coords.vertexBottomLeftY += anchor_y_offset;
- coords.vertexBottomRightY += anchor_y_offset;
+ coords.vertexTopLeftX -= anchor_x_offset;
+ coords.vertexTopRightX -= anchor_x_offset;
+ coords.vertexBottomLeftX -= anchor_x_offset;
+ coords.vertexBottomRightX -= anchor_x_offset;
+ coords.vertexTopLeftY -= anchor_y_offset;
+ coords.vertexTopRightY -= anchor_y_offset;
+ coords.vertexBottomLeftY -= anchor_y_offset;
+ coords.vertexBottomRightY -= anchor_y_offset;
// rotation
glRotatef(rotation->get_double_value(frame), 0, 0, 1);
diff --git a/icons/icons.qrc b/icons/icons.qrc
index 4c80d9b23..4e55ea1b1 100644
--- a/icons/icons.qrc
+++ b/icons/icons.qrc
@@ -38,5 +38,6 @@
zoomout-disabled.png
add-transition.png
add-effect.png
+ olive-splash.png
diff --git a/icons/olive-splash.png b/icons/olive-splash.png
new file mode 100644
index 000000000..008682ac9
Binary files /dev/null and b/icons/olive-splash.png differ
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 7bb462e35..94388a015 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -186,7 +186,9 @@ void MainWindow::on_actionDelete_triggered()
panel_effect_controls->delete_effects();
} else if (panel_project->is_focused()) {
panel_project->delete_selected_media();
- }
+ } else if (panel_effect_controls->keyframe_focus()) {
+ panel_effect_controls->delete_selected_keyframes();
+ }
}
void MainWindow::on_actionSelect_All_triggered()
diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp
index adced628a..caa1a4f5f 100644
--- a/panels/effectcontrols.cpp
+++ b/panels/effectcontrols.cpp
@@ -89,6 +89,10 @@ void EffectControls::update_keyframes() {
ui->keyframeView->update();
}
+void EffectControls::delete_selected_keyframes() {
+ ui->keyframeView->delete_selected_keyframes();
+}
+
void EffectControls::show_effect_menu(bool video, bool transitions) {
video_menu = video;
transition_menu = transitions;
diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h
index c2b871c99..6d9df4aca 100644
--- a/panels/effectcontrols.h
+++ b/panels/effectcontrols.h
@@ -38,6 +38,7 @@ public:
void reload_clips();
void set_zoom(bool in);
bool keyframe_focus();
+ void delete_selected_keyframes();
double zoom;
public slots:
diff --git a/panels/timeline.cpp b/panels/timeline.cpp
index 772f230ca..9c5fb5c92 100644
--- a/panels/timeline.cpp
+++ b/panels/timeline.cpp
@@ -22,12 +22,19 @@
#include
#include
#include
+#include
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) {
if (source_frame_rate == target_frame_rate) return framenumber;
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),
playhead(0),
diff --git a/panels/timeline.h b/panels/timeline.h
index 4152aaab2..f3172f839 100644
--- a/panels/timeline.h
+++ b/panels/timeline.h
@@ -24,6 +24,7 @@ int lerp(int a, int b, double t);
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);
struct Ghost {
int clip;
diff --git a/project/undo.cpp b/project/undo.cpp
index 4e5994d38..2ccb4fc13 100644
--- a/project/undo.cpp
+++ b/project/undo.cpp
@@ -787,17 +787,146 @@ void MediaRename::redo() {
project_changed = true;
}
-ValueChangeCommand::ValueChangeCommand() : done(true), old_project_changed(project_changed) {}
+KeyframeMove::KeyframeMove() : old_project_changed(project_changed) {}
-void ValueChangeCommand::undo() {
- source->set_value(old_val, false);
- done = false;
+void KeyframeMove::undo() {
+ for (int i=0;ikeyframe_times[keyframes.at(i)] -= movement;
+ }
project_changed = old_project_changed;
}
-void ValueChangeCommand::redo() {
- if (!done) {
- source->set_value(new_val, false);
+void KeyframeMove::redo() {
+ for (int i=0;ikeyframe_times[keyframes.at(i)] += movement;
}
project_changed = true;
}
+
+KeyframeDelete::KeyframeDelete() : old_project_changed(project_changed), disable_keyframes_on_row(NULL), sorted(false) {}
+
+void KeyframeDelete::undo() {
+ if (disable_keyframes_on_row != NULL) disable_keyframes_on_row->setKeyframing(true);
+
+ int data_index = 0;
+ for (int i=0;ikeyframe_times.insert(keyframe_index, deleted_keyframe_times.at(i));
+ row->keyframe_types.insert(keyframe_index, deleted_keyframe_types.at(i));
+
+ for (int j=0;jfieldCount();j++) {
+ row->field(j)->keyframe_data.insert(keyframe_index, deleted_keyframe_data.at(data_index));
+ data_index++;
+ }
+ }
+
+ project_changed = old_project_changed;
+}
+
+void KeyframeDelete::redo() {
+ if (!sorted) {
+ for (int i=0;i keyframes.at(j)) {
+ int temp = keyframes.at(i);
+ EffectRow* temp_row = rows.at(i);
+
+ keyframes[i] = keyframes.at(j);
+ rows[i] = rows.at(j);
+
+ keyframes[j] = temp;
+ rows[j] = temp_row;
+ }
+ }
+ }
+ sorted = true;
+ }
+
+ deleted_keyframe_times.resize(rows.size());
+ deleted_keyframe_types.resize(rows.size());
+ deleted_keyframe_data.clear();
+
+ for (int i=0;ikeyframe_times.at(keyframe_index));
+ deleted_keyframe_types[i] = (row->keyframe_types.at(keyframe_index));
+
+ row->keyframe_times.removeAt(keyframe_index);
+ row->keyframe_types.removeAt(keyframe_index);
+
+ for (int j=0;jfieldCount();j++) {
+ deleted_keyframe_data.append(row->field(j)->keyframe_data.at(keyframe_index));
+ row->field(j)->keyframe_data.removeAt(keyframe_index);
+ }
+ }
+
+ if (disable_keyframes_on_row != NULL) disable_keyframes_on_row->setKeyframing(false);
+ project_changed = true;
+}
+
+KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
+ old_project_changed(project_changed),
+ row(r),
+ index(i),
+ time(t),
+ just_made_keyframe(justMadeKeyframe),
+ done(true)
+{
+ enable_keyframes = !row->isKeyframing();
+ if (index != -1) old_values.resize(row->fieldCount());
+ new_values.resize(row->fieldCount());
+ for (int i=0;ifieldCount();i++) {
+ EffectField* field = row->field(i);
+ if (index != -1) {
+ if (field->type == EFFECT_FIELD_DOUBLE) {
+ old_values[i] = static_cast(field->ui_element)->get_drag_start_value();
+ } else {
+ old_values[i] = field->keyframe_data.at(index);
+ }
+ }
+ new_values[i] = field->get_current_data();
+ }
+}
+
+void KeyframeSet::undo() {
+ if (enable_keyframes) row->setKeyframing(false);
+
+ bool append = (index == -1 || just_made_keyframe);
+ if (append) {
+ row->keyframe_times.removeLast();
+ row->keyframe_types.removeLast();
+ }
+ for (int i=0;ifieldCount();i++) {
+ if (append) {
+ row->field(i)->keyframe_data.removeLast();
+ } else {
+ row->field(i)->keyframe_data[index] = old_values.at(i);
+ }
+ }
+
+ project_changed = old_project_changed;
+ done = false;
+}
+
+void KeyframeSet::redo() {
+ bool append = (index == -1 || (just_made_keyframe && !done));
+ if (append) {
+ row->keyframe_times.append(time);
+ row->keyframe_types.append((row->keyframe_types.size() > 0) ? row->keyframe_types.last() : EFFECT_KEYFRAME_LINEAR);
+ }
+ for (int i=0;ifieldCount();i++) {
+ if (append) {
+ row->field(i)->keyframe_data.append(new_values.at(i));
+ } else {
+ row->field(i)->keyframe_data[index] = new_values.at(i);
+ }
+ }
+ row->setKeyframing(true);
+
+ project_changed = true;
+ done = true;
+}
diff --git a/project/undo.h b/project/undo.h
index 91621af35..ed6e5fee8 100644
--- a/project/undo.h
+++ b/project/undo.h
@@ -6,6 +6,7 @@ class QCheckBox;
class LabelSlider;
class Effect;
class SourceTable;
+class EffectRow;
struct Clip;
struct Sequence;
struct Media;
@@ -200,17 +201,50 @@ private:
bool old_project_changed;
};
-class ValueChangeCommand : public QUndoCommand {
+class KeyframeMove : public QUndoCommand {
public:
- ValueChangeCommand();
- LabelSlider* source;
- float old_val;
- float new_val;
+ KeyframeMove();
+ QVector rows;
+ QVector keyframes;
+ long movement;
void undo();
void redo();
private:
- bool done;
bool old_project_changed;
};
+class KeyframeDelete : public QUndoCommand {
+public:
+ KeyframeDelete();
+ QVector rows;
+ EffectRow* disable_keyframes_on_row;
+ QVector keyframes;
+ void undo();
+ void redo();
+private:
+ bool old_project_changed;
+ QVector deleted_keyframe_times;
+ QVector deleted_keyframe_types;
+ QVector deleted_keyframe_data;
+ bool sorted;
+};
+
+
+class KeyframeSet : public QUndoCommand {
+public:
+ KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe);
+ void undo();
+ void redo();
+ QVector old_values;
+ QVector new_values;
+private:
+ bool old_project_changed;
+ EffectRow* row;
+ int index;
+ long time;
+ bool enable_keyframes;
+ bool just_made_keyframe;
+ bool done;
+};
+
#endif // UNDO_H
diff --git a/ui/checkboxex.cpp b/ui/checkboxex.cpp
index 9ec062d1a..c9134c321 100644
--- a/ui/checkboxex.cpp
+++ b/ui/checkboxex.cpp
@@ -3,7 +3,7 @@
#include "project/undo.h"
CheckboxEx::CheckboxEx(QWidget* parent) : QCheckBox(parent) {
- connect(this, SIGNAL(clicked(bool)), this, SLOT(checkbox_command()));
+// connect(this, SIGNAL(clicked(bool)), this, SLOT(checkbox_command()));
}
void CheckboxEx::checkbox_command() {
diff --git a/ui/colorbutton.cpp b/ui/colorbutton.cpp
index e2062961a..2ddfafb22 100644
--- a/ui/colorbutton.cpp
+++ b/ui/colorbutton.cpp
@@ -29,8 +29,10 @@ void ColorButton::open_dialog() {
QColor old_color = color;
QColor new_color = QColorDialog::getColor(color, NULL);
if (new_color.isValid() && old_color != new_color) {
- ColorCommand* command = new ColorCommand(this, old_color, new_color);
- undo_stack.push(command);
+ ColorCommand* command = new ColorCommand(this, old_color, new_color);
+// undo_stack.push(command);
+ command->redo();
+ delete command;
set_button_color();
diff --git a/ui/comboboxex.cpp b/ui/comboboxex.cpp
index 147dd27a3..6c1243561 100644
--- a/ui/comboboxex.cpp
+++ b/ui/comboboxex.cpp
@@ -45,7 +45,7 @@ void ComboBoxEx::setCurrentTextEx(const QString &text) {
void ComboBoxEx::index_changed(int i) {
if (index != i) {
- undo_stack.push(new ComboBoxExCommand(this, index, i));
+// undo_stack.push(new ComboBoxExCommand(this, index, i));
index = i;
}
}
diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp
index db91f4c65..84842d262 100644
--- a/ui/keyframeview.cpp
+++ b/ui/keyframeview.cpp
@@ -7,6 +7,9 @@
#include "project/clip.h"
#include "panels/timeline.h"
#include "ui/timelineheader.h"
+#include "project/undo.h"
+#include "panels/viewer.h"
+#include "ui/viewerwidget.h"
#include
#include
@@ -14,7 +17,11 @@
#define KEYFRAME_SIZE 6
#define KEYFRAME_POINT_COUNT 4
-KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), mousedown(false), visible_in(0), visible_out(0) {
+long KeyframeView::adjust_row_keyframe(EffectRow* row, long time) {
+ return time-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
+}
+
+KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), mousedown(false), dragging(false), keys_selected(false), select_rect(false), visible_in(0), visible_out(0) {
setFocusPolicy(Qt::ClickFocus);
setMouseTracking(true);
}
@@ -39,15 +46,10 @@ void KeyframeView::paintEvent(QPaintEvent*) {
int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height();
for (int k=0;kkeyframe_times.size();k++) {
- bool keyframe_selected = false;
- for (int l=0;lzoom, row->keyframe_times.at(k)-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in)), keyframe_y, keyframe_selected);
+ bool keyframe_selected = keyframeIsSelected(row, k);
+ long keyframe_frame = adjust_row_keyframe(row, row->keyframe_times.at(k));
+ if (dragging && keyframe_selected) keyframe_frame += frame_diff;
+ draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame), keyframe_y, keyframe_selected);
}
rows.append(row);
@@ -62,11 +64,43 @@ void KeyframeView::paintEvent(QPaintEvent*) {
p.drawLine(playhead_x, 0, playhead_x, height());
}
+ if (select_rect) {
+ draw_selection_rectangle(p, QRect(rect_select_x, rect_select_y, rect_select_w, rect_select_h));
+ }
+
/*if (mouseover && mouseover_row < rowY.size()) {
draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, mouseover_frame - visible_in), rowY.at(mouseover_row), true);
}*/
}
+bool KeyframeView::keyframeIsSelected(EffectRow *row, int keyframe) {
+ for (int i=0;idelete_keyframe(kd, selected_keyframes.at(i));
+ del = true;
+ }
+ if (del) {
+ undo_stack.push(kd);
+
+ selected_keyframes.clear();
+ selected_rows.clear();
+ update();
+ panel_viewer->viewer_widget->update();
+ } else {
+ delete kd;
+ }
+}
+
void KeyframeView::draw_keyframe(QPainter &p, int x, int y, bool darker) {
QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)};
int color = (darker) ? 100 : 160;
@@ -80,7 +114,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
int keyframe_index = -1;
long frame_diff = 0;
long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()-KEYFRAME_SIZE);
- long frame_mid = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x());
+ drag_frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x());
long frame_max = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()+KEYFRAME_SIZE);
for (int i=0;iy() > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && event->y() < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) {
@@ -88,7 +122,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
for (int j=0;jkeyframe_times.size();j++) {
long eval_keyframe_time = row->keyframe_times.at(j)-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
if (eval_keyframe_time >= frame_min && eval_keyframe_time <= frame_max) {
- long eval_frame_diff = qAbs(eval_keyframe_time - frame_mid);
+ long eval_frame_diff = qAbs(eval_keyframe_time - drag_frame_start);
if (keyframe_index == -1 || eval_frame_diff < frame_diff) {
row_index = i;
keyframe_index = j;
@@ -100,24 +134,26 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
}
}
bool already_selected = false;
- if (keyframe_index > -1) {
- for (int i=0;i -1) already_selected = keyframeIsSelected(rows.at(row_index), keyframe_index);
if (!already_selected) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
selected_rows.clear();
selected_keyframes.clear();
}
if (keyframe_index > -1) {
- selected_rows.append(row_index);
+ selected_rows.append(rows.at(row_index));
selected_keyframes.append(keyframe_index);
}
}
+ if (selected_rows.size() > 0) {
+ keys_selected = true;
+ } else {
+ rect_select_x = event->x();
+ rect_select_y = event->y();
+ }
+
update();
mousedown = true;
}
@@ -138,11 +174,70 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
update();
}
mouseover = new_mo;*/
- if (mousedown) {
+ if (mousedown) {
+ if (keys_selected) {
+ frame_diff = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()) - drag_frame_start;
+ // validate frame_diff
+ for (int i=0;ikeyframe_times.at(selected_keyframes.at(i));
+ for (int j=0;jkeyframe_times.size();j++) {
+ while (!keyframeIsSelected(row, j) && row->keyframe_times.at(j) == eval_key + frame_diff) {
+ if (last_frame_diff > frame_diff) {
+ frame_diff++;
+ } else {
+ frame_diff--;
+ }
+ }
+ }
+ }
+
+ last_frame_diff = frame_diff;
+
+ dragging = true;
+ } else {
+ 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);
+ long frame_end = getFrameFromScreenPoint(panel_effect_controls->zoom, event->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= min_row && rowY.at(i) <= max_row) {
+ EffectRow* row = rows.at(i);
+ for (int j=0;jkeyframe_times.size();j++) {
+ long keyframe_frame = adjust_row_keyframe(row, row->keyframe_times.at(j));
+ if (!keyframeIsSelected(row, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) {
+ selected_rows.append(rows.at(i));
+ selected_keyframes.append(j);
+ }
+ }
+ }
+ }
+
+ select_rect = true;
+ }
+ update();
}
}
-void KeyframeView::mouseReleaseEvent(QMouseEvent* event) {
+void KeyframeView::mouseReleaseEvent(QMouseEvent*) {
+ if (dragging && frame_diff != 0) {
+ KeyframeMove* ka = new KeyframeMove();
+ ka->movement = frame_diff;
+ ka->keyframes = selected_keyframes;
+ ka->rows = selected_rows;
+ undo_stack.push(ka);
+ }
+
+ select_rect = false;
+ dragging = false;
mousedown = false;
+ update();
}
diff --git a/ui/keyframeview.h b/ui/keyframeview.h
index 10c9a9f63..ec62761c9 100644
--- a/ui/keyframeview.h
+++ b/ui/keyframeview.h
@@ -15,14 +15,18 @@ public:
KeyframeView(QWidget* parent = 0);
QVector effects;
+ void delete_selected_keyframes();
+
TimelineHeader* header;
long visible_in;
long visible_out;
private:
- QVector selected_rows;
+ long adjust_row_keyframe(EffectRow* row, long time);
+ QVector selected_rows;
QVector selected_keyframes;
QVector rowY;
+ long frame_diff;
QVector rows;
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
@@ -30,9 +34,18 @@ private:
void paintEvent(QPaintEvent *event);
void draw_keyframe(QPainter& p, int x, int y, bool darker);
bool mousedown;
+ bool dragging;
+ bool keys_selected;
+ bool select_rect;
- int drag_row_index;
- int drag_keyframe_index;
+ bool keyframeIsSelected(EffectRow* row, int keyframe);
+
+ long drag_frame_start;
+ long last_frame_diff;
+ int rect_select_x;
+ int rect_select_y;
+ int rect_select_w;
+ int rect_select_h;
};
#endif // KEYFRAMEVIEW_H
diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp
index 85a847903..c6ef7025a 100644
--- a/ui/labelslider.cpp
+++ b/ui/labelslider.cpp
@@ -8,6 +8,7 @@
LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) {
drag_start = false;
+ drag_proc = false;
min_enabled = false;
max_enabled = false;
setStyleSheet("QLabel{color:#ffc000;text-decoration:underline;}QLabel:disabled{color:#808080;}");
@@ -38,6 +39,10 @@ bool LabelSlider::is_set() {
return set;
}
+bool LabelSlider::is_dragging() {
+ return drag_proc;
+}
+
double LabelSlider::value() {
return internal_value;
}
@@ -60,18 +65,16 @@ void LabelSlider::set_maximum_value(double v) {
max_enabled = true;
}
-void LabelSlider::mousePressEvent(QMouseEvent *ev) {
- if (ev->modifiers() & Qt::AltModifier) {
- ValueChangeCommand* vcc = new ValueChangeCommand();
- vcc->source = this;
- vcc->old_val = internal_value;
- vcc->new_val = default_value;
- undo_stack.push(vcc);
+double LabelSlider::get_drag_start_value() {
+ return drag_start_value;
+}
+void LabelSlider::mousePressEvent(QMouseEvent *ev) {
+ drag_start_value = internal_value;
+ if (ev->modifiers() & Qt::AltModifier) {
set_value(default_value, true);
} else {
qApp->setOverrideCursor(Qt::BlankCursor);
- drag_start_value = internal_value;
drag_start = true;
drag_start_x = cursor().pos().x();
drag_start_y = cursor().pos().y();
@@ -80,9 +83,9 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) {
void LabelSlider::mouseMoveEvent(QMouseEvent*) {
if (drag_start) {
+ drag_proc = true;
set_value(internal_value + (cursor().pos().x()-drag_start_x) + (drag_start_y-cursor().pos().y()), true);
cursor().setPos(drag_start_x, drag_start_y);
- drag_proc = true;
}
}
@@ -91,25 +94,12 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
qApp->restoreOverrideCursor();
drag_start = false;
if (drag_proc) {
- // send undo event
- ValueChangeCommand* vcc = new ValueChangeCommand();
- vcc->source = this;
- vcc->old_val = drag_start_value;
- vcc->new_val = internal_value;
- undo_stack.push(vcc);
-
- drag_proc = false;
+ drag_proc = false;
+ emit valueChanged();
} else {
double d = QInputDialog::getDouble(this, "Set Value", "New value:", internal_value);
if (d != internal_value) {
- ValueChangeCommand* vcc = new ValueChangeCommand();
- vcc->source = this;
- vcc->old_val = internal_value;
-
set_value(d, true);
-
- vcc->new_val = internal_value;
- undo_stack.push(vcc);
}
}
}
diff --git a/ui/labelslider.h b/ui/labelslider.h
index 72e8c2120..04a9dbb05 100644
--- a/ui/labelslider.h
+++ b/ui/labelslider.h
@@ -15,6 +15,8 @@ public:
void set_maximum_value(double v);
double value();
bool is_set();
+ double get_drag_start_value();
+ bool is_dragging();
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
@@ -36,7 +38,7 @@ private:
bool set;
signals:
- void valueChanged();
+ void valueChanged();
};
#endif // LABELSLIDER_H
diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp
index fb8190bc0..f4fe68882 100644
--- a/ui/timelinewidget.cpp
+++ b/ui/timelinewidget.cpp
@@ -1793,10 +1793,8 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
if (bottom_align) {
rsy += height();
}
- QRect rect_select(panel_timeline->rect_select_x, rsy, panel_timeline->rect_select_w, rsh);
- p.setPen(QColor(204, 204, 204));
- p.drawRect(rect_select);
- p.fillRect(rect_select, QColor(0, 0, 0, 32));
+ QRect rect_select(panel_timeline->rect_select_x, rsy, panel_timeline->rect_select_w, rsh);
+ draw_selection_rectangle(p, rect_select);
}
// Draw ghosts