implemented rolling edit (#74)
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.6.2, 2018-07-08T11:23:30. -->
|
||||
<!-- Written by QtCreator 4.6.2, 2018-07-08T12:53:52. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
+30
-13
@@ -358,7 +358,8 @@ void Project::load_project() {
|
||||
Clip* temp_clip;
|
||||
|
||||
int state = LOAD_STATE_IDLE;
|
||||
while (!stream.atEnd()) {
|
||||
bool error = false;
|
||||
while (!error && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
switch (state) {
|
||||
case LOAD_STATE_IDLE:
|
||||
@@ -380,9 +381,13 @@ void Project::load_project() {
|
||||
case LOAD_STATE_FOOTAGE:
|
||||
if (stream.isEndElement() && stream.name() == "footage") {
|
||||
Media* m = import_file(temp_url);
|
||||
m->save_id = temp_media_id;
|
||||
m->name = temp_name;
|
||||
temp_media_list.append(m);
|
||||
if (m == NULL) {
|
||||
error = (QMessageBox::warning(this, "Source load error", "Couldn't load source file '" + temp_url + "'. This is unsupported and may lead to crashes. Do you wish to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No);
|
||||
} else {
|
||||
m->save_id = temp_media_id;
|
||||
m->name = temp_name;
|
||||
temp_media_list.append(m);
|
||||
}
|
||||
state = LOAD_STATE_IDLE;
|
||||
} else if (stream.isStartElement()) {
|
||||
if (stream.name() == "name") {
|
||||
@@ -410,9 +415,12 @@ void Project::load_project() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
clip->linked.removeAt(j);
|
||||
qDebug() << "[WARNING] Discarded link from loaded file - this should NEVER happen";
|
||||
if (!found) {
|
||||
if (QMessageBox::warning(this, "Corrupt clip link", "Project contains a non-existent clip link. It may be corrupt. Would you like to load it anyway?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
||||
clip->linked.removeAt(j);
|
||||
} else {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -497,9 +505,13 @@ void Project::load_project() {
|
||||
} else if (stream.name() == "stream") {
|
||||
stream.readNext();
|
||||
int stream_index = stream.text().toInt();
|
||||
temp_clip->media_stream = temp_clip->media->get_stream_from_file_index(stream_index);
|
||||
if (temp_clip->media_stream == NULL) {
|
||||
qDebug() << "[WARNING] Could not load media stream - project file seems corrupt";
|
||||
if (temp_clip->media != NULL) {
|
||||
temp_clip->media_stream = temp_clip->media->get_stream_from_file_index(stream_index);
|
||||
if (temp_clip->media_stream == NULL) {
|
||||
if (QMessageBox::warning(this, "Source changed", "Source file '" + temp_clip->media->url + "' appears to have changed since last saving the project. This is unsupported and may lead to crashes. Do you wish to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (stream.name() == "linked") {
|
||||
state = LOAD_STATE_CLIP_LINKS;
|
||||
@@ -531,11 +543,16 @@ void Project::load_project() {
|
||||
}
|
||||
if (stream.hasError()) {
|
||||
qDebug() << "[ERROR] Error parsing XML." << stream.error();
|
||||
QMessageBox::critical(this, "XML Parsing Error", "Couldn't load '" + project_url + "'. " + stream.error(), QMessageBox::Ok);
|
||||
error = true;
|
||||
}
|
||||
|
||||
panel_timeline->redraw_all_clips(false);
|
||||
|
||||
project_changed = false;
|
||||
if (error) {
|
||||
new_project();
|
||||
} else {
|
||||
panel_timeline->redraw_all_clips(false);
|
||||
project_changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Project::save_project() {
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ Timeline::Timeline(QWidget *parent) :
|
||||
splitting = false;
|
||||
importing = false;
|
||||
playing = false;
|
||||
trim_in = false;
|
||||
trim_in_point = false;
|
||||
snapped = false;
|
||||
rect_select_init = false;
|
||||
rect_select_proc = false;
|
||||
|
||||
+5
-2
@@ -34,6 +34,7 @@ struct Ghost {
|
||||
// other variables
|
||||
long ghost_length;
|
||||
long media_length;
|
||||
bool trim_in;
|
||||
};
|
||||
|
||||
struct Selection {
|
||||
@@ -44,6 +45,8 @@ struct Selection {
|
||||
long old_in;
|
||||
long old_out;
|
||||
int old_track;
|
||||
|
||||
bool trim_in;
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
@@ -141,11 +144,11 @@ public:
|
||||
// moving
|
||||
bool moving_init;
|
||||
bool moving_proc;
|
||||
QVector<Ghost> ghosts;
|
||||
QVector<Ghost> ghosts;
|
||||
|
||||
// trimming
|
||||
int trim_target;
|
||||
bool trim_in;
|
||||
bool trim_in_point;
|
||||
|
||||
// splitting
|
||||
bool splitting;
|
||||
|
||||
@@ -23,6 +23,7 @@ Clip::Clip() {
|
||||
texture = NULL;
|
||||
opening_transition = NULL;
|
||||
closing_transition = NULL;
|
||||
media = NULL;
|
||||
pkt = new AVPacket();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "audiomonitor.h"
|
||||
|
||||
#include "project/sequence.h"
|
||||
#include "playback/audio.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/timeline.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QLinearGradient>
|
||||
#include <QtMath>
|
||||
#include <QDebug>
|
||||
|
||||
#define AUDIO_MONITOR_GAP 3
|
||||
|
||||
extern "C" {
|
||||
#include "libavformat/avformat.h"
|
||||
}
|
||||
|
||||
AudioMonitor::AudioMonitor(QWidget *parent) : QWidget(parent) {
|
||||
}
|
||||
|
||||
void AudioMonitor::reset() {
|
||||
sample_cache_offset = -1;
|
||||
sample_cache.clear();
|
||||
}
|
||||
|
||||
void AudioMonitor::resizeEvent(QResizeEvent *e) {
|
||||
gradient = QLinearGradient(QPoint(0, rect().top()), QPoint(0, rect().bottom()));
|
||||
gradient.setColorAt(0, Qt::red);
|
||||
gradient.setColorAt(0.25, Qt::yellow);
|
||||
gradient.setColorAt(1, Qt::green);
|
||||
QWidget::resizeEvent(e);
|
||||
}
|
||||
|
||||
void AudioMonitor::paintEvent(QPaintEvent *) {
|
||||
if (sequence != NULL) {
|
||||
QPainter p(this);
|
||||
int channel_x = AUDIO_MONITOR_GAP;
|
||||
int channel_count = av_get_channel_layout_nb_channels(sequence->audio_layout);
|
||||
int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP;
|
||||
// for (int i=0;i<channel_count;i++) {
|
||||
for (int i=0;i<1;i++) {
|
||||
QRect r(channel_x, 0, channel_width, height());
|
||||
p.fillRect(r, gradient);
|
||||
|
||||
if (sample_cache_offset != -1) {
|
||||
long playhead_offset = panel_timeline->playhead - sample_cache_offset;
|
||||
if (playhead_offset >= 0 && playhead_offset < sample_cache.size()) {
|
||||
//int channel_offset = i*2;
|
||||
double multiplier = 1 - qAbs((double) sample_cache.at(playhead_offset) / 32768.0); // 16-bit int divided to float
|
||||
r.setHeight(r.height()*multiplier);
|
||||
sample_cache_offset++;
|
||||
sample_cache.removeFirst();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
p.fillRect(r, QColor(0, 0, 0, 160));
|
||||
channel_x += channel_width + AUDIO_MONITOR_GAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef AUDIOMONITOR_H
|
||||
#define AUDIOMONITOR_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class AudioMonitor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioMonitor(QWidget *parent = 0);
|
||||
QVector<qint16> sample_cache;
|
||||
long sample_cache_offset;
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
void resizeEvent(QResizeEvent *);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
QLinearGradient gradient;
|
||||
};
|
||||
|
||||
#endif // AUDIOMONITOR_H
|
||||
+67
-33
@@ -210,6 +210,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
|
||||
case TIMELINE_TOOL_POINTER:
|
||||
case TIMELINE_TOOL_RIPPLE:
|
||||
case TIMELINE_TOOL_SLIP:
|
||||
case TIMELINE_TOOL_ROLLING:
|
||||
{
|
||||
if (track_resizing) {
|
||||
track_resize_mouse_cache = event->pos().y();
|
||||
@@ -295,24 +296,26 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
|
||||
// ripple_length becomes the length/number of frames we trimmed
|
||||
// ripple point becomes the point to ripple (i.e. the point after or before which we move every clip)
|
||||
if (panel_timeline->trim_in) {
|
||||
ripple_length = panel_timeline->ghosts.at(0).old_in - panel_timeline->ghosts.at(0).in;
|
||||
ripple_point = panel_timeline->ghosts.at(0).old_in;
|
||||
const Ghost& first_ghost = panel_timeline->ghosts.at(0);
|
||||
if (panel_timeline->trim_in_point) {
|
||||
ripple_length = first_ghost.old_in - panel_timeline->ghosts.at(0).in;
|
||||
ripple_point = first_ghost.old_in;
|
||||
} else {
|
||||
// if we're trimming an out-point
|
||||
ripple_length = panel_timeline->ghosts.at(0).old_out - panel_timeline->ghosts.at(0).out;
|
||||
ripple_point = panel_timeline->ghosts.at(0).old_out;
|
||||
ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out;
|
||||
ripple_point = first_ghost.old_out;
|
||||
}
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
long comp_point;
|
||||
if (panel_timeline->trim_in) {
|
||||
comp_point = panel_timeline->ghosts.at(i).old_in;
|
||||
if (panel_timeline->trim_in_point) {
|
||||
comp_point = g.old_in;
|
||||
} else {
|
||||
comp_point = panel_timeline->ghosts.at(i).old_out;
|
||||
comp_point = g.old_out;
|
||||
}
|
||||
if (ripple_point > comp_point) ripple_point = comp_point;
|
||||
}
|
||||
if (!panel_timeline->trim_in) ripple_length = -ripple_length;
|
||||
if (!panel_timeline->trim_in_point) ripple_length = -ripple_length;
|
||||
panel_timeline->ripple(ripple_point, ripple_length);
|
||||
}
|
||||
|
||||
@@ -467,10 +470,11 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
void TimelineWidget::init_ghosts() {
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
Ghost& g = panel_timeline->ghosts[i];
|
||||
g.old_in = g.in;
|
||||
g.old_out = g.out;
|
||||
g.old_track = g.track;
|
||||
g.old_clip_in = g.clip_in;
|
||||
Clip* c = sequence->get_clip(g.clip);
|
||||
g.in = g.old_in = c->timeline_in;
|
||||
g.out = g.old_out = c->timeline_out;
|
||||
g.track = g.old_track = c->track;
|
||||
g.clip_in = g.old_clip_in = c->clip_in;
|
||||
|
||||
if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP) {
|
||||
// used for trim ops
|
||||
@@ -491,12 +495,12 @@ bool subvalidate_snapping(Ghost& g, long* frame_diff, long snap_point) {
|
||||
long in_validator = g.old_in + *frame_diff - snap_point;
|
||||
long out_validator = g.old_out + *frame_diff - snap_point;
|
||||
|
||||
if ((panel_timeline->trim_target == -1 || panel_timeline->trim_in) && in_validator > -snap_range && in_validator < snap_range) {
|
||||
if ((panel_timeline->trim_target == -1 || g.trim_in) && in_validator > -snap_range && in_validator < snap_range) {
|
||||
*frame_diff -= in_validator;
|
||||
panel_timeline->snap_point = snap_point;
|
||||
panel_timeline->snapped = true;
|
||||
return true;
|
||||
} else if (!panel_timeline->trim_in && out_validator > -snap_range && out_validator < snap_range) {
|
||||
} else if (!g.trim_in && out_validator > -snap_range && out_validator < snap_range) {
|
||||
*frame_diff -= out_validator;
|
||||
panel_timeline->snap_point = snap_point;
|
||||
panel_timeline->snapped = true;
|
||||
@@ -538,7 +542,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
|
||||
validate_snapping(g, &frame_diff);
|
||||
|
||||
if (panel_timeline->trim_in) {
|
||||
if (g.trim_in) {
|
||||
// prevent clip length from being less than 1 frame long
|
||||
validator = g.ghost_length - frame_diff;
|
||||
if (validator < 1) frame_diff -= (1 - validator);
|
||||
@@ -576,7 +580,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
for (int k=0;k<pre_clips.size();k++) {
|
||||
Clip* pre = pre_clips.at(k);
|
||||
if (pre != post && pre->track == post->track) {
|
||||
if (panel_timeline->trim_in) {
|
||||
if (panel_timeline->trim_in_point) {
|
||||
validator = post->timeline_in - frame_diff - pre->timeline_out;
|
||||
if (validator < 0) frame_diff += validator;
|
||||
} else {
|
||||
@@ -593,7 +597,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
Ghost& g = panel_timeline->ghosts[i];
|
||||
|
||||
if (panel_timeline->trim_in) {
|
||||
if (g.trim_in) {
|
||||
g.in = g.old_in + frame_diff;
|
||||
g.clip_in = g.old_clip_in + frame_diff;
|
||||
} else {
|
||||
@@ -605,7 +609,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
for (int i=0;i<panel_timeline->selections.size();i++) {
|
||||
Selection& s = panel_timeline->selections[i];
|
||||
|
||||
if (panel_timeline->trim_in) {
|
||||
if (panel_timeline->trim_in_point) {
|
||||
s.in = s.old_in + frame_diff;
|
||||
} else {
|
||||
s.out = s.old_out + frame_diff;
|
||||
@@ -780,14 +784,45 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
if (c != NULL && panel_timeline->is_clip_selected(c)) {
|
||||
Ghost g;
|
||||
g.clip = i;
|
||||
g.in = c->timeline_in;
|
||||
g.out = c->timeline_out;
|
||||
g.track = c->track;
|
||||
g.clip_in = c->clip_in;
|
||||
g.trim_in = panel_timeline->trim_in_point;
|
||||
panel_timeline->ghosts.append(g);
|
||||
}
|
||||
}
|
||||
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_ROLLING) {
|
||||
int size = panel_timeline->ghosts.size();
|
||||
for (int i=0;i<size;i++) {
|
||||
Clip* ghost_clip = sequence->get_clip(panel_timeline->ghosts.at(i).clip);
|
||||
for (int j=0;j<sequence->clip_count();j++) {
|
||||
Clip* comp_clip = sequence->get_clip(j);
|
||||
if (comp_clip->track == ghost_clip->track) {
|
||||
if ((panel_timeline->trim_in_point && comp_clip->timeline_out == ghost_clip->timeline_in) ||
|
||||
(!panel_timeline->trim_in_point && comp_clip->timeline_in == ghost_clip->timeline_out)) {
|
||||
// see if this clip is already selected, and if so just switch the trim_in
|
||||
bool found = false;
|
||||
for (int k=0;k<size;k++) {
|
||||
if (panel_timeline->ghosts.at(k).clip == j) {
|
||||
panel_timeline->ghosts[k].trim_in = !panel_timeline->trim_in_point;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// add ghost for this clip with opposite trim_in
|
||||
Ghost g;
|
||||
g.clip = j;
|
||||
g.trim_in = !panel_timeline->trim_in_point;
|
||||
panel_timeline->ghosts.append(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init_ghosts();
|
||||
|
||||
// ripple edit prep
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
|
||||
QVector<Clip*> axis_ghosts;
|
||||
@@ -797,8 +832,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
for (int j=0;j<axis_ghosts.size();j++) {
|
||||
Clip* cc = axis_ghosts.at(j);
|
||||
if (c->track == cc->track &&
|
||||
((panel_timeline->trim_in && c->timeline_in < cc->timeline_in) ||
|
||||
(!panel_timeline->trim_in && c->timeline_out > cc->timeline_out))) {
|
||||
((panel_timeline->trim_in_point && c->timeline_in < cc->timeline_in) ||
|
||||
(!panel_timeline->trim_in_point && c->timeline_out > cc->timeline_out))) {
|
||||
axis_ghosts[j] = c;
|
||||
found = true;
|
||||
break;
|
||||
@@ -814,7 +849,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
if (c != NULL && !panel_timeline->is_clip_selected(c)) {
|
||||
for (int j=0;j<axis_ghosts.size();j++) {
|
||||
Clip* axis = axis_ghosts.at(j);
|
||||
long comp_point = (panel_timeline->trim_in) ? axis->timeline_in : axis->timeline_out;
|
||||
long comp_point = (panel_timeline->trim_in_point) ? axis->timeline_in : axis->timeline_out;
|
||||
bool clip_is_pre = (c->timeline_in < comp_point);
|
||||
QVector<Clip*>& clip_list = clip_is_pre ? pre_clips : post_clips;
|
||||
bool found = false;
|
||||
@@ -834,10 +869,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// qDebug() << "found" << pre_clips.size() << "pres and" << post_clips.size() << "posts";
|
||||
}
|
||||
|
||||
init_ghosts();
|
||||
}
|
||||
|
||||
panel_timeline->moving_proc = true;
|
||||
}
|
||||
@@ -925,7 +957,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
panel_timeline->rect_select_h = 0;
|
||||
panel_timeline->rect_select_proc = true;
|
||||
}
|
||||
} else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
|
||||
} else if (panel_timeline->tool == TIMELINE_TOOL_POINTER ||
|
||||
panel_timeline->tool == TIMELINE_TOOL_RIPPLE ||
|
||||
panel_timeline->tool == TIMELINE_TOOL_ROLLING) {
|
||||
track_resizing = false;
|
||||
|
||||
QPoint pos = event->pos();
|
||||
@@ -943,7 +977,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
int nc = qAbs(c->timeline_in + 1 - panel_timeline->cursor_frame);
|
||||
if (nc < closeness) {
|
||||
panel_timeline->trim_target = i;
|
||||
panel_timeline->trim_in = true;
|
||||
panel_timeline->trim_in_point = true;
|
||||
closeness = nc;
|
||||
found = true;
|
||||
}
|
||||
@@ -952,7 +986,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
int nc = qAbs(c->timeline_out - 1 - panel_timeline->cursor_frame);
|
||||
if (nc < closeness) {
|
||||
panel_timeline->trim_target = i;
|
||||
panel_timeline->trim_in = false;
|
||||
panel_timeline->trim_in_point = false;
|
||||
closeness = nc;
|
||||
found = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user