change: change code style to Linux style except indent.
This commit is contained in:
@@ -27,39 +27,30 @@
|
||||
|
||||
using namespace olive::core;
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class Block;
|
||||
class Track;
|
||||
|
||||
class Timeline {
|
||||
public:
|
||||
enum MovementMode {
|
||||
kNone,
|
||||
kMove,
|
||||
kTrimIn,
|
||||
kTrimOut
|
||||
};
|
||||
enum MovementMode { kNone, kMove, kTrimIn, kTrimOut };
|
||||
|
||||
enum ThumbnailMode {
|
||||
kThumbnailOff,
|
||||
kThumbnailInOut,
|
||||
kThumbnailOn
|
||||
};
|
||||
enum ThumbnailMode { kThumbnailOff, kThumbnailInOut, kThumbnailOn };
|
||||
|
||||
enum WaveformMode {
|
||||
kWaveformsDisabled,
|
||||
kWaveformsEnabled
|
||||
};
|
||||
enum WaveformMode { kWaveformsDisabled, kWaveformsEnabled };
|
||||
|
||||
static bool IsATrimMode(MovementMode mode) {return mode == kTrimIn || mode == kTrimOut;}
|
||||
|
||||
struct EditToInfo {
|
||||
Track* track;
|
||||
rational nearest_time;
|
||||
Block* nearest_block;
|
||||
};
|
||||
static bool IsATrimMode(MovementMode mode)
|
||||
{
|
||||
return mode == kTrimIn || mode == kTrimOut;
|
||||
}
|
||||
|
||||
struct EditToInfo {
|
||||
Track *track;
|
||||
rational nearest_time;
|
||||
Block *nearest_block;
|
||||
};
|
||||
};
|
||||
|
||||
#define PLAYHEAD_COLOR palette().highlight().color()
|
||||
|
||||
@@ -20,43 +20,47 @@
|
||||
|
||||
#include "timelinecoordinate.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
TimelineCoordinate::TimelineCoordinate() :
|
||||
track_(Track::kNone, 0)
|
||||
TimelineCoordinate::TimelineCoordinate()
|
||||
: track_(Track::kNone, 0)
|
||||
{
|
||||
}
|
||||
|
||||
TimelineCoordinate::TimelineCoordinate(const rational &frame, const Track::Reference &track) :
|
||||
frame_(frame),
|
||||
track_(track)
|
||||
TimelineCoordinate::TimelineCoordinate(const rational &frame,
|
||||
const Track::Reference &track)
|
||||
: frame_(frame)
|
||||
, track_(track)
|
||||
{
|
||||
}
|
||||
|
||||
TimelineCoordinate::TimelineCoordinate(const rational &frame, const Track::Type &track_type, const int &track_index) :
|
||||
frame_(frame),
|
||||
track_(track_type, track_index)
|
||||
TimelineCoordinate::TimelineCoordinate(const rational &frame,
|
||||
const Track::Type &track_type,
|
||||
const int &track_index)
|
||||
: frame_(frame)
|
||||
, track_(track_type, track_index)
|
||||
{
|
||||
}
|
||||
|
||||
const rational &TimelineCoordinate::GetFrame() const
|
||||
{
|
||||
return frame_;
|
||||
return frame_;
|
||||
}
|
||||
|
||||
const Track::Reference &TimelineCoordinate::GetTrack() const
|
||||
{
|
||||
return track_;
|
||||
return track_;
|
||||
}
|
||||
|
||||
void TimelineCoordinate::SetFrame(const rational &frame)
|
||||
{
|
||||
frame_ = frame;
|
||||
frame_ = frame;
|
||||
}
|
||||
|
||||
void TimelineCoordinate::SetTrack(const Track::Reference &track)
|
||||
{
|
||||
track_ = track;
|
||||
track_ = track;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,26 +23,26 @@
|
||||
|
||||
#include "node/output/track/track.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class TimelineCoordinate
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class TimelineCoordinate {
|
||||
public:
|
||||
TimelineCoordinate();
|
||||
TimelineCoordinate(const rational& frame, const Track::Reference& track);
|
||||
TimelineCoordinate(const rational& frame, const Track::Type& track_type, const int& track_index);
|
||||
TimelineCoordinate();
|
||||
TimelineCoordinate(const rational &frame, const Track::Reference &track);
|
||||
TimelineCoordinate(const rational &frame, const Track::Type &track_type,
|
||||
const int &track_index);
|
||||
|
||||
const rational& GetFrame() const;
|
||||
const Track::Reference& GetTrack() const;
|
||||
const rational &GetFrame() const;
|
||||
const Track::Reference &GetTrack() const;
|
||||
|
||||
void SetFrame(const rational& frame);
|
||||
void SetTrack(const Track::Reference& track);
|
||||
void SetFrame(const rational &frame);
|
||||
void SetTrack(const Track::Reference &track);
|
||||
|
||||
private:
|
||||
rational frame_;
|
||||
|
||||
Track::Reference track_;
|
||||
rational frame_;
|
||||
|
||||
Track::Reference track_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+221
-194
@@ -28,376 +28,403 @@
|
||||
#include "core.h"
|
||||
#include "ui/colorcoding.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
TimelineMarker::TimelineMarker(QObject *parent) :
|
||||
color_(OLIVE_CONFIG("MarkerColor").toInt())
|
||||
namespace olive
|
||||
{
|
||||
setParent(parent);
|
||||
|
||||
TimelineMarker::TimelineMarker(QObject *parent)
|
||||
: color_(OLIVE_CONFIG("MarkerColor").toInt())
|
||||
{
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
TimelineMarker::TimelineMarker(int color, const TimeRange &time, const QString &name, QObject *parent) :
|
||||
time_(time),
|
||||
name_(name),
|
||||
color_(color)
|
||||
TimelineMarker::TimelineMarker(int color, const TimeRange &time,
|
||||
const QString &name, QObject *parent)
|
||||
: time_(time)
|
||||
, name_(name)
|
||||
, color_(color)
|
||||
{
|
||||
setParent(parent);
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
void TimelineMarker::set_time(const TimeRange &time)
|
||||
{
|
||||
time_ = time;
|
||||
emit TimeChanged(time_);
|
||||
time_ = time;
|
||||
emit TimeChanged(time_);
|
||||
}
|
||||
|
||||
void TimelineMarker::set_time(const rational &time)
|
||||
{
|
||||
set_time(TimeRange(time, time + time_.length()));
|
||||
set_time(TimeRange(time, time + time_.length()));
|
||||
}
|
||||
|
||||
bool TimelineMarker::has_sibling_at_time(const rational &t) const
|
||||
{
|
||||
TimelineMarker *m = static_cast<TimelineMarkerList*>(parent())->GetMarkerAtTime(t);
|
||||
return m && m != this;
|
||||
TimelineMarker *m =
|
||||
static_cast<TimelineMarkerList *>(parent())->GetMarkerAtTime(t);
|
||||
return m && m != this;
|
||||
}
|
||||
|
||||
void TimelineMarker::set_name(const QString &name)
|
||||
{
|
||||
name_ = name;
|
||||
emit NameChanged(name_);
|
||||
name_ = name;
|
||||
emit NameChanged(name_);
|
||||
}
|
||||
|
||||
void TimelineMarker::set_color(int c)
|
||||
{
|
||||
color_ = c;
|
||||
emit ColorChanged(color_);
|
||||
color_ = c;
|
||||
emit ColorChanged(color_);
|
||||
}
|
||||
|
||||
int TimelineMarker::GetMarkerHeight(const QFontMetrics &fm)
|
||||
{
|
||||
return fm.height();
|
||||
return fm.height();
|
||||
}
|
||||
|
||||
QRect TimelineMarker::Draw(QPainter *p, const QPoint &pt, int max_right, double scale, bool selected)
|
||||
QRect TimelineMarker::Draw(QPainter *p, const QPoint &pt, int max_right,
|
||||
double scale, bool selected)
|
||||
{
|
||||
QFontMetrics fm = p->fontMetrics();
|
||||
QFontMetrics fm = p->fontMetrics();
|
||||
|
||||
int marker_height = GetMarkerHeight(fm);
|
||||
int marker_width = QtUtils::QFontMetricsWidth(fm, QStringLiteral("H"));
|
||||
int marker_height = GetMarkerHeight(fm);
|
||||
int marker_width = QtUtils::QFontMetricsWidth(fm, QStringLiteral("H"));
|
||||
|
||||
int half_width = marker_width / 2;
|
||||
int half_width = marker_width / 2;
|
||||
|
||||
QColor c = QtUtils::toQColor(ColorCoding::GetColor(color()));
|
||||
if (selected) {
|
||||
p->setPen(Qt::white);
|
||||
p->setBrush(c.lighter());
|
||||
} else {
|
||||
p->setPen(Qt::black);
|
||||
p->setBrush(c);
|
||||
}
|
||||
QColor c = QtUtils::toQColor(ColorCoding::GetColor(color()));
|
||||
if (selected) {
|
||||
p->setPen(Qt::white);
|
||||
p->setBrush(c.lighter());
|
||||
} else {
|
||||
p->setPen(Qt::black);
|
||||
p->setBrush(c);
|
||||
}
|
||||
|
||||
int top = pt.y() - marker_height;
|
||||
int top = pt.y() - marker_height;
|
||||
|
||||
QTextOption op(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
op.setWrapMode(QTextOption::NoWrap);
|
||||
QTextOption op(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
op.setWrapMode(QTextOption::NoWrap);
|
||||
|
||||
if (time_.out() != time_.in()) {
|
||||
QRect marker_rect(pt.x(), top, time_.length().toDouble() * scale, marker_height);
|
||||
if (time_.out() != time_.in()) {
|
||||
QRect marker_rect(pt.x(), top, time_.length().toDouble() * scale,
|
||||
marker_height);
|
||||
|
||||
p->drawRect(marker_rect);
|
||||
p->drawRect(marker_rect);
|
||||
|
||||
if (!name_.isEmpty()) {
|
||||
p->setPen(ColorCoding::GetUISelectorColor(ColorCoding::GetColor(color_)));
|
||||
p->drawText(marker_rect.adjusted(marker_width/4, 0, 0, 0), name_, op);
|
||||
}
|
||||
if (!name_.isEmpty()) {
|
||||
p->setPen(
|
||||
ColorCoding::GetUISelectorColor(ColorCoding::GetColor(color_)));
|
||||
p->drawText(marker_rect.adjusted(marker_width / 4, 0, 0, 0), name_,
|
||||
op);
|
||||
}
|
||||
|
||||
return marker_rect;
|
||||
} else {
|
||||
int half_marker_height = marker_height / 3;
|
||||
int left = pt.x() - half_width;
|
||||
int right = pt.x() + half_width;
|
||||
int center_y = pt.y() - half_marker_height;
|
||||
return marker_rect;
|
||||
} else {
|
||||
int half_marker_height = marker_height / 3;
|
||||
int left = pt.x() - half_width;
|
||||
int right = pt.x() + half_width;
|
||||
int center_y = pt.y() - half_marker_height;
|
||||
|
||||
QPoint points[] = {
|
||||
pt,
|
||||
QPoint(left, center_y),
|
||||
QPoint(left, top),
|
||||
QPoint(right, top),
|
||||
QPoint(right, center_y),
|
||||
pt,
|
||||
};
|
||||
QPoint points[] = {
|
||||
pt,
|
||||
QPoint(left, center_y),
|
||||
QPoint(left, top),
|
||||
QPoint(right, top),
|
||||
QPoint(right, center_y),
|
||||
pt,
|
||||
};
|
||||
|
||||
p->setRenderHint(QPainter::Antialiasing);
|
||||
p->drawPolygon(points, 6);
|
||||
p->setRenderHint(QPainter::Antialiasing);
|
||||
p->drawPolygon(points, 6);
|
||||
|
||||
if (!name_.isEmpty() && max_right != -1) {
|
||||
QRect text_rect(right, top, max_right - right, marker_height);
|
||||
if (!name_.isEmpty() && max_right != -1) {
|
||||
QRect text_rect(right, top, max_right - right, marker_height);
|
||||
|
||||
int padding = QtUtils::QFontMetricsWidth(p->fontMetrics(), QStringLiteral(" "));
|
||||
text_rect.adjust(padding, 0, - padding - half_width, 0);
|
||||
int padding = QtUtils::QFontMetricsWidth(p->fontMetrics(),
|
||||
QStringLiteral(" "));
|
||||
text_rect.adjust(padding, 0, -padding - half_width, 0);
|
||||
|
||||
p->setPen(qApp->palette().text().color());
|
||||
p->drawText(text_rect, name_, op);
|
||||
}
|
||||
p->setPen(qApp->palette().text().color());
|
||||
p->drawText(text_rect, name_, op);
|
||||
}
|
||||
|
||||
return QRect(left, top, marker_width, marker_height);
|
||||
}
|
||||
return QRect(left, top, marker_width, marker_height);
|
||||
}
|
||||
}
|
||||
|
||||
bool TimelineMarker::load(QXmlStreamReader *reader)
|
||||
{
|
||||
rational in, out;
|
||||
rational in, out;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
this->set_name(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("color")) {
|
||||
this->set_color(attr.value().toInt());
|
||||
}
|
||||
}
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
this->set_name(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("color")) {
|
||||
this->set_color(attr.value().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
this->set_time(TimeRange(in, out));
|
||||
this->set_time(TimeRange(in, out));
|
||||
|
||||
// This element has no inner text, so just skip it
|
||||
reader->skipCurrentElement();
|
||||
// This element has no inner text, so just skip it
|
||||
reader->skipCurrentElement();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimelineMarker::save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("name"), this->name());
|
||||
writer->writeAttribute(QStringLiteral("in"), QString::fromStdString(this->time().in().toString()));
|
||||
writer->writeAttribute(QStringLiteral("out"), QString::fromStdString(this->time().out().toString()));
|
||||
writer->writeAttribute(QStringLiteral("color"), QString::number(this->color()));
|
||||
writer->writeAttribute(QStringLiteral("name"), this->name());
|
||||
writer->writeAttribute(
|
||||
QStringLiteral("in"),
|
||||
QString::fromStdString(this->time().in().toString()));
|
||||
writer->writeAttribute(
|
||||
QStringLiteral("out"),
|
||||
QString::fromStdString(this->time().out().toString()));
|
||||
writer->writeAttribute(QStringLiteral("color"),
|
||||
QString::number(this->color()));
|
||||
}
|
||||
|
||||
bool TimelineMarkerList::load(QXmlStreamReader *reader)
|
||||
{
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("marker")) {
|
||||
TimelineMarker *marker = new TimelineMarker(this);
|
||||
if (!marker->load(reader)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("marker")) {
|
||||
TimelineMarker *marker = new TimelineMarker(this);
|
||||
if (!marker->load(reader)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimelineMarkerList::save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
for (auto it=this->cbegin(); it!=this->cend(); it++) {
|
||||
TimelineMarker* marker = *it;
|
||||
for (auto it = this->cbegin(); it != this->cend(); it++) {
|
||||
TimelineMarker *marker = *it;
|
||||
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
writer->writeStartElement(QStringLiteral("marker"));
|
||||
|
||||
marker->save(writer);
|
||||
marker->save(writer);
|
||||
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
writer->writeEndElement(); // marker
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineMarkerList::childEvent(QChildEvent *e)
|
||||
{
|
||||
QObject::childEvent(e);
|
||||
QObject::childEvent(e);
|
||||
|
||||
if (TimelineMarker *marker = dynamic_cast<TimelineMarker *>(e->child())) {
|
||||
if (e->type() == QChildEvent::ChildAdded) {
|
||||
if (TimelineMarker *marker = dynamic_cast<TimelineMarker *>(e->child())) {
|
||||
if (e->type() == QChildEvent::ChildAdded) {
|
||||
connect(marker, &TimelineMarker::TimeChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerTimeChange);
|
||||
connect(marker, &TimelineMarker::TimeChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerModification);
|
||||
connect(marker, &TimelineMarker::NameChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerModification);
|
||||
connect(marker, &TimelineMarker::ColorChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerModification);
|
||||
|
||||
connect(marker, &TimelineMarker::TimeChanged, this, &TimelineMarkerList::HandleMarkerTimeChange);
|
||||
connect(marker, &TimelineMarker::TimeChanged, this, &TimelineMarkerList::HandleMarkerModification);
|
||||
connect(marker, &TimelineMarker::NameChanged, this, &TimelineMarkerList::HandleMarkerModification);
|
||||
connect(marker, &TimelineMarker::ColorChanged, this, &TimelineMarkerList::HandleMarkerModification);
|
||||
InsertIntoList(marker);
|
||||
|
||||
InsertIntoList(marker);
|
||||
emit MarkerAdded(marker);
|
||||
|
||||
emit MarkerAdded(marker);
|
||||
} else if (e->type() == QChildEvent::ChildRemoved) {
|
||||
RemoveFromList(marker);
|
||||
|
||||
} else if (e->type() == QChildEvent::ChildRemoved) {
|
||||
disconnect(marker, &TimelineMarker::TimeChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerTimeChange);
|
||||
disconnect(marker, &TimelineMarker::TimeChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerModification);
|
||||
disconnect(marker, &TimelineMarker::NameChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerModification);
|
||||
disconnect(marker, &TimelineMarker::ColorChanged, this,
|
||||
&TimelineMarkerList::HandleMarkerModification);
|
||||
|
||||
RemoveFromList(marker);
|
||||
|
||||
disconnect(marker, &TimelineMarker::TimeChanged, this, &TimelineMarkerList::HandleMarkerTimeChange);
|
||||
disconnect(marker, &TimelineMarker::TimeChanged, this, &TimelineMarkerList::HandleMarkerModification);
|
||||
disconnect(marker, &TimelineMarker::NameChanged, this, &TimelineMarkerList::HandleMarkerModification);
|
||||
disconnect(marker, &TimelineMarker::ColorChanged, this, &TimelineMarkerList::HandleMarkerModification);
|
||||
|
||||
emit MarkerRemoved(marker);
|
||||
|
||||
}
|
||||
}
|
||||
emit MarkerRemoved(marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineMarkerList::InsertIntoList(TimelineMarker *marker)
|
||||
{
|
||||
// Insertion sort by time to allow some loop optimizations
|
||||
bool found = false;
|
||||
for (auto it=markers_.begin(); it!=markers_.end(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
// Insertion sort by time to allow some loop optimizations
|
||||
bool found = false;
|
||||
for (auto it = markers_.begin(); it != markers_.end(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
|
||||
Q_ASSERT(m->time().in() != marker->time().in());
|
||||
Q_ASSERT(m->time().in() != marker->time().in());
|
||||
|
||||
if (m->time().in() > marker->time().in()) {
|
||||
markers_.insert(it, marker);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m->time().in() > marker->time().in()) {
|
||||
markers_.insert(it, marker);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
markers_.push_back(marker);
|
||||
}
|
||||
if (!found) {
|
||||
markers_.push_back(marker);
|
||||
}
|
||||
}
|
||||
|
||||
bool TimelineMarkerList::RemoveFromList(TimelineMarker *marker)
|
||||
{
|
||||
auto it = std::find(markers_.begin(), markers_.end(), marker);
|
||||
auto it = std::find(markers_.begin(), markers_.end(), marker);
|
||||
|
||||
if (it != markers_.end()) {
|
||||
markers_.erase(it);
|
||||
return true;
|
||||
}
|
||||
if (it != markers_.end()) {
|
||||
markers_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void TimelineMarkerList::HandleMarkerModification()
|
||||
{
|
||||
emit MarkerModified(static_cast<TimelineMarker*>(sender()));
|
||||
emit MarkerModified(static_cast<TimelineMarker *>(sender()));
|
||||
}
|
||||
|
||||
void TimelineMarkerList::HandleMarkerTimeChange()
|
||||
{
|
||||
TimelineMarker *m = static_cast<TimelineMarker*>(sender());
|
||||
TimelineMarker *m = static_cast<TimelineMarker *>(sender());
|
||||
|
||||
auto it = std::find(markers_.begin(), markers_.end(), m);
|
||||
auto it = std::find(markers_.begin(), markers_.end(), m);
|
||||
|
||||
if (it != markers_.end()) {
|
||||
markers_.erase(it);
|
||||
InsertIntoList(m);
|
||||
}
|
||||
if (it != markers_.end()) {
|
||||
markers_.erase(it);
|
||||
InsertIntoList(m);
|
||||
}
|
||||
}
|
||||
|
||||
MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list, const TimeRange &range, const QString &name, int color) :
|
||||
MarkerAddCommand(marker_list, new TimelineMarker(color, range, name, &memory_manager_))
|
||||
MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list,
|
||||
const TimeRange &range, const QString &name,
|
||||
int color)
|
||||
: MarkerAddCommand(marker_list,
|
||||
new TimelineMarker(color, range, name, &memory_manager_))
|
||||
{
|
||||
}
|
||||
|
||||
MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list, TimelineMarker *marker) :
|
||||
marker_list_(marker_list),
|
||||
added_marker_(marker)
|
||||
MarkerAddCommand::MarkerAddCommand(TimelineMarkerList *marker_list,
|
||||
TimelineMarker *marker)
|
||||
: marker_list_(marker_list)
|
||||
, added_marker_(marker)
|
||||
{
|
||||
added_marker_->setParent(&memory_manager_);
|
||||
added_marker_->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
Project* MarkerAddCommand::GetRelevantProject() const
|
||||
Project *MarkerAddCommand::GetRelevantProject() const
|
||||
{
|
||||
return Project::GetProjectFromObject(marker_list_);
|
||||
return Project::GetProjectFromObject(marker_list_);
|
||||
}
|
||||
|
||||
void MarkerAddCommand::redo()
|
||||
{
|
||||
added_marker_->setParent(marker_list_);
|
||||
added_marker_->setParent(marker_list_);
|
||||
}
|
||||
|
||||
void MarkerAddCommand::undo()
|
||||
{
|
||||
added_marker_->setParent(&memory_manager_);
|
||||
added_marker_->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
MarkerRemoveCommand::MarkerRemoveCommand(TimelineMarker *marker) :
|
||||
marker_(marker)
|
||||
MarkerRemoveCommand::MarkerRemoveCommand(TimelineMarker *marker)
|
||||
: marker_(marker)
|
||||
{
|
||||
}
|
||||
|
||||
Project* MarkerRemoveCommand::GetRelevantProject() const
|
||||
Project *MarkerRemoveCommand::GetRelevantProject() const
|
||||
{
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
}
|
||||
|
||||
void MarkerRemoveCommand::redo()
|
||||
{
|
||||
marker_list_ = marker_->parent();
|
||||
marker_->setParent(&memory_manager_);
|
||||
marker_list_ = marker_->parent();
|
||||
marker_->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
void MarkerRemoveCommand::undo()
|
||||
{
|
||||
marker_->setParent(marker_list_);
|
||||
marker_->setParent(marker_list_);
|
||||
}
|
||||
|
||||
MarkerChangeColorCommand::MarkerChangeColorCommand(TimelineMarker *marker, int new_color) :
|
||||
marker_(marker),
|
||||
new_color_(new_color)
|
||||
MarkerChangeColorCommand::MarkerChangeColorCommand(TimelineMarker *marker,
|
||||
int new_color)
|
||||
: marker_(marker)
|
||||
, new_color_(new_color)
|
||||
{
|
||||
}
|
||||
|
||||
Project* MarkerChangeColorCommand::GetRelevantProject() const
|
||||
Project *MarkerChangeColorCommand::GetRelevantProject() const
|
||||
{
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
}
|
||||
|
||||
void MarkerChangeColorCommand::redo()
|
||||
{
|
||||
old_color_ = marker_->color();
|
||||
marker_->set_color(new_color_);
|
||||
old_color_ = marker_->color();
|
||||
marker_->set_color(new_color_);
|
||||
}
|
||||
|
||||
void MarkerChangeColorCommand::undo()
|
||||
{
|
||||
marker_->set_color(old_color_);
|
||||
marker_->set_color(old_color_);
|
||||
}
|
||||
|
||||
MarkerChangeNameCommand::MarkerChangeNameCommand(TimelineMarker *marker, QString new_name) :
|
||||
marker_(marker),
|
||||
new_name_(new_name)
|
||||
MarkerChangeNameCommand::MarkerChangeNameCommand(TimelineMarker *marker,
|
||||
QString new_name)
|
||||
: marker_(marker)
|
||||
, new_name_(new_name)
|
||||
{
|
||||
}
|
||||
|
||||
Project* MarkerChangeNameCommand::GetRelevantProject() const
|
||||
Project *MarkerChangeNameCommand::GetRelevantProject() const
|
||||
{
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
}
|
||||
|
||||
void MarkerChangeNameCommand::redo()
|
||||
{
|
||||
old_name_ = marker_->name();
|
||||
marker_->set_name(new_name_);
|
||||
old_name_ = marker_->name();
|
||||
marker_->set_name(new_name_);
|
||||
}
|
||||
|
||||
void MarkerChangeNameCommand::undo()
|
||||
{
|
||||
marker_->set_name(old_name_);
|
||||
marker_->set_name(old_name_);
|
||||
}
|
||||
|
||||
MarkerChangeTimeCommand::MarkerChangeTimeCommand(TimelineMarker* marker, const TimeRange &time, const TimeRange &old_time) :
|
||||
marker_(marker),
|
||||
old_time_(old_time),
|
||||
new_time_(time)
|
||||
MarkerChangeTimeCommand::MarkerChangeTimeCommand(TimelineMarker *marker,
|
||||
const TimeRange &time,
|
||||
const TimeRange &old_time)
|
||||
: marker_(marker)
|
||||
, old_time_(old_time)
|
||||
, new_time_(time)
|
||||
{
|
||||
}
|
||||
|
||||
Project* MarkerChangeTimeCommand::GetRelevantProject() const
|
||||
Project *MarkerChangeTimeCommand::GetRelevantProject() const
|
||||
{
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
return Project::GetProjectFromObject(marker_);
|
||||
}
|
||||
|
||||
void MarkerChangeTimeCommand::redo()
|
||||
{
|
||||
marker_->set_time(new_time_);
|
||||
marker_->set_time(new_time_);
|
||||
}
|
||||
|
||||
void MarkerChangeTimeCommand::undo()
|
||||
{
|
||||
marker_->set_time(old_time_);
|
||||
marker_->set_time(old_time_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+154
-123
@@ -31,218 +31,249 @@
|
||||
|
||||
using namespace olive::core;
|
||||
|
||||
namespace olive {
|
||||
|
||||
class TimelineMarker : public QObject
|
||||
namespace olive
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
class TimelineMarker : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimelineMarker(QObject* parent = nullptr);
|
||||
TimelineMarker(int color, const TimeRange& time, const QString& name = QString(), QObject* parent = nullptr);
|
||||
TimelineMarker(QObject *parent = nullptr);
|
||||
TimelineMarker(int color, const TimeRange &time,
|
||||
const QString &name = QString(), QObject *parent = nullptr);
|
||||
|
||||
const TimeRange &time() const { return time_; }
|
||||
void set_time(const TimeRange& time);
|
||||
void set_time(const rational& time);
|
||||
const TimeRange &time() const
|
||||
{
|
||||
return time_;
|
||||
}
|
||||
void set_time(const TimeRange &time);
|
||||
void set_time(const rational &time);
|
||||
|
||||
bool has_sibling_at_time(const rational &t) const;
|
||||
bool has_sibling_at_time(const rational &t) const;
|
||||
|
||||
const QString& name() const { return name_; }
|
||||
void set_name(const QString& name);
|
||||
const QString &name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
void set_name(const QString &name);
|
||||
|
||||
int color() const { return color_; }
|
||||
void set_color(int c);
|
||||
int color() const
|
||||
{
|
||||
return color_;
|
||||
}
|
||||
void set_color(int c);
|
||||
|
||||
static int GetMarkerHeight(const QFontMetrics &fm);
|
||||
QRect Draw(QPainter *p, const QPoint &pt, int max_right, double scale, bool selected);
|
||||
static int GetMarkerHeight(const QFontMetrics &fm);
|
||||
QRect Draw(QPainter *p, const QPoint &pt, int max_right, double scale,
|
||||
bool selected);
|
||||
|
||||
bool load(QXmlStreamReader *reader);
|
||||
void save(QXmlStreamWriter *writer) const;
|
||||
bool load(QXmlStreamReader *reader);
|
||||
void save(QXmlStreamWriter *writer) const;
|
||||
|
||||
signals:
|
||||
void TimeChanged(const TimeRange& time);
|
||||
void TimeChanged(const TimeRange &time);
|
||||
|
||||
void NameChanged(const QString& name);
|
||||
void NameChanged(const QString &name);
|
||||
|
||||
void ColorChanged(int c);
|
||||
void ColorChanged(int c);
|
||||
|
||||
private:
|
||||
TimeRange time_;
|
||||
TimeRange time_;
|
||||
|
||||
QString name_;
|
||||
|
||||
int color_;
|
||||
QString name_;
|
||||
|
||||
int color_;
|
||||
};
|
||||
|
||||
class TimelineMarkerList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class TimelineMarkerList : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimelineMarkerList(QObject *parent = nullptr) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
TimelineMarkerList(QObject *parent = nullptr)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool empty() const { return markers_.empty(); }
|
||||
inline std::vector<TimelineMarker*>::iterator begin() { return markers_.begin(); }
|
||||
inline std::vector<TimelineMarker*>::iterator end() { return markers_.end(); }
|
||||
inline std::vector<TimelineMarker*>::const_iterator cbegin() const { return markers_.cbegin(); }
|
||||
inline std::vector<TimelineMarker*>::const_iterator cend() const { return markers_.cend(); }
|
||||
inline TimelineMarker *back() const { return markers_.back(); }
|
||||
inline TimelineMarker *front() const { return markers_.front(); }
|
||||
inline size_t size() const { return markers_.size(); }
|
||||
inline bool empty() const
|
||||
{
|
||||
return markers_.empty();
|
||||
}
|
||||
inline std::vector<TimelineMarker *>::iterator begin()
|
||||
{
|
||||
return markers_.begin();
|
||||
}
|
||||
inline std::vector<TimelineMarker *>::iterator end()
|
||||
{
|
||||
return markers_.end();
|
||||
}
|
||||
inline std::vector<TimelineMarker *>::const_iterator cbegin() const
|
||||
{
|
||||
return markers_.cbegin();
|
||||
}
|
||||
inline std::vector<TimelineMarker *>::const_iterator cend() const
|
||||
{
|
||||
return markers_.cend();
|
||||
}
|
||||
inline TimelineMarker *back() const
|
||||
{
|
||||
return markers_.back();
|
||||
}
|
||||
inline TimelineMarker *front() const
|
||||
{
|
||||
return markers_.front();
|
||||
}
|
||||
inline size_t size() const
|
||||
{
|
||||
return markers_.size();
|
||||
}
|
||||
|
||||
bool load(QXmlStreamReader *reader);
|
||||
void save(QXmlStreamWriter *writer) const;
|
||||
bool load(QXmlStreamReader *reader);
|
||||
void save(QXmlStreamWriter *writer) const;
|
||||
|
||||
TimelineMarker *GetMarkerAtTime(const rational &t) const
|
||||
{
|
||||
for (auto it=markers_.cbegin(); it!=markers_.cend(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
if (m->time().in() == t) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
TimelineMarker *GetMarkerAtTime(const rational &t) const
|
||||
{
|
||||
for (auto it = markers_.cbegin(); it != markers_.cend(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
if (m->time().in() == t) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TimelineMarker *GetClosestMarkerToTime(const rational &t) const
|
||||
{
|
||||
TimelineMarker *closest = nullptr;
|
||||
TimelineMarker *GetClosestMarkerToTime(const rational &t) const
|
||||
{
|
||||
TimelineMarker *closest = nullptr;
|
||||
|
||||
for (auto it=markers_.cbegin(); it!=markers_.cend(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
for (auto it = markers_.cbegin(); it != markers_.cend(); it++) {
|
||||
TimelineMarker *m = *it;
|
||||
|
||||
rational this_diff = qAbs(m->time().in() - t);
|
||||
rational this_diff = qAbs(m->time().in() - t);
|
||||
|
||||
if (closest) {
|
||||
rational stored_diff = qAbs(closest->time().in() - t);
|
||||
if (closest) {
|
||||
rational stored_diff = qAbs(closest->time().in() - t);
|
||||
|
||||
if (this_diff > stored_diff) {
|
||||
// Since the list is organized by time, if the diff increases, assume we are only going
|
||||
// to move further away from here and there's no need to check
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this_diff > stored_diff) {
|
||||
// Since the list is organized by time, if the diff increases, assume we are only going
|
||||
// to move further away from here and there's no need to check
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closest = m;
|
||||
}
|
||||
closest = m;
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
signals:
|
||||
void MarkerAdded(TimelineMarker* marker);
|
||||
void MarkerAdded(TimelineMarker *marker);
|
||||
|
||||
void MarkerRemoved(TimelineMarker* marker);
|
||||
void MarkerRemoved(TimelineMarker *marker);
|
||||
|
||||
void MarkerModified(TimelineMarker* marker);
|
||||
void MarkerModified(TimelineMarker *marker);
|
||||
|
||||
protected:
|
||||
virtual void childEvent(QChildEvent *e) override;
|
||||
virtual void childEvent(QChildEvent *e) override;
|
||||
|
||||
private:
|
||||
void InsertIntoList(TimelineMarker *m);
|
||||
bool RemoveFromList(TimelineMarker *m);
|
||||
void InsertIntoList(TimelineMarker *m);
|
||||
bool RemoveFromList(TimelineMarker *m);
|
||||
|
||||
std::vector<TimelineMarker*> markers_;
|
||||
std::vector<TimelineMarker *> markers_;
|
||||
|
||||
private slots:
|
||||
void HandleMarkerModification();
|
||||
|
||||
void HandleMarkerTimeChange();
|
||||
void HandleMarkerModification();
|
||||
|
||||
void HandleMarkerTimeChange();
|
||||
};
|
||||
|
||||
class MarkerAddCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerAddCommand(TimelineMarkerList* marker_list, const TimeRange& range, const QString& name, int color);
|
||||
MarkerAddCommand(TimelineMarkerList* marker_list, TimelineMarker *marker);
|
||||
MarkerAddCommand(TimelineMarkerList *marker_list, const TimeRange &range,
|
||||
const QString &name, int color);
|
||||
MarkerAddCommand(TimelineMarkerList *marker_list, TimelineMarker *marker);
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
virtual Project *GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TimelineMarkerList* marker_list_;
|
||||
|
||||
TimelineMarker* added_marker_;
|
||||
QObject memory_manager_;
|
||||
TimelineMarkerList *marker_list_;
|
||||
|
||||
TimelineMarker *added_marker_;
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
class MarkerRemoveCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerRemoveCommand(TimelineMarker* marker);
|
||||
MarkerRemoveCommand(TimelineMarker *marker);
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
virtual Project *GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TimelineMarker* marker_;
|
||||
QObject* marker_list_;
|
||||
|
||||
QObject memory_manager_;
|
||||
TimelineMarker *marker_;
|
||||
QObject *marker_list_;
|
||||
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
class MarkerChangeColorCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerChangeColorCommand(TimelineMarker* marker, int new_color);
|
||||
MarkerChangeColorCommand(TimelineMarker *marker, int new_color);
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
virtual Project *GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TimelineMarker* marker_;
|
||||
int old_color_;
|
||||
int new_color_;
|
||||
|
||||
TimelineMarker *marker_;
|
||||
int old_color_;
|
||||
int new_color_;
|
||||
};
|
||||
|
||||
class MarkerChangeNameCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerChangeNameCommand(TimelineMarker* marker, QString name);
|
||||
MarkerChangeNameCommand(TimelineMarker *marker, QString name);
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
virtual Project *GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TimelineMarker* marker_;
|
||||
QString old_name_;
|
||||
QString new_name_;
|
||||
TimelineMarker *marker_;
|
||||
QString old_name_;
|
||||
QString new_name_;
|
||||
};
|
||||
|
||||
class MarkerChangeTimeCommand : public UndoCommand {
|
||||
public:
|
||||
MarkerChangeTimeCommand(TimelineMarker* marker, const TimeRange &time, const TimeRange &old_time);
|
||||
MarkerChangeTimeCommand(TimelineMarker* marker, const TimeRange &time) :
|
||||
MarkerChangeTimeCommand(marker, time, marker->time())
|
||||
{}
|
||||
MarkerChangeTimeCommand(TimelineMarker *marker, const TimeRange &time,
|
||||
const TimeRange &old_time);
|
||||
MarkerChangeTimeCommand(TimelineMarker *marker, const TimeRange &time)
|
||||
: MarkerChangeTimeCommand(marker, time, marker->time())
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
virtual Project *GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TimelineMarker* marker_;
|
||||
TimeRange old_time_;
|
||||
TimeRange new_time_;
|
||||
|
||||
TimelineMarker *marker_;
|
||||
TimeRange old_time_;
|
||||
TimeRange new_time_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -24,23 +24,24 @@
|
||||
#include "node/node.h"
|
||||
#include "node/nodeundo.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
inline bool NodeCanBeRemoved(Node* n)
|
||||
namespace olive
|
||||
{
|
||||
return n->output_connections().empty();
|
||||
|
||||
inline bool NodeCanBeRemoved(Node *n)
|
||||
{
|
||||
return n->output_connections().empty();
|
||||
}
|
||||
|
||||
inline UndoCommand* CreateRemoveCommand(Node* n)
|
||||
inline UndoCommand *CreateRemoveCommand(Node *n)
|
||||
{
|
||||
return new NodeRemoveWithExclusiveDependenciesAndDisconnect(n);
|
||||
return new NodeRemoveWithExclusiveDependenciesAndDisconnect(n);
|
||||
}
|
||||
|
||||
inline UndoCommand* CreateAndRunRemoveCommand(Node* n)
|
||||
inline UndoCommand *CreateAndRunRemoveCommand(Node *n)
|
||||
{
|
||||
UndoCommand* command = CreateRemoveCommand(n);
|
||||
command->redo_now();
|
||||
return command;
|
||||
UndoCommand *command = CreateRemoveCommand(n);
|
||||
command->redo_now();
|
||||
return command;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+239
-248
@@ -30,387 +30,378 @@
|
||||
#include "node/project/sequence/sequence.h"
|
||||
#include "timelineundosplit.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class BlockResizeCommand : public UndoCommand {
|
||||
public:
|
||||
BlockResizeCommand(Block* block, rational new_length) :
|
||||
block_(block),
|
||||
new_length_(new_length)
|
||||
{
|
||||
}
|
||||
BlockResizeCommand(Block *block, rational new_length)
|
||||
: block_(block)
|
||||
, new_length_(new_length)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Block* block_;
|
||||
rational old_length_;
|
||||
rational new_length_;
|
||||
|
||||
Block *block_;
|
||||
rational old_length_;
|
||||
rational new_length_;
|
||||
};
|
||||
|
||||
class BlockResizeWithMediaInCommand : public UndoCommand {
|
||||
public:
|
||||
BlockResizeWithMediaInCommand(Block* block, rational new_length) :
|
||||
block_(block),
|
||||
new_length_(new_length)
|
||||
{
|
||||
}
|
||||
BlockResizeWithMediaInCommand(Block *block, rational new_length)
|
||||
: block_(block)
|
||||
, new_length_(new_length)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo();
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
virtual void undo();
|
||||
|
||||
private:
|
||||
Block* block_;
|
||||
rational old_length_;
|
||||
rational new_length_;
|
||||
|
||||
Block *block_;
|
||||
rational old_length_;
|
||||
rational new_length_;
|
||||
};
|
||||
|
||||
class BlockSetMediaInCommand : public UndoCommand {
|
||||
public:
|
||||
BlockSetMediaInCommand(ClipBlock* block, rational new_media_in) :
|
||||
block_(block),
|
||||
new_media_in_(new_media_in)
|
||||
{
|
||||
}
|
||||
BlockSetMediaInCommand(ClipBlock *block, rational new_media_in)
|
||||
: block_(block)
|
||||
, new_media_in_(new_media_in)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo();
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
virtual void undo();
|
||||
|
||||
private:
|
||||
ClipBlock* block_;
|
||||
rational old_media_in_;
|
||||
rational new_media_in_;
|
||||
|
||||
ClipBlock *block_;
|
||||
rational old_media_in_;
|
||||
rational new_media_in_;
|
||||
};
|
||||
|
||||
class TimelineAddTrackCommand : public UndoCommand {
|
||||
public:
|
||||
TimelineAddTrackCommand(TrackList *timeline) :
|
||||
TimelineAddTrackCommand(timeline, OLIVE_CONFIG("AutoMergeTracks").toBool())
|
||||
{
|
||||
}
|
||||
TimelineAddTrackCommand(TrackList *timeline)
|
||||
: TimelineAddTrackCommand(timeline,
|
||||
OLIVE_CONFIG("AutoMergeTracks").toBool())
|
||||
{
|
||||
}
|
||||
|
||||
TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks);
|
||||
TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks);
|
||||
|
||||
static Track* RunImmediately(TrackList *timeline)
|
||||
{
|
||||
TimelineAddTrackCommand c(timeline);
|
||||
c.redo();
|
||||
return c.track();
|
||||
}
|
||||
static Track *RunImmediately(TrackList *timeline)
|
||||
{
|
||||
TimelineAddTrackCommand c(timeline);
|
||||
c.redo();
|
||||
return c.track();
|
||||
}
|
||||
|
||||
static Track* RunImmediately(TrackList *timeline, bool automerge)
|
||||
{
|
||||
TimelineAddTrackCommand c(timeline, automerge);
|
||||
c.redo();
|
||||
return c.track();
|
||||
}
|
||||
static Track *RunImmediately(TrackList *timeline, bool automerge)
|
||||
{
|
||||
TimelineAddTrackCommand c(timeline, automerge);
|
||||
c.redo();
|
||||
return c.track();
|
||||
}
|
||||
|
||||
virtual ~TimelineAddTrackCommand() override
|
||||
{
|
||||
delete position_command_;
|
||||
}
|
||||
virtual ~TimelineAddTrackCommand() override
|
||||
{
|
||||
delete position_command_;
|
||||
}
|
||||
|
||||
Track* track() const
|
||||
{
|
||||
return track_;
|
||||
}
|
||||
Track *track() const
|
||||
{
|
||||
return track_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->parent()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->parent()->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TrackList* timeline_;
|
||||
TrackList *timeline_;
|
||||
|
||||
Track* track_;
|
||||
Node* merge_;
|
||||
NodeInput base_;
|
||||
NodeInput blend_;
|
||||
Track *track_;
|
||||
Node *merge_;
|
||||
NodeInput base_;
|
||||
NodeInput blend_;
|
||||
|
||||
NodeInput direct_;
|
||||
NodeInput direct_;
|
||||
|
||||
MultiUndoCommand* position_command_;
|
||||
|
||||
QObject memory_manager_;
|
||||
MultiUndoCommand *position_command_;
|
||||
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
class TimelineRemoveTrackCommand : public UndoCommand
|
||||
{
|
||||
class TimelineRemoveTrackCommand : public UndoCommand {
|
||||
public:
|
||||
TimelineRemoveTrackCommand(Track *track) :
|
||||
track_(track),
|
||||
remove_command_(nullptr)
|
||||
{}
|
||||
TimelineRemoveTrackCommand(Track *track)
|
||||
: track_(track)
|
||||
, remove_command_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TimelineRemoveTrackCommand()
|
||||
{
|
||||
delete remove_command_;
|
||||
}
|
||||
virtual ~TimelineRemoveTrackCommand()
|
||||
{
|
||||
delete remove_command_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Track *track_;
|
||||
Track *track_;
|
||||
|
||||
TrackList *list_;
|
||||
TrackList *list_;
|
||||
|
||||
int index_;
|
||||
|
||||
UndoCommand *remove_command_;
|
||||
int index_;
|
||||
|
||||
UndoCommand *remove_command_;
|
||||
};
|
||||
|
||||
class TransitionRemoveCommand : public UndoCommand {
|
||||
public:
|
||||
TransitionRemoveCommand(TransitionBlock* block, bool remove_from_graph) :
|
||||
block_(block),
|
||||
remove_from_graph_(remove_from_graph),
|
||||
remove_command_(nullptr)
|
||||
{
|
||||
}
|
||||
TransitionRemoveCommand(TransitionBlock *block, bool remove_from_graph)
|
||||
: block_(block)
|
||||
, remove_from_graph_(remove_from_graph)
|
||||
, remove_command_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TransitionBlock* block_;
|
||||
TransitionBlock *block_;
|
||||
|
||||
Track* track_;
|
||||
Track *track_;
|
||||
|
||||
Block* out_block_;
|
||||
Block* in_block_;
|
||||
|
||||
bool remove_from_graph_;
|
||||
UndoCommand* remove_command_;
|
||||
Block *out_block_;
|
||||
Block *in_block_;
|
||||
|
||||
bool remove_from_graph_;
|
||||
UndoCommand *remove_command_;
|
||||
};
|
||||
|
||||
class TrackReplaceBlockWithGapCommand : public UndoCommand {
|
||||
public:
|
||||
TrackReplaceBlockWithGapCommand(Track* track, Block* block, bool handle_transitions = true) :
|
||||
track_(track),
|
||||
block_(block),
|
||||
existing_gap_(nullptr),
|
||||
existing_merged_gap_(nullptr),
|
||||
our_gap_(nullptr),
|
||||
handle_transitions_(handle_transitions)
|
||||
{
|
||||
}
|
||||
TrackReplaceBlockWithGapCommand(Track *track, Block *block,
|
||||
bool handle_transitions = true)
|
||||
: track_(track)
|
||||
, block_(block)
|
||||
, existing_gap_(nullptr)
|
||||
, existing_merged_gap_(nullptr)
|
||||
, our_gap_(nullptr)
|
||||
, handle_transitions_(handle_transitions)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
void CreateRemoveTransitionCommandIfNecessary(bool next);
|
||||
void CreateRemoveTransitionCommandIfNecessary(bool next);
|
||||
|
||||
Track* track_;
|
||||
Block* block_;
|
||||
Track *track_;
|
||||
Block *block_;
|
||||
|
||||
GapBlock* existing_gap_;
|
||||
GapBlock* existing_merged_gap_;
|
||||
bool existing_gap_precedes_;
|
||||
GapBlock* our_gap_;
|
||||
GapBlock *existing_gap_;
|
||||
GapBlock *existing_merged_gap_;
|
||||
bool existing_gap_precedes_;
|
||||
GapBlock *our_gap_;
|
||||
|
||||
bool handle_transitions_;
|
||||
bool handle_transitions_;
|
||||
|
||||
QObject memory_manager_;
|
||||
|
||||
QVector<TransitionRemoveCommand*> transition_remove_commands_;
|
||||
QObject memory_manager_;
|
||||
|
||||
QVector<TransitionRemoveCommand *> transition_remove_commands_;
|
||||
};
|
||||
|
||||
class BlockEnableDisableCommand : public UndoCommand {
|
||||
public:
|
||||
BlockEnableDisableCommand(Block* block, bool enabled) :
|
||||
block_(block),
|
||||
old_enabled_(block_->is_enabled()),
|
||||
new_enabled_(enabled)
|
||||
{
|
||||
}
|
||||
BlockEnableDisableCommand(Block *block, bool enabled)
|
||||
: block_(block)
|
||||
, old_enabled_(block_->is_enabled())
|
||||
, new_enabled_(enabled)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
block_->set_enabled(new_enabled_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
block_->set_enabled(new_enabled_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
block_->set_enabled(old_enabled_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
block_->set_enabled(old_enabled_);
|
||||
}
|
||||
|
||||
private:
|
||||
Block* block_;
|
||||
Block *block_;
|
||||
|
||||
bool old_enabled_;
|
||||
|
||||
bool new_enabled_;
|
||||
bool old_enabled_;
|
||||
|
||||
bool new_enabled_;
|
||||
};
|
||||
|
||||
class TrackListInsertGaps : public UndoCommand {
|
||||
public:
|
||||
TrackListInsertGaps(TrackList* track_list, const rational& point, const rational& length) :
|
||||
track_list_(track_list),
|
||||
point_(point),
|
||||
length_(length),
|
||||
split_command_(nullptr)
|
||||
{
|
||||
}
|
||||
TrackListInsertGaps(TrackList *track_list, const rational &point,
|
||||
const rational &length)
|
||||
: track_list_(track_list)
|
||||
, point_(point)
|
||||
, length_(length)
|
||||
, split_command_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TrackListInsertGaps() override
|
||||
{
|
||||
delete split_command_;
|
||||
}
|
||||
virtual ~TrackListInsertGaps() override
|
||||
{
|
||||
delete split_command_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_list_->parent()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_list_->parent()->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TrackList* track_list_;
|
||||
TrackList *track_list_;
|
||||
|
||||
rational point_;
|
||||
rational point_;
|
||||
|
||||
rational length_;
|
||||
rational length_;
|
||||
|
||||
QVector<Track*> working_tracks_;
|
||||
QVector<Track *> working_tracks_;
|
||||
|
||||
QVector<Block*> gaps_to_extend_;
|
||||
QVector<Block *> gaps_to_extend_;
|
||||
|
||||
struct AddGap {
|
||||
GapBlock* gap;
|
||||
Block* before;
|
||||
Track* track;
|
||||
};
|
||||
struct AddGap {
|
||||
GapBlock *gap;
|
||||
Block *before;
|
||||
Track *track;
|
||||
};
|
||||
|
||||
QVector<AddGap> gaps_added_;
|
||||
QVector<AddGap> gaps_added_;
|
||||
|
||||
BlockSplitPreservingLinksCommand* split_command_;
|
||||
|
||||
QObject memory_manager_;
|
||||
BlockSplitPreservingLinksCommand *split_command_;
|
||||
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
class TimelineAddDefaultTransitionCommand : public UndoCommand
|
||||
{
|
||||
class TimelineAddDefaultTransitionCommand : public UndoCommand {
|
||||
public:
|
||||
TimelineAddDefaultTransitionCommand(const QVector<ClipBlock*> &clips, const rational &timebase) :
|
||||
clips_(clips),
|
||||
timebase_(timebase)
|
||||
{}
|
||||
TimelineAddDefaultTransitionCommand(const QVector<ClipBlock *> &clips,
|
||||
const rational &timebase)
|
||||
: clips_(clips)
|
||||
, timebase_(timebase)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TimelineAddDefaultTransitionCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
virtual ~TimelineAddDefaultTransitionCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return clips_.empty() ? nullptr : clips_.first()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return clips_.empty() ? nullptr : clips_.first()->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override
|
||||
{
|
||||
for (auto it=commands_.cbegin(); it!=commands_.cend(); it++) {
|
||||
(*it)->redo_now();
|
||||
}
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
for (auto it = commands_.cbegin(); it != commands_.cend(); it++) {
|
||||
(*it)->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
for (auto it=commands_.crbegin(); it!=commands_.crend(); it++) {
|
||||
(*it)->undo_now();
|
||||
}
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
for (auto it = commands_.crbegin(); it != commands_.crend(); it++) {
|
||||
(*it)->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum CreateTransitionMode {
|
||||
kIn,
|
||||
kOut,
|
||||
kOutDual
|
||||
};
|
||||
enum CreateTransitionMode { kIn, kOut, kOutDual };
|
||||
|
||||
void AddTransition(ClipBlock *c, CreateTransitionMode mode);
|
||||
void AdjustClipLength(ClipBlock *c, const rational &transition_length, bool out);
|
||||
void ValidateTransitionLength(ClipBlock *c, rational &transition_length);
|
||||
void AddTransition(ClipBlock *c, CreateTransitionMode mode);
|
||||
void AdjustClipLength(ClipBlock *c, const rational &transition_length,
|
||||
bool out);
|
||||
void ValidateTransitionLength(ClipBlock *c, rational &transition_length);
|
||||
|
||||
QVector<ClipBlock *> clips_;
|
||||
rational timebase_;
|
||||
QVector<UndoCommand *> commands_;
|
||||
|
||||
QVector<ClipBlock*> clips_;
|
||||
rational timebase_;
|
||||
QVector<UndoCommand*> commands_;
|
||||
|
||||
QHash<ClipBlock*, rational> lengths_;
|
||||
|
||||
QHash<ClipBlock *, rational> lengths_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -25,158 +25,163 @@
|
||||
#include "node/project.h"
|
||||
#include "timelineundocommon.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
//
|
||||
// BlockTrimCommand
|
||||
//
|
||||
void BlockTrimCommand::redo()
|
||||
{
|
||||
if (doing_nothing_) {
|
||||
return;
|
||||
}
|
||||
if (doing_nothing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine how much time to invalidate
|
||||
TimeRange invalidate_range;
|
||||
// Determine how much time to invalidate
|
||||
TimeRange invalidate_range;
|
||||
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff_);
|
||||
block_->set_length_and_media_in(new_length_);
|
||||
} else {
|
||||
invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff_);
|
||||
block_->set_length_and_media_out(new_length_);
|
||||
}
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff_);
|
||||
block_->set_length_and_media_in(new_length_);
|
||||
} else {
|
||||
invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff_);
|
||||
block_->set_length_and_media_out(new_length_);
|
||||
}
|
||||
|
||||
if (needs_adjacent_) {
|
||||
if (we_created_adjacent_) {
|
||||
// Add adjacent and insert it
|
||||
adjacent_->setParent(track_->parent());
|
||||
if (needs_adjacent_) {
|
||||
if (we_created_adjacent_) {
|
||||
// Add adjacent and insert it
|
||||
adjacent_->setParent(track_->parent());
|
||||
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
track_->InsertBlockBefore(adjacent_, block_);
|
||||
} else {
|
||||
track_->InsertBlockAfter(adjacent_, block_);
|
||||
}
|
||||
} else if (we_removed_adjacent_) {
|
||||
track_->RippleRemoveBlock(adjacent_);
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
track_->InsertBlockBefore(adjacent_, block_);
|
||||
} else {
|
||||
track_->InsertBlockAfter(adjacent_, block_);
|
||||
}
|
||||
} else if (we_removed_adjacent_) {
|
||||
track_->RippleRemoveBlock(adjacent_);
|
||||
|
||||
// It no longer inputs/outputs anything, remove it
|
||||
if (remove_block_from_graph_ && NodeCanBeRemoved(adjacent_)) {
|
||||
if (!deleted_adjacent_command_) {
|
||||
deleted_adjacent_command_ = CreateAndRunRemoveCommand(adjacent_);
|
||||
} else {
|
||||
deleted_adjacent_command_->redo_now();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rational adjacent_length = adjacent_->length() + trim_diff_;
|
||||
// It no longer inputs/outputs anything, remove it
|
||||
if (remove_block_from_graph_ && NodeCanBeRemoved(adjacent_)) {
|
||||
if (!deleted_adjacent_command_) {
|
||||
deleted_adjacent_command_ =
|
||||
CreateAndRunRemoveCommand(adjacent_);
|
||||
} else {
|
||||
deleted_adjacent_command_->redo_now();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rational adjacent_length = adjacent_->length() + trim_diff_;
|
||||
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
adjacent_->set_length_and_media_out(adjacent_length);
|
||||
} else {
|
||||
adjacent_->set_length_and_media_in(adjacent_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
adjacent_->set_length_and_media_out(adjacent_length);
|
||||
} else {
|
||||
adjacent_->set_length_and_media_in(adjacent_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_cast<TransitionBlock*>(block_)) {
|
||||
// Whole transition needs to be invalidated
|
||||
invalidate_range = block_->range();
|
||||
}
|
||||
if (dynamic_cast<TransitionBlock *>(block_)) {
|
||||
// Whole transition needs to be invalidated
|
||||
invalidate_range = block_->range();
|
||||
}
|
||||
}
|
||||
|
||||
void BlockTrimCommand::undo()
|
||||
{
|
||||
if (doing_nothing_) {
|
||||
return;
|
||||
}
|
||||
if (doing_nothing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer
|
||||
if (needs_adjacent_) {
|
||||
if (we_created_adjacent_) {
|
||||
// Adjacent is ours, just delete it
|
||||
track_->RippleRemoveBlock(adjacent_);
|
||||
adjacent_->setParent(&memory_manager_);
|
||||
} else {
|
||||
if (we_removed_adjacent_) {
|
||||
if (deleted_adjacent_command_) {
|
||||
// We deleted adjacent, restore it now
|
||||
deleted_adjacent_command_->undo_now();
|
||||
}
|
||||
// Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer
|
||||
if (needs_adjacent_) {
|
||||
if (we_created_adjacent_) {
|
||||
// Adjacent is ours, just delete it
|
||||
track_->RippleRemoveBlock(adjacent_);
|
||||
adjacent_->setParent(&memory_manager_);
|
||||
} else {
|
||||
if (we_removed_adjacent_) {
|
||||
if (deleted_adjacent_command_) {
|
||||
// We deleted adjacent, restore it now
|
||||
deleted_adjacent_command_->undo_now();
|
||||
}
|
||||
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
track_->InsertBlockBefore(adjacent_, block_);
|
||||
} else {
|
||||
track_->InsertBlockAfter(adjacent_, block_);
|
||||
}
|
||||
} else {
|
||||
rational adjacent_length = adjacent_->length() - trim_diff_;
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
track_->InsertBlockBefore(adjacent_, block_);
|
||||
} else {
|
||||
track_->InsertBlockAfter(adjacent_, block_);
|
||||
}
|
||||
} else {
|
||||
rational adjacent_length = adjacent_->length() - trim_diff_;
|
||||
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
adjacent_->set_length_and_media_out(adjacent_length);
|
||||
} else {
|
||||
adjacent_->set_length_and_media_in(adjacent_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
adjacent_->set_length_and_media_out(adjacent_length);
|
||||
} else {
|
||||
adjacent_->set_length_and_media_in(adjacent_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimeRange invalidate_range;
|
||||
TimeRange invalidate_range;
|
||||
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
block_->set_length_and_media_in(old_length_);
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
block_->set_length_and_media_in(old_length_);
|
||||
|
||||
invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff_);
|
||||
} else {
|
||||
block_->set_length_and_media_out(old_length_);
|
||||
invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff_);
|
||||
} else {
|
||||
block_->set_length_and_media_out(old_length_);
|
||||
|
||||
invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff_);
|
||||
}
|
||||
invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff_);
|
||||
}
|
||||
|
||||
if (dynamic_cast<TransitionBlock*>(block_)) {
|
||||
// Whole transition needs to be invalidated
|
||||
invalidate_range = block_->range();
|
||||
}
|
||||
if (dynamic_cast<TransitionBlock *>(block_)) {
|
||||
// Whole transition needs to be invalidated
|
||||
invalidate_range = block_->range();
|
||||
}
|
||||
}
|
||||
|
||||
void BlockTrimCommand::prepare()
|
||||
{
|
||||
// Store old length
|
||||
old_length_ = block_->length();
|
||||
// Store old length
|
||||
old_length_ = block_->length();
|
||||
|
||||
// Determine if the length isn't changing, in which case we set a flag to do nothing
|
||||
if ((doing_nothing_ = (old_length_ == new_length_))) {
|
||||
return;
|
||||
}
|
||||
// Determine if the length isn't changing, in which case we set a flag to do nothing
|
||||
if ((doing_nothing_ = (old_length_ == new_length_))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer
|
||||
trim_diff_ = old_length_ - new_length_;
|
||||
// Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer
|
||||
trim_diff_ = old_length_ - new_length_;
|
||||
|
||||
// Retrieve our adjacent block (or nullptr if none)
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
adjacent_ = block_->previous();
|
||||
} else {
|
||||
adjacent_ = block_->next();
|
||||
}
|
||||
// Retrieve our adjacent block (or nullptr if none)
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
adjacent_ = block_->previous();
|
||||
} else {
|
||||
adjacent_ = block_->next();
|
||||
}
|
||||
|
||||
// Ignore when trimming the out with no adjacent, because the user must have trimmed the end
|
||||
// of the last block in the track, so we don't need to do anything elses
|
||||
needs_adjacent_ = (mode_ == Timeline::kTrimIn || adjacent_);
|
||||
// Ignore when trimming the out with no adjacent, because the user must have trimmed the end
|
||||
// of the last block in the track, so we don't need to do anything elses
|
||||
needs_adjacent_ = (mode_ == Timeline::kTrimIn || adjacent_);
|
||||
|
||||
if (needs_adjacent_) {
|
||||
// If we're trimming shorter, we need an adjacent, so check if we have a viable one.
|
||||
we_created_adjacent_ = (trim_diff_ > 0 && (!adjacent_ || (!dynamic_cast<GapBlock*>(adjacent_) && !trim_is_a_roll_edit_)));
|
||||
if (needs_adjacent_) {
|
||||
// If we're trimming shorter, we need an adjacent, so check if we have a viable one.
|
||||
we_created_adjacent_ =
|
||||
(trim_diff_ > 0 &&
|
||||
(!adjacent_ ||
|
||||
(!dynamic_cast<GapBlock *>(adjacent_) && !trim_is_a_roll_edit_)));
|
||||
|
||||
if (we_created_adjacent_) {
|
||||
// We shortened but don't have a viable adjacent to lengthen, so we create one
|
||||
adjacent_ = new GapBlock();
|
||||
adjacent_->set_length_and_media_out(trim_diff_);
|
||||
} else {
|
||||
// Determine if we're removing the adjacent
|
||||
rational adjacent_length = adjacent_->length() + trim_diff_;
|
||||
we_removed_adjacent_ = adjacent_length.isNull();
|
||||
}
|
||||
}
|
||||
if (we_created_adjacent_) {
|
||||
// We shortened but don't have a viable adjacent to lengthen, so we create one
|
||||
adjacent_ = new GapBlock();
|
||||
adjacent_->set_length_and_media_out(trim_diff_);
|
||||
} else {
|
||||
// Determine if we're removing the adjacent
|
||||
rational adjacent_length = adjacent_->length() + trim_diff_;
|
||||
we_removed_adjacent_ = adjacent_length.isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -184,124 +189,130 @@ void BlockTrimCommand::prepare()
|
||||
//
|
||||
void TrackSlideCommand::redo()
|
||||
{
|
||||
// Make sure all movement blocks' old positions are invalidated
|
||||
TimeRange invalidate_range(blocks_.first()->in(), blocks_.last()->out());
|
||||
// Make sure all movement blocks' old positions are invalidated
|
||||
TimeRange invalidate_range(blocks_.first()->in(), blocks_.last()->out());
|
||||
|
||||
// We will always have an in adjacent if there was a valid slide
|
||||
if (we_created_in_adjacent_) {
|
||||
// We created in adjacent, so all we have to do is insert it
|
||||
in_adjacent_->setParent(track_->parent());
|
||||
track_->InsertBlockBefore(in_adjacent_, blocks_.first());
|
||||
} else if (-movement_ == in_adjacent_->length()) {
|
||||
// Movement will remove in adjacent
|
||||
track_->RippleRemoveBlock(in_adjacent_);
|
||||
// We will always have an in adjacent if there was a valid slide
|
||||
if (we_created_in_adjacent_) {
|
||||
// We created in adjacent, so all we have to do is insert it
|
||||
in_adjacent_->setParent(track_->parent());
|
||||
track_->InsertBlockBefore(in_adjacent_, blocks_.first());
|
||||
} else if (-movement_ == in_adjacent_->length()) {
|
||||
// Movement will remove in adjacent
|
||||
track_->RippleRemoveBlock(in_adjacent_);
|
||||
|
||||
if (NodeCanBeRemoved(in_adjacent_)) {
|
||||
if (!in_adjacent_remove_command_) {
|
||||
in_adjacent_remove_command_ = CreateRemoveCommand(in_adjacent_);
|
||||
}
|
||||
if (NodeCanBeRemoved(in_adjacent_)) {
|
||||
if (!in_adjacent_remove_command_) {
|
||||
in_adjacent_remove_command_ = CreateRemoveCommand(in_adjacent_);
|
||||
}
|
||||
|
||||
in_adjacent_remove_command_->redo_now();
|
||||
}
|
||||
in_adjacent_remove_command_->redo_now();
|
||||
}
|
||||
|
||||
we_removed_in_adjacent_ = true;
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
in_adjacent_->set_length_and_media_out(in_adjacent_->length() + movement_);
|
||||
}
|
||||
we_removed_in_adjacent_ = true;
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
in_adjacent_->set_length_and_media_out(in_adjacent_->length() +
|
||||
movement_);
|
||||
}
|
||||
|
||||
// We may not have an out adjacent if the slide was at the end of the track
|
||||
if (out_adjacent_) {
|
||||
if (we_created_out_adjacent_) {
|
||||
// We created out adjacent, so we just have to insert it
|
||||
out_adjacent_->setParent(track_->parent());
|
||||
track_->InsertBlockAfter(out_adjacent_, blocks_.last());
|
||||
} else if (movement_ == out_adjacent_->length()) {
|
||||
// Movement will remove out adjacent
|
||||
track_->RippleRemoveBlock(out_adjacent_);
|
||||
// We may not have an out adjacent if the slide was at the end of the track
|
||||
if (out_adjacent_) {
|
||||
if (we_created_out_adjacent_) {
|
||||
// We created out adjacent, so we just have to insert it
|
||||
out_adjacent_->setParent(track_->parent());
|
||||
track_->InsertBlockAfter(out_adjacent_, blocks_.last());
|
||||
} else if (movement_ == out_adjacent_->length()) {
|
||||
// Movement will remove out adjacent
|
||||
track_->RippleRemoveBlock(out_adjacent_);
|
||||
|
||||
if (NodeCanBeRemoved(out_adjacent_)) {
|
||||
if (!out_adjacent_remove_command_) {
|
||||
out_adjacent_remove_command_ = CreateRemoveCommand(out_adjacent_);
|
||||
}
|
||||
if (NodeCanBeRemoved(out_adjacent_)) {
|
||||
if (!out_adjacent_remove_command_) {
|
||||
out_adjacent_remove_command_ =
|
||||
CreateRemoveCommand(out_adjacent_);
|
||||
}
|
||||
|
||||
out_adjacent_remove_command_->redo_now();
|
||||
}
|
||||
out_adjacent_remove_command_->redo_now();
|
||||
}
|
||||
|
||||
we_removed_out_adjacent_ = true;
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
out_adjacent_->set_length_and_media_in(out_adjacent_->length() - movement_);
|
||||
}
|
||||
}
|
||||
we_removed_out_adjacent_ = true;
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
out_adjacent_->set_length_and_media_in(out_adjacent_->length() -
|
||||
movement_);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all movement blocks' new positions are invalidated
|
||||
invalidate_range.set_range(qMin(invalidate_range.in(), blocks_.first()->in()),
|
||||
qMax(invalidate_range.out(), blocks_.last()->out()));
|
||||
// Make sure all movement blocks' new positions are invalidated
|
||||
invalidate_range.set_range(
|
||||
qMin(invalidate_range.in(), blocks_.first()->in()),
|
||||
qMax(invalidate_range.out(), blocks_.last()->out()));
|
||||
}
|
||||
|
||||
|
||||
void TrackSlideCommand::undo()
|
||||
{
|
||||
// Make sure all movement blocks' old positions are invalidated
|
||||
TimeRange invalidate_range(blocks_.first()->in(), blocks_.last()->out());
|
||||
// Make sure all movement blocks' old positions are invalidated
|
||||
TimeRange invalidate_range(blocks_.first()->in(), blocks_.last()->out());
|
||||
|
||||
if (we_created_in_adjacent_) {
|
||||
// We created this, so we can remove it now
|
||||
track_->RippleRemoveBlock(in_adjacent_);
|
||||
in_adjacent_->setParent(&memory_manager_);
|
||||
} else if (we_removed_in_adjacent_) {
|
||||
if (in_adjacent_remove_command_) {
|
||||
// We removed this, so we can restore it now
|
||||
in_adjacent_remove_command_->undo_now();
|
||||
}
|
||||
if (we_created_in_adjacent_) {
|
||||
// We created this, so we can remove it now
|
||||
track_->RippleRemoveBlock(in_adjacent_);
|
||||
in_adjacent_->setParent(&memory_manager_);
|
||||
} else if (we_removed_in_adjacent_) {
|
||||
if (in_adjacent_remove_command_) {
|
||||
// We removed this, so we can restore it now
|
||||
in_adjacent_remove_command_->undo_now();
|
||||
}
|
||||
|
||||
track_->InsertBlockBefore(in_adjacent_, blocks_.first());
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
in_adjacent_->set_length_and_media_out(in_adjacent_->length() - movement_);
|
||||
}
|
||||
track_->InsertBlockBefore(in_adjacent_, blocks_.first());
|
||||
} else {
|
||||
// Simply resize adjacent
|
||||
in_adjacent_->set_length_and_media_out(in_adjacent_->length() -
|
||||
movement_);
|
||||
}
|
||||
|
||||
if (out_adjacent_) {
|
||||
if (we_created_out_adjacent_) {
|
||||
// We created this, so we can remove it now
|
||||
track_->RippleRemoveBlock(out_adjacent_);
|
||||
out_adjacent_->setParent(&memory_manager_);
|
||||
} else if (we_removed_out_adjacent_) {
|
||||
if (out_adjacent_remove_command_) {
|
||||
out_adjacent_remove_command_->undo_now();
|
||||
}
|
||||
if (out_adjacent_) {
|
||||
if (we_created_out_adjacent_) {
|
||||
// We created this, so we can remove it now
|
||||
track_->RippleRemoveBlock(out_adjacent_);
|
||||
out_adjacent_->setParent(&memory_manager_);
|
||||
} else if (we_removed_out_adjacent_) {
|
||||
if (out_adjacent_remove_command_) {
|
||||
out_adjacent_remove_command_->undo_now();
|
||||
}
|
||||
|
||||
track_->InsertBlockAfter(out_adjacent_, blocks_.last());
|
||||
} else {
|
||||
out_adjacent_->set_length_and_media_in(out_adjacent_->length() + movement_);
|
||||
}
|
||||
}
|
||||
track_->InsertBlockAfter(out_adjacent_, blocks_.last());
|
||||
} else {
|
||||
out_adjacent_->set_length_and_media_in(out_adjacent_->length() +
|
||||
movement_);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all movement blocks' new positions are invalidated
|
||||
invalidate_range.set_range(qMin(invalidate_range.in(), blocks_.first()->in()),
|
||||
qMax(invalidate_range.out(), blocks_.last()->out()));
|
||||
// Make sure all movement blocks' new positions are invalidated
|
||||
invalidate_range.set_range(
|
||||
qMin(invalidate_range.in(), blocks_.first()->in()),
|
||||
qMax(invalidate_range.out(), blocks_.last()->out()));
|
||||
}
|
||||
|
||||
void TrackSlideCommand::prepare()
|
||||
{
|
||||
if (!in_adjacent_) {
|
||||
in_adjacent_ = new GapBlock();
|
||||
in_adjacent_->set_length_and_media_out(movement_);
|
||||
in_adjacent_->setParent(&memory_manager_);
|
||||
we_created_in_adjacent_ = true;
|
||||
} else {
|
||||
we_created_in_adjacent_ = false;
|
||||
}
|
||||
if (!in_adjacent_) {
|
||||
in_adjacent_ = new GapBlock();
|
||||
in_adjacent_->set_length_and_media_out(movement_);
|
||||
in_adjacent_->setParent(&memory_manager_);
|
||||
we_created_in_adjacent_ = true;
|
||||
} else {
|
||||
we_created_in_adjacent_ = false;
|
||||
}
|
||||
|
||||
if (!out_adjacent_ && blocks_.last()->next()) {
|
||||
out_adjacent_ = new GapBlock();
|
||||
out_adjacent_->set_length_and_media_out(-movement_);
|
||||
out_adjacent_->setParent(&memory_manager_);
|
||||
we_created_out_adjacent_ = true;
|
||||
} else {
|
||||
we_created_out_adjacent_ = false;
|
||||
}
|
||||
if (!out_adjacent_ && blocks_.last()->next()) {
|
||||
out_adjacent_ = new GapBlock();
|
||||
out_adjacent_->set_length_and_media_out(-movement_);
|
||||
out_adjacent_->setParent(&memory_manager_);
|
||||
we_created_out_adjacent_ = true;
|
||||
} else {
|
||||
we_created_out_adjacent_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -309,78 +320,81 @@ void TrackSlideCommand::prepare()
|
||||
//
|
||||
TrackPlaceBlockCommand::~TrackPlaceBlockCommand()
|
||||
{
|
||||
delete ripple_remove_command_;
|
||||
qDeleteAll(add_track_commands_);
|
||||
delete ripple_remove_command_;
|
||||
qDeleteAll(add_track_commands_);
|
||||
}
|
||||
|
||||
void TrackPlaceBlockCommand::redo()
|
||||
{
|
||||
// Determine if we need to add tracks
|
||||
if (track_index_ >= timeline_->GetTracks().size()) {
|
||||
if (add_track_commands_.isEmpty()) {
|
||||
// First redo, create tracks now
|
||||
add_track_commands_.resize(track_index_ - timeline_->GetTracks().size() + 1);
|
||||
// Determine if we need to add tracks
|
||||
if (track_index_ >= timeline_->GetTracks().size()) {
|
||||
if (add_track_commands_.isEmpty()) {
|
||||
// First redo, create tracks now
|
||||
add_track_commands_.resize(track_index_ -
|
||||
timeline_->GetTracks().size() + 1);
|
||||
|
||||
for (int i=0; i<add_track_commands_.size(); i++) {
|
||||
add_track_commands_[i] = new TimelineAddTrackCommand(timeline_);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < add_track_commands_.size(); i++) {
|
||||
add_track_commands_[i] = new TimelineAddTrackCommand(timeline_);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<add_track_commands_.size(); i++) {
|
||||
add_track_commands_.at(i)->redo_now();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < add_track_commands_.size(); i++) {
|
||||
add_track_commands_.at(i)->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
Track* track = timeline_->GetTrackAt(track_index_);
|
||||
Track *track = timeline_->GetTrackAt(track_index_);
|
||||
|
||||
bool append = (in_ >= track->track_length());
|
||||
bool append = (in_ >= track->track_length());
|
||||
|
||||
// Check if the placement location is past the end of the timeline
|
||||
if (append) {
|
||||
if (in_ > track->track_length()) {
|
||||
// If so, insert a gap here
|
||||
if (!gap_) {
|
||||
gap_ = new GapBlock();
|
||||
gap_->set_length_and_media_out(in_ - track->track_length());
|
||||
}
|
||||
gap_->setParent(track->parent());
|
||||
track->AppendBlock(gap_);
|
||||
}
|
||||
// Check if the placement location is past the end of the timeline
|
||||
if (append) {
|
||||
if (in_ > track->track_length()) {
|
||||
// If so, insert a gap here
|
||||
if (!gap_) {
|
||||
gap_ = new GapBlock();
|
||||
gap_->set_length_and_media_out(in_ - track->track_length());
|
||||
}
|
||||
gap_->setParent(track->parent());
|
||||
track->AppendBlock(gap_);
|
||||
}
|
||||
|
||||
track->AppendBlock(insert_);
|
||||
} else {
|
||||
// Place the Block at this point
|
||||
if (!ripple_remove_command_) {
|
||||
ripple_remove_command_ = new TrackRippleRemoveAreaCommand(track, TimeRange(in_, in_ + insert_->length()));
|
||||
ripple_remove_command_->SetAllowSplittingGaps(true);
|
||||
}
|
||||
track->AppendBlock(insert_);
|
||||
} else {
|
||||
// Place the Block at this point
|
||||
if (!ripple_remove_command_) {
|
||||
ripple_remove_command_ = new TrackRippleRemoveAreaCommand(
|
||||
track, TimeRange(in_, in_ + insert_->length()));
|
||||
ripple_remove_command_->SetAllowSplittingGaps(true);
|
||||
}
|
||||
|
||||
ripple_remove_command_->redo_now();
|
||||
track->InsertBlockAfter(insert_, ripple_remove_command_->GetInsertionIndex());
|
||||
}
|
||||
ripple_remove_command_->redo_now();
|
||||
track->InsertBlockAfter(insert_,
|
||||
ripple_remove_command_->GetInsertionIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void TrackPlaceBlockCommand::undo()
|
||||
{
|
||||
Track* t = timeline_->GetTrackAt(track_index_);
|
||||
Track *t = timeline_->GetTrackAt(track_index_);
|
||||
|
||||
TimeRange insert_range(insert_->in(), insert_->out());
|
||||
TimeRange insert_range(insert_->in(), insert_->out());
|
||||
|
||||
// Firstly, remove our insert
|
||||
t->RippleRemoveBlock(insert_);
|
||||
// Firstly, remove our insert
|
||||
t->RippleRemoveBlock(insert_);
|
||||
|
||||
if (ripple_remove_command_) {
|
||||
// If we ripple removed, just undo that
|
||||
ripple_remove_command_->undo_now();
|
||||
} else if (gap_) {
|
||||
t->RippleRemoveBlock(gap_);
|
||||
gap_->setParent(&memory_manager_);
|
||||
}
|
||||
if (ripple_remove_command_) {
|
||||
// If we ripple removed, just undo that
|
||||
ripple_remove_command_->undo_now();
|
||||
} else if (gap_) {
|
||||
t->RippleRemoveBlock(gap_);
|
||||
gap_->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
// Remove tracks if we added them
|
||||
for (int i=add_track_commands_.size()-1; i>=0; i--) {
|
||||
add_track_commands_.at(i)->undo_now();
|
||||
}
|
||||
// Remove tracks if we added them
|
||||
for (int i = add_track_commands_.size() - 1; i >= 0; i--) {
|
||||
add_track_commands_.at(i)->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+112
-110
@@ -28,7 +28,8 @@
|
||||
#include "timelineundogeneral.h"
|
||||
#include "timelineundoripple.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Performs a trim in the timeline that only affects the block and the block adjacent
|
||||
@@ -42,124 +43,125 @@ namespace olive {
|
||||
*/
|
||||
class BlockTrimCommand : public UndoCommand {
|
||||
public:
|
||||
BlockTrimCommand(Track *track, Block* block, rational new_length, Timeline::MovementMode mode) :
|
||||
track_(track),
|
||||
block_(block),
|
||||
new_length_(new_length),
|
||||
mode_(mode),
|
||||
deleted_adjacent_command_(nullptr),
|
||||
trim_is_a_roll_edit_(false)
|
||||
{
|
||||
}
|
||||
BlockTrimCommand(Track *track, Block *block, rational new_length,
|
||||
Timeline::MovementMode mode)
|
||||
: track_(track)
|
||||
, block_(block)
|
||||
, new_length_(new_length)
|
||||
, mode_(mode)
|
||||
, deleted_adjacent_command_(nullptr)
|
||||
, trim_is_a_roll_edit_(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BlockTrimCommand() override
|
||||
{
|
||||
delete deleted_adjacent_command_;
|
||||
}
|
||||
virtual ~BlockTrimCommand() override
|
||||
{
|
||||
delete deleted_adjacent_command_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Set this if the trim should always affect the adjacent clip and not create a gap
|
||||
*/
|
||||
void SetTrimIsARollEdit(bool e)
|
||||
{
|
||||
trim_is_a_roll_edit_ = e;
|
||||
}
|
||||
void SetTrimIsARollEdit(bool e)
|
||||
{
|
||||
trim_is_a_roll_edit_ = e;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Set whether adjacent blocks set to zero length should be removed from the whole graph
|
||||
*
|
||||
* If an adjacent block's length is set to 0, it's automatically removed from the track. By
|
||||
* default it also gets removed from the whole graph. Set this to FALSE to disable that
|
||||
* functionality.
|
||||
*/
|
||||
void SetRemoveZeroLengthFromGraph(bool e)
|
||||
{
|
||||
remove_block_from_graph_ = e;
|
||||
}
|
||||
void SetRemoveZeroLengthFromGraph(bool e)
|
||||
{
|
||||
remove_block_from_graph_ = e;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
virtual void prepare() override;
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
bool doing_nothing_;
|
||||
rational trim_diff_;
|
||||
bool doing_nothing_;
|
||||
rational trim_diff_;
|
||||
|
||||
Track* track_;
|
||||
Block* block_;
|
||||
rational old_length_;
|
||||
rational new_length_;
|
||||
Timeline::MovementMode mode_;
|
||||
Track *track_;
|
||||
Block *block_;
|
||||
rational old_length_;
|
||||
rational new_length_;
|
||||
Timeline::MovementMode mode_;
|
||||
|
||||
Block* adjacent_;
|
||||
bool needs_adjacent_;
|
||||
bool we_created_adjacent_;
|
||||
bool we_removed_adjacent_;
|
||||
UndoCommand* deleted_adjacent_command_;
|
||||
Block *adjacent_;
|
||||
bool needs_adjacent_;
|
||||
bool we_created_adjacent_;
|
||||
bool we_removed_adjacent_;
|
||||
UndoCommand *deleted_adjacent_command_;
|
||||
|
||||
bool trim_is_a_roll_edit_;
|
||||
bool remove_block_from_graph_;
|
||||
|
||||
QObject memory_manager_;
|
||||
bool trim_is_a_roll_edit_;
|
||||
bool remove_block_from_graph_;
|
||||
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
class TrackSlideCommand : public UndoCommand {
|
||||
public:
|
||||
TrackSlideCommand(Track* track, const QList<Block*>& moving_blocks, Block* in_adjacent, Block* out_adjacent, const rational& movement) :
|
||||
track_(track),
|
||||
blocks_(moving_blocks),
|
||||
movement_(movement),
|
||||
we_removed_in_adjacent_(false),
|
||||
in_adjacent_(in_adjacent),
|
||||
in_adjacent_remove_command_(nullptr),
|
||||
we_removed_out_adjacent_(false),
|
||||
out_adjacent_(out_adjacent),
|
||||
out_adjacent_remove_command_(nullptr)
|
||||
{
|
||||
Q_ASSERT(!movement_.isNull());
|
||||
}
|
||||
TrackSlideCommand(Track *track, const QList<Block *> &moving_blocks,
|
||||
Block *in_adjacent, Block *out_adjacent,
|
||||
const rational &movement)
|
||||
: track_(track)
|
||||
, blocks_(moving_blocks)
|
||||
, movement_(movement)
|
||||
, we_removed_in_adjacent_(false)
|
||||
, in_adjacent_(in_adjacent)
|
||||
, in_adjacent_remove_command_(nullptr)
|
||||
, we_removed_out_adjacent_(false)
|
||||
, out_adjacent_(out_adjacent)
|
||||
, out_adjacent_remove_command_(nullptr)
|
||||
{
|
||||
Q_ASSERT(!movement_.isNull());
|
||||
}
|
||||
|
||||
virtual ~TrackSlideCommand() override
|
||||
{
|
||||
delete in_adjacent_remove_command_;
|
||||
delete out_adjacent_remove_command_;
|
||||
}
|
||||
virtual ~TrackSlideCommand() override
|
||||
{
|
||||
delete in_adjacent_remove_command_;
|
||||
delete out_adjacent_remove_command_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Track* track_;
|
||||
QList<Block*> blocks_;
|
||||
rational movement_;
|
||||
Track *track_;
|
||||
QList<Block *> blocks_;
|
||||
rational movement_;
|
||||
|
||||
bool we_created_in_adjacent_;
|
||||
bool we_removed_in_adjacent_;
|
||||
Block* in_adjacent_;
|
||||
UndoCommand* in_adjacent_remove_command_;
|
||||
bool we_created_out_adjacent_;
|
||||
bool we_removed_out_adjacent_;
|
||||
Block* out_adjacent_;
|
||||
UndoCommand* out_adjacent_remove_command_;
|
||||
|
||||
QObject memory_manager_;
|
||||
bool we_created_in_adjacent_;
|
||||
bool we_removed_in_adjacent_;
|
||||
Block *in_adjacent_;
|
||||
UndoCommand *in_adjacent_remove_command_;
|
||||
bool we_created_out_adjacent_;
|
||||
bool we_removed_out_adjacent_;
|
||||
Block *out_adjacent_;
|
||||
UndoCommand *out_adjacent_remove_command_;
|
||||
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -171,38 +173,38 @@ private:
|
||||
*/
|
||||
class TrackPlaceBlockCommand : public UndoCommand {
|
||||
public:
|
||||
TrackPlaceBlockCommand(TrackList *timeline, int track, Block* block, rational in) :
|
||||
timeline_(timeline),
|
||||
track_index_(track),
|
||||
in_(in),
|
||||
gap_(nullptr),
|
||||
insert_(block),
|
||||
ripple_remove_command_(nullptr)
|
||||
{
|
||||
}
|
||||
TrackPlaceBlockCommand(TrackList *timeline, int track, Block *block,
|
||||
rational in)
|
||||
: timeline_(timeline)
|
||||
, track_index_(track)
|
||||
, in_(in)
|
||||
, gap_(nullptr)
|
||||
, insert_(block)
|
||||
, ripple_remove_command_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TrackPlaceBlockCommand() override;
|
||||
virtual ~TrackPlaceBlockCommand() override;
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->parent()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->parent()->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TrackList* timeline_;
|
||||
int track_index_;
|
||||
rational in_;
|
||||
GapBlock* gap_;
|
||||
Block* insert_;
|
||||
QVector<TimelineAddTrackCommand*> add_track_commands_;
|
||||
QObject memory_manager_;
|
||||
TrackRippleRemoveAreaCommand* ripple_remove_command_;
|
||||
|
||||
TrackList *timeline_;
|
||||
int track_index_;
|
||||
rational in_;
|
||||
GapBlock *gap_;
|
||||
Block *insert_;
|
||||
QVector<TimelineAddTrackCommand *> add_track_commands_;
|
||||
QObject memory_manager_;
|
||||
TrackRippleRemoveAreaCommand *ripple_remove_command_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+371
-363
@@ -22,159 +22,165 @@
|
||||
|
||||
#include "timelineundocommon.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
//
|
||||
// TrackRippleRemoveAreaCommand
|
||||
//
|
||||
TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(Track* track, const TimeRange& range) :
|
||||
track_(track),
|
||||
range_(range),
|
||||
allow_splitting_gaps_(false),
|
||||
splice_split_command_(nullptr)
|
||||
TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(
|
||||
Track *track, const TimeRange &range)
|
||||
: track_(track)
|
||||
, range_(range)
|
||||
, allow_splitting_gaps_(false)
|
||||
, splice_split_command_(nullptr)
|
||||
{
|
||||
trim_out_.block = nullptr;
|
||||
trim_in_.block = nullptr;
|
||||
trim_out_.block = nullptr;
|
||||
trim_in_.block = nullptr;
|
||||
}
|
||||
|
||||
TrackRippleRemoveAreaCommand::~TrackRippleRemoveAreaCommand()
|
||||
{
|
||||
delete splice_split_command_;
|
||||
qDeleteAll(remove_block_commands_);
|
||||
delete splice_split_command_;
|
||||
qDeleteAll(remove_block_commands_);
|
||||
}
|
||||
|
||||
void TrackRippleRemoveAreaCommand::prepare()
|
||||
{
|
||||
// Determine precisely what will be happening to these tracks
|
||||
Block* first_block = track_->NearestBlockBeforeOrAt(range_.in());
|
||||
// Determine precisely what will be happening to these tracks
|
||||
Block *first_block = track_->NearestBlockBeforeOrAt(range_.in());
|
||||
|
||||
if (!first_block) {
|
||||
// No blocks at this time, nothing to be done on this track
|
||||
return;
|
||||
}
|
||||
if (!first_block) {
|
||||
// No blocks at this time, nothing to be done on this track
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if this first block is getting trimmed or removed
|
||||
bool first_block_is_out_trimmed = first_block->in() < range_.in();
|
||||
bool first_block_is_in_trimmed = first_block->out() > range_.out();
|
||||
// Determine if this first block is getting trimmed or removed
|
||||
bool first_block_is_out_trimmed = first_block->in() < range_.in();
|
||||
bool first_block_is_in_trimmed = first_block->out() > range_.out();
|
||||
|
||||
// Set's the block that any insert command should insert AFTER. If the first block is not
|
||||
// getting out-trimmed, that means first block is either getting removed or in-trimmed, which
|
||||
// means any insert should happen before it
|
||||
insert_previous_ = first_block_is_out_trimmed ? first_block : first_block->previous();
|
||||
// Set's the block that any insert command should insert AFTER. If the first block is not
|
||||
// getting out-trimmed, that means first block is either getting removed or in-trimmed, which
|
||||
// means any insert should happen before it
|
||||
insert_previous_ = first_block_is_out_trimmed ? first_block :
|
||||
first_block->previous();
|
||||
|
||||
// If it's getting trimmed, determine if it's actually getting spliced
|
||||
if (first_block_is_out_trimmed && first_block_is_in_trimmed) {
|
||||
if (!allow_splitting_gaps_ && dynamic_cast<GapBlock*>(first_block)) {
|
||||
// As a rule, we don't split gaps, so we just treat it as a trim of the range requested
|
||||
trim_out_ = {first_block,
|
||||
first_block->length(),
|
||||
first_block->length() - range_.length()};
|
||||
} else {
|
||||
// This block is getting spliced, so we'll handle that later
|
||||
splice_split_command_ = new BlockSplitCommand(first_block, range_.in());
|
||||
}
|
||||
} else {
|
||||
// It's just getting trimmed or removed, so we'll append that operation
|
||||
if (first_block_is_out_trimmed) {
|
||||
trim_out_ = {first_block,
|
||||
first_block->length(),
|
||||
first_block->length() - (first_block->out() - range_.in())};
|
||||
} else if (first_block_is_in_trimmed) {
|
||||
// Block is getting in trimmed
|
||||
trim_in_ = {first_block,
|
||||
first_block->length(),
|
||||
first_block->length() - (range_.out() - first_block->in())};
|
||||
} else {
|
||||
// We know for sure this block is within the range so it will be removed
|
||||
removals_.append(RemoveOperation({first_block, first_block->previous()}));
|
||||
}
|
||||
// If it's getting trimmed, determine if it's actually getting spliced
|
||||
if (first_block_is_out_trimmed && first_block_is_in_trimmed) {
|
||||
if (!allow_splitting_gaps_ && dynamic_cast<GapBlock *>(first_block)) {
|
||||
// As a rule, we don't split gaps, so we just treat it as a trim of the range requested
|
||||
trim_out_ = { first_block, first_block->length(),
|
||||
first_block->length() - range_.length() };
|
||||
} else {
|
||||
// This block is getting spliced, so we'll handle that later
|
||||
splice_split_command_ =
|
||||
new BlockSplitCommand(first_block, range_.in());
|
||||
}
|
||||
} else {
|
||||
// It's just getting trimmed or removed, so we'll append that operation
|
||||
if (first_block_is_out_trimmed) {
|
||||
trim_out_ = { first_block, first_block->length(),
|
||||
first_block->length() -
|
||||
(first_block->out() - range_.in()) };
|
||||
} else if (first_block_is_in_trimmed) {
|
||||
// Block is getting in trimmed
|
||||
trim_in_ = { first_block, first_block->length(),
|
||||
first_block->length() -
|
||||
(range_.out() - first_block->in()) };
|
||||
} else {
|
||||
// We know for sure this block is within the range so it will be removed
|
||||
removals_.append(
|
||||
RemoveOperation({ first_block, first_block->previous() }));
|
||||
}
|
||||
|
||||
// If the first block is getting in trimmed, we're already at the end of our range
|
||||
if (!first_block_is_in_trimmed) {
|
||||
// Loop through the rest of the blocks and determine what to do with those
|
||||
for (Block* next=first_block->next(); next; next=next->next()) {
|
||||
bool trimming = (next->out() > range_.out());
|
||||
// If the first block is getting in trimmed, we're already at the end of our range
|
||||
if (!first_block_is_in_trimmed) {
|
||||
// Loop through the rest of the blocks and determine what to do with those
|
||||
for (Block *next = first_block->next(); next; next = next->next()) {
|
||||
bool trimming = (next->out() > range_.out());
|
||||
|
||||
if (trimming) {
|
||||
trim_in_ = {next,
|
||||
next->length(),
|
||||
next->length() - (range_.out() - next->in())};
|
||||
break;
|
||||
} else {
|
||||
removals_.append(RemoveOperation({next, next->previous()}));
|
||||
if (trimming) {
|
||||
trim_in_ = { next, next->length(),
|
||||
next->length() - (range_.out() - next->in()) };
|
||||
break;
|
||||
} else {
|
||||
removals_.append(
|
||||
RemoveOperation({ next, next->previous() }));
|
||||
|
||||
if (next->out() == range_.out()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next->out() == range_.out()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackRippleRemoveAreaCommand::redo()
|
||||
{
|
||||
if (splice_split_command_) {
|
||||
// We're just splicing
|
||||
splice_split_command_->redo_now();
|
||||
if (splice_split_command_) {
|
||||
// We're just splicing
|
||||
splice_split_command_->redo_now();
|
||||
|
||||
// Trim the in of the split
|
||||
Block* split = splice_split_command_->new_block();
|
||||
split->set_length_and_media_in(split->length() - (range_.out() - split->in()));
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.new_length);
|
||||
}
|
||||
// Trim the in of the split
|
||||
Block *split = splice_split_command_->new_block();
|
||||
split->set_length_and_media_in(split->length() -
|
||||
(range_.out() - split->in()));
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.new_length);
|
||||
}
|
||||
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.new_length);
|
||||
}
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.new_length);
|
||||
}
|
||||
|
||||
// Perform removals
|
||||
if (!removals_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
// Ripple remove them all first
|
||||
track_->RippleRemoveBlock(op.block);
|
||||
}
|
||||
// Perform removals
|
||||
if (!removals_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
// Ripple remove them all first
|
||||
track_->RippleRemoveBlock(op.block);
|
||||
}
|
||||
|
||||
// Create undo commands for node removals where possible
|
||||
if (remove_block_commands_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
if (NodeCanBeRemoved(op.block)) {
|
||||
remove_block_commands_.append(CreateRemoveCommand(op.block));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create undo commands for node removals where possible
|
||||
if (remove_block_commands_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
if (NodeCanBeRemoved(op.block)) {
|
||||
remove_block_commands_.append(
|
||||
CreateRemoveCommand(op.block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (UndoCommand* c, remove_block_commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (UndoCommand *c, remove_block_commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackRippleRemoveAreaCommand::undo()
|
||||
{
|
||||
if (splice_split_command_) {
|
||||
splice_split_command_->undo_now();
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.old_length);
|
||||
}
|
||||
if (splice_split_command_) {
|
||||
splice_split_command_->undo_now();
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.old_length);
|
||||
}
|
||||
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.old_length);
|
||||
}
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.old_length);
|
||||
}
|
||||
|
||||
// Un-remove any blocks
|
||||
for (int i=remove_block_commands_.size()-1; i>=0; i--) {
|
||||
remove_block_commands_.at(i)->undo_now();
|
||||
}
|
||||
// Un-remove any blocks
|
||||
for (int i = remove_block_commands_.size() - 1; i >= 0; i--) {
|
||||
remove_block_commands_.at(i)->undo_now();
|
||||
}
|
||||
|
||||
foreach (auto op, removals_) {
|
||||
track_->InsertBlockAfter(op.block, op.before);
|
||||
}
|
||||
}
|
||||
foreach (auto op, removals_) {
|
||||
track_->InsertBlockAfter(op.block, op.before);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -182,199 +188,197 @@ void TrackRippleRemoveAreaCommand::undo()
|
||||
//
|
||||
void TrackListRippleRemoveAreaCommand::prepare()
|
||||
{
|
||||
foreach (Track* track, list_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
foreach (Track *track, list_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TrackRippleRemoveAreaCommand* c = new TrackRippleRemoveAreaCommand(track, range_);
|
||||
commands_.append(c);
|
||||
working_tracks_.append(track);
|
||||
}
|
||||
TrackRippleRemoveAreaCommand *c =
|
||||
new TrackRippleRemoveAreaCommand(track, range_);
|
||||
commands_.append(c);
|
||||
working_tracks_.append(track);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackListRippleRemoveAreaCommand::redo()
|
||||
{
|
||||
foreach (TrackRippleRemoveAreaCommand* c, commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
foreach (TrackRippleRemoveAreaCommand *c, commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackListRippleRemoveAreaCommand::undo()
|
||||
{
|
||||
foreach (TrackRippleRemoveAreaCommand* c, commands_) {
|
||||
c->undo_now();
|
||||
}
|
||||
foreach (TrackRippleRemoveAreaCommand *c, commands_) {
|
||||
c->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TimelineRippleRemoveAreaCommand
|
||||
//
|
||||
TimelineRippleRemoveAreaCommand::TimelineRippleRemoveAreaCommand(Sequence* timeline, rational in, rational out) :
|
||||
timeline_(timeline)
|
||||
TimelineRippleRemoveAreaCommand::TimelineRippleRemoveAreaCommand(
|
||||
Sequence *timeline, rational in, rational out)
|
||||
: timeline_(timeline)
|
||||
{
|
||||
for (int i=0; i<Track::kCount; i++) {
|
||||
add_child(new TrackListRippleRemoveAreaCommand(timeline->track_list(static_cast<Track::Type>(i)),
|
||||
in,
|
||||
out));
|
||||
}
|
||||
for (int i = 0; i < Track::kCount; i++) {
|
||||
add_child(new TrackListRippleRemoveAreaCommand(
|
||||
timeline->track_list(static_cast<Track::Type>(i)), in, out));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TrackListRippleToolCommand
|
||||
//
|
||||
TrackListRippleToolCommand::TrackListRippleToolCommand(TrackList* track_list,
|
||||
const QHash<Track*, RippleInfo>& info,
|
||||
const rational& ripple_movement,
|
||||
const Timeline::MovementMode& movement_mode) :
|
||||
track_list_(track_list),
|
||||
info_(info),
|
||||
ripple_movement_(ripple_movement),
|
||||
movement_mode_(movement_mode)
|
||||
TrackListRippleToolCommand::TrackListRippleToolCommand(
|
||||
TrackList *track_list, const QHash<Track *, RippleInfo> &info,
|
||||
const rational &ripple_movement,
|
||||
const Timeline::MovementMode &movement_mode)
|
||||
: track_list_(track_list)
|
||||
, info_(info)
|
||||
, ripple_movement_(ripple_movement)
|
||||
, movement_mode_(movement_mode)
|
||||
{
|
||||
}
|
||||
|
||||
void TrackListRippleToolCommand::ripple(bool redo)
|
||||
{
|
||||
if (info_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (info_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The following variables are used to determine how much of the cache to invalidate
|
||||
// The following variables are used to determine how much of the cache to invalidate
|
||||
|
||||
// If we can shift, we will shift from the latest out before the ripple to the latest out after,
|
||||
// since those sections will be unchanged by this ripple
|
||||
rational pre_latest_out = RATIONAL_MIN;
|
||||
rational post_latest_out = RATIONAL_MIN;
|
||||
// If we can shift, we will shift from the latest out before the ripple to the latest out after,
|
||||
// since those sections will be unchanged by this ripple
|
||||
rational pre_latest_out = RATIONAL_MIN;
|
||||
rational post_latest_out = RATIONAL_MIN;
|
||||
|
||||
// Make timeline changes
|
||||
for (auto it=info_.cbegin(); it!=info_.cend(); it++) {
|
||||
Track* track = it.key();
|
||||
const RippleInfo& info = it.value();
|
||||
WorkingData working_data = working_data_.value(track);
|
||||
Block* b = info.block;
|
||||
// Make timeline changes
|
||||
for (auto it = info_.cbegin(); it != info_.cend(); it++) {
|
||||
Track *track = it.key();
|
||||
const RippleInfo &info = it.value();
|
||||
WorkingData working_data = working_data_.value(track);
|
||||
Block *b = info.block;
|
||||
|
||||
// Generate block length
|
||||
rational new_block_length;
|
||||
rational operation_movement = ripple_movement_;
|
||||
// Generate block length
|
||||
rational new_block_length;
|
||||
rational operation_movement = ripple_movement_;
|
||||
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
|
||||
if (!redo) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
if (!redo) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
|
||||
if (b) {
|
||||
new_block_length = b->length() + operation_movement;
|
||||
}
|
||||
if (b) {
|
||||
new_block_length = b->length() + operation_movement;
|
||||
}
|
||||
|
||||
rational pre_shift;
|
||||
rational post_shift;
|
||||
rational pre_shift;
|
||||
rational post_shift;
|
||||
|
||||
if (info.append_gap) {
|
||||
if (info.append_gap) {
|
||||
// Rather than rippling the referenced block, we'll insert a gap and ripple with that
|
||||
GapBlock *gap = working_data.created_gap;
|
||||
|
||||
// Rather than rippling the referenced block, we'll insert a gap and ripple with that
|
||||
GapBlock* gap = working_data.created_gap;
|
||||
if (redo) {
|
||||
if (!gap) {
|
||||
gap = new GapBlock();
|
||||
gap->set_length_and_media_out(qAbs(ripple_movement_));
|
||||
working_data.created_gap = gap;
|
||||
}
|
||||
|
||||
if (redo) {
|
||||
if (!gap) {
|
||||
gap = new GapBlock();
|
||||
gap->set_length_and_media_out(qAbs(ripple_movement_));
|
||||
working_data.created_gap = gap;
|
||||
}
|
||||
gap->setParent(track->parent());
|
||||
track->InsertBlockBefore(gap, b);
|
||||
|
||||
gap->setParent(track->parent());
|
||||
track->InsertBlockBefore(gap, b);
|
||||
// As an insertion, we will shift from the gap's in to the gap's out
|
||||
pre_shift = gap->in();
|
||||
post_shift = gap->out();
|
||||
working_data.earliest_point_of_change = gap->in();
|
||||
} else {
|
||||
// As a removal, we will shift from the gap's out to the gap's in
|
||||
pre_shift = gap->out();
|
||||
post_shift = gap->in();
|
||||
|
||||
// As an insertion, we will shift from the gap's in to the gap's out
|
||||
pre_shift = gap->in();
|
||||
post_shift = gap->out();
|
||||
working_data.earliest_point_of_change = gap->in();
|
||||
} else {
|
||||
// As a removal, we will shift from the gap's out to the gap's in
|
||||
pre_shift = gap->out();
|
||||
post_shift = gap->in();
|
||||
track->RippleRemoveBlock(gap);
|
||||
gap->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
track->RippleRemoveBlock(gap);
|
||||
gap->setParent(&memory_manager_);
|
||||
}
|
||||
} else if ((redo && new_block_length.isNull()) ||
|
||||
(!redo && !b->track())) {
|
||||
// The ripple is the length of this block. We assume that for this to happen, it must have
|
||||
// been a gap that we will now remove.
|
||||
|
||||
} else if ((redo && new_block_length.isNull()) || (!redo && !b->track())) {
|
||||
if (redo) {
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
|
||||
// The ripple is the length of this block. We assume that for this to happen, it must have
|
||||
// been a gap that we will now remove.
|
||||
// As a removal, we will be shifting from the out point to the in point
|
||||
pre_shift = b->out();
|
||||
post_shift = b->in();
|
||||
|
||||
if (redo) {
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
// Remove gap from track and from graph
|
||||
working_data.removed_gap_after = b->previous();
|
||||
track->RippleRemoveBlock(b);
|
||||
b->setParent(&memory_manager_);
|
||||
} else {
|
||||
// Restore gap to graph and track
|
||||
b->setParent(track->parent());
|
||||
track->InsertBlockAfter(b, working_data.removed_gap_after);
|
||||
|
||||
// As a removal, we will be shifting from the out point to the in point
|
||||
pre_shift = b->out();
|
||||
post_shift = b->in();
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
|
||||
// Remove gap from track and from graph
|
||||
working_data.removed_gap_after = b->previous();
|
||||
track->RippleRemoveBlock(b);
|
||||
b->setParent(&memory_manager_);
|
||||
} else {
|
||||
// Restore gap to graph and track
|
||||
b->setParent(track->parent());
|
||||
track->InsertBlockAfter(b, working_data.removed_gap_after);
|
||||
// As an insert, we will be shifting from the block's in point to its out point
|
||||
pre_shift = b->in();
|
||||
post_shift = b->out();
|
||||
}
|
||||
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
} else {
|
||||
// Store old length
|
||||
working_data.old_length = b->length();
|
||||
|
||||
// As an insert, we will be shifting from the block's in point to its out point
|
||||
pre_shift = b->in();
|
||||
post_shift = b->out();
|
||||
}
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
// The earliest point changes will occur is in point of this bloc
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
|
||||
} else {
|
||||
// Undo the trim in inversion we do above, this will still be inverted accurately for
|
||||
// undoing where appropriate
|
||||
rational inverted = -operation_movement;
|
||||
if (inverted > 0) {
|
||||
pre_shift = b->in() + inverted;
|
||||
post_shift = b->in();
|
||||
} else {
|
||||
pre_shift = b->in();
|
||||
post_shift = b->in() - inverted;
|
||||
}
|
||||
|
||||
// Store old length
|
||||
working_data.old_length = b->length();
|
||||
// Update length
|
||||
b->set_length_and_media_in(new_block_length);
|
||||
} else {
|
||||
// The earliest point changes will occur is the out point if trimming out or the in point
|
||||
// if trimming in
|
||||
working_data.earliest_point_of_change = b->out();
|
||||
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
// The earliest point changes will occur is in point of this bloc
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
// The latest out before the ripple is this block's current out point
|
||||
pre_shift = b->out();
|
||||
|
||||
// Undo the trim in inversion we do above, this will still be inverted accurately for
|
||||
// undoing where appropriate
|
||||
rational inverted = -operation_movement;
|
||||
if (inverted > 0) {
|
||||
pre_shift = b->in() + inverted;
|
||||
post_shift = b->in();
|
||||
} else {
|
||||
pre_shift = b->in();
|
||||
post_shift = b->in() - inverted;
|
||||
}
|
||||
// Update length
|
||||
b->set_length_and_media_out(new_block_length);
|
||||
|
||||
// Update length
|
||||
b->set_length_and_media_in(new_block_length);
|
||||
} else {
|
||||
// The earliest point changes will occur is the out point if trimming out or the in point
|
||||
// if trimming in
|
||||
working_data.earliest_point_of_change = b->out();
|
||||
// The latest out after the ripple is this block's out point after the length change
|
||||
post_shift = b->out();
|
||||
}
|
||||
}
|
||||
|
||||
// The latest out before the ripple is this block's current out point
|
||||
pre_shift = b->out();
|
||||
working_data_.insert(it.key(), working_data);
|
||||
|
||||
// Update length
|
||||
b->set_length_and_media_out(new_block_length);
|
||||
|
||||
// The latest out after the ripple is this block's out point after the length change
|
||||
post_shift = b->out();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
working_data_.insert(it.key(), working_data);
|
||||
|
||||
pre_latest_out = qMax(pre_latest_out, pre_shift);
|
||||
post_latest_out = qMax(post_latest_out, post_shift);
|
||||
}
|
||||
pre_latest_out = qMax(pre_latest_out, pre_shift);
|
||||
post_latest_out = qMax(post_latest_out, post_shift);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -382,140 +386,144 @@ void TrackListRippleToolCommand::ripple(bool redo)
|
||||
//
|
||||
void TimelineRippleDeleteGapsAtRegionsCommand::prepare()
|
||||
{
|
||||
int max_gaps = 0;
|
||||
QHash<Track*, QVector<RemovalRequest> > requested_gaps;
|
||||
int max_gaps = 0;
|
||||
QHash<Track *, QVector<RemovalRequest>> requested_gaps;
|
||||
|
||||
// Convert regions to gaps
|
||||
for (const QPair<Track*, TimeRange> ®ion : qAsConst(regions_)) {
|
||||
Track *track = region.first;
|
||||
const TimeRange &range = region.second;
|
||||
// Convert regions to gaps
|
||||
for (const QPair<Track *, TimeRange> ®ion : qAsConst(regions_)) {
|
||||
Track *track = region.first;
|
||||
const TimeRange &range = region.second;
|
||||
|
||||
GapBlock *gap = dynamic_cast<GapBlock*>(track->NearestBlockBeforeOrAt(range.in()));
|
||||
GapBlock *gap =
|
||||
dynamic_cast<GapBlock *>(track->NearestBlockBeforeOrAt(range.in()));
|
||||
|
||||
if (gap) {
|
||||
QVector<RemovalRequest> &gaps_on_track = requested_gaps[track];
|
||||
if (gap) {
|
||||
QVector<RemovalRequest> &gaps_on_track = requested_gaps[track];
|
||||
|
||||
RemovalRequest this_req = {gap, range};
|
||||
RemovalRequest this_req = { gap, range };
|
||||
|
||||
// Insertion sort
|
||||
bool inserted = false;
|
||||
for (int i=0; i<gaps_on_track.size(); i++) {
|
||||
if (gaps_on_track.at(i).range.in() < range.in()) {
|
||||
gaps_on_track.insert(i, this_req);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
gaps_on_track.append(this_req);
|
||||
}
|
||||
// Insertion sort
|
||||
bool inserted = false;
|
||||
for (int i = 0; i < gaps_on_track.size(); i++) {
|
||||
if (gaps_on_track.at(i).range.in() < range.in()) {
|
||||
gaps_on_track.insert(i, this_req);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
gaps_on_track.append(this_req);
|
||||
}
|
||||
|
||||
max_gaps = qMax(max_gaps, gaps_on_track.size());
|
||||
} else {
|
||||
qWarning() << "Failed to find corresponding gap to region";
|
||||
}
|
||||
}
|
||||
max_gaps = qMax(max_gaps, gaps_on_track.size());
|
||||
} else {
|
||||
qWarning() << "Failed to find corresponding gap to region";
|
||||
}
|
||||
}
|
||||
|
||||
// For each gap on each track, find a corresponding gap on every other track (which may include
|
||||
// a requested gap) to ripple in order to keep everything synchronized
|
||||
QHash<GapBlock*, rational> gap_lengths;
|
||||
for (int gap_index=0; gap_index<max_gaps; gap_index++) {
|
||||
rational earliest_point = RATIONAL_MAX;
|
||||
rational ripple_length = RATIONAL_MAX;
|
||||
rational latest_point = RATIONAL_MIN;
|
||||
// For each gap on each track, find a corresponding gap on every other track (which may include
|
||||
// a requested gap) to ripple in order to keep everything synchronized
|
||||
QHash<GapBlock *, rational> gap_lengths;
|
||||
for (int gap_index = 0; gap_index < max_gaps; gap_index++) {
|
||||
rational earliest_point = RATIONAL_MAX;
|
||||
rational ripple_length = RATIONAL_MAX;
|
||||
rational latest_point = RATIONAL_MIN;
|
||||
|
||||
foreach (const QVector<RemovalRequest> &gaps_on_track, requested_gaps) {
|
||||
if (gap_index < gaps_on_track.size()) {
|
||||
const RemovalRequest &gap = gaps_on_track.at(gap_index);
|
||||
earliest_point = qMin(earliest_point, gap.range.in());
|
||||
ripple_length = qMin(ripple_length, gap.range.length());
|
||||
latest_point = qMax(latest_point, gap.range.out());
|
||||
}
|
||||
}
|
||||
foreach (const QVector<RemovalRequest> &gaps_on_track, requested_gaps) {
|
||||
if (gap_index < gaps_on_track.size()) {
|
||||
const RemovalRequest &gap = gaps_on_track.at(gap_index);
|
||||
earliest_point = qMin(earliest_point, gap.range.in());
|
||||
ripple_length = qMin(ripple_length, gap.range.length());
|
||||
latest_point = qMax(latest_point, gap.range.out());
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which gaps will be involved in this operation
|
||||
QVector<GapBlock*> gaps;
|
||||
// Determine which gaps will be involved in this operation
|
||||
QVector<GapBlock *> gaps;
|
||||
|
||||
foreach (Track* track, timeline_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
foreach (Track *track, timeline_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QVector<RemovalRequest> &requested_gaps_on_track = requested_gaps.value(track);
|
||||
GapBlock *gap = nullptr;
|
||||
if (gap_index < requested_gaps_on_track.size()) {
|
||||
// A requested gap was at this index, use it
|
||||
gap = requested_gaps_on_track.at(gap_index).gap;
|
||||
} else {
|
||||
// No requested gap was at this index, find one
|
||||
Block *block = track->NearestBlockAfterOrAt(earliest_point);
|
||||
const QVector<RemovalRequest> &requested_gaps_on_track =
|
||||
requested_gaps.value(track);
|
||||
GapBlock *gap = nullptr;
|
||||
if (gap_index < requested_gaps_on_track.size()) {
|
||||
// A requested gap was at this index, use it
|
||||
gap = requested_gaps_on_track.at(gap_index).gap;
|
||||
} else {
|
||||
// No requested gap was at this index, find one
|
||||
Block *block = track->NearestBlockAfterOrAt(earliest_point);
|
||||
|
||||
if (block) {
|
||||
// Found a block, test if it's a gap
|
||||
gap = dynamic_cast<GapBlock*>(block);
|
||||
if (block) {
|
||||
// Found a block, test if it's a gap
|
||||
gap = dynamic_cast<GapBlock *>(block);
|
||||
|
||||
if (!gap) {
|
||||
if (block->in() == earliest_point) {
|
||||
if (block->next()) {
|
||||
gap = dynamic_cast<GapBlock*>(block->next());
|
||||
if (!gap) {
|
||||
if (block->in() == earliest_point) {
|
||||
if (block->next()) {
|
||||
gap = dynamic_cast<GapBlock *>(block->next());
|
||||
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gap = dynamic_cast<GapBlock*>(block->previous());
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gap = dynamic_cast<GapBlock *>(block->previous());
|
||||
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Assume track finishes here and track won't be affected by this operation
|
||||
}
|
||||
}
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Assume track finishes here and track won't be affected by this operation
|
||||
}
|
||||
}
|
||||
|
||||
if (gap) {
|
||||
gaps.append(gap);
|
||||
if (gap) {
|
||||
gaps.append(gap);
|
||||
|
||||
if (!gap_lengths.contains(gap)) {
|
||||
gap_lengths.insert(gap, gap->length());
|
||||
}
|
||||
if (!gap_lengths.contains(gap)) {
|
||||
gap_lengths.insert(gap, gap->length());
|
||||
}
|
||||
|
||||
ripple_length = qMin(ripple_length, gap_lengths.value(gap));
|
||||
}
|
||||
ripple_length = qMin(ripple_length, gap_lengths.value(gap));
|
||||
}
|
||||
|
||||
if (ripple_length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ripple_length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ripple_length > 0) {
|
||||
foreach (GapBlock *gap, gaps) {
|
||||
if (gap_lengths.value(gap) == ripple_length) {
|
||||
commands_.append(new TrackRippleRemoveBlockCommand(gap->track(), gap));
|
||||
} else {
|
||||
gap_lengths[gap] -= ripple_length;
|
||||
commands_.append(new BlockResizeCommand(gap, gap_lengths.value(gap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ripple_length > 0) {
|
||||
foreach (GapBlock *gap, gaps) {
|
||||
if (gap_lengths.value(gap) == ripple_length) {
|
||||
commands_.append(
|
||||
new TrackRippleRemoveBlockCommand(gap->track(), gap));
|
||||
} else {
|
||||
gap_lengths[gap] -= ripple_length;
|
||||
commands_.append(
|
||||
new BlockResizeCommand(gap, gap_lengths.value(gap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineRippleDeleteGapsAtRegionsCommand::redo()
|
||||
{
|
||||
for (auto it=commands_.cbegin(); it!=commands_.cend(); it++) {
|
||||
(*it)->redo_now();
|
||||
}
|
||||
for (auto it = commands_.cbegin(); it != commands_.cend(); it++) {
|
||||
(*it)->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineRippleDeleteGapsAtRegionsCommand::undo()
|
||||
{
|
||||
for (auto it=commands_.crbegin(); it!=commands_.crend(); it++) {
|
||||
(*it)->undo_now();
|
||||
}
|
||||
for (auto it = commands_.crbegin(); it != commands_.crend(); it++) {
|
||||
(*it)->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+139
-146
@@ -29,7 +29,8 @@
|
||||
#include "timelineundosplit.h"
|
||||
#include "timelineundotrack.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Clears the area between in and out
|
||||
@@ -38,220 +39,212 @@ namespace olive {
|
||||
* By default, nothing takes this area meaning all subsequent clips are pushed backward, however you can specify
|
||||
* a block to insert at the `in` point. No checking is done to ensure `insert` is the same length as `in` to `out`.
|
||||
*/
|
||||
class TrackRippleRemoveAreaCommand : public UndoCommand
|
||||
{
|
||||
class TrackRippleRemoveAreaCommand : public UndoCommand {
|
||||
public:
|
||||
TrackRippleRemoveAreaCommand(Track* track, const TimeRange& range);
|
||||
TrackRippleRemoveAreaCommand(Track *track, const TimeRange &range);
|
||||
|
||||
virtual ~TrackRippleRemoveAreaCommand() override;
|
||||
virtual ~TrackRippleRemoveAreaCommand() override;
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Block to insert after if you want to insert something between this ripple
|
||||
*/
|
||||
Block* GetInsertionIndex() const
|
||||
{
|
||||
return insert_previous_;
|
||||
}
|
||||
Block *GetInsertionIndex() const
|
||||
{
|
||||
return insert_previous_;
|
||||
}
|
||||
|
||||
Block* GetSplicedBlock() const
|
||||
{
|
||||
if (splice_split_command_) {
|
||||
return splice_split_command_->new_block();
|
||||
}
|
||||
Block *GetSplicedBlock() const
|
||||
{
|
||||
if (splice_split_command_) {
|
||||
return splice_split_command_->new_block();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetAllowSplittingGaps(bool e)
|
||||
{
|
||||
allow_splitting_gaps_ = e;
|
||||
}
|
||||
void SetAllowSplittingGaps(bool e)
|
||||
{
|
||||
allow_splitting_gaps_ = e;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
struct TrimOperation {
|
||||
Block* block;
|
||||
rational old_length;
|
||||
rational new_length;
|
||||
};
|
||||
struct TrimOperation {
|
||||
Block *block;
|
||||
rational old_length;
|
||||
rational new_length;
|
||||
};
|
||||
|
||||
struct RemoveOperation {
|
||||
Block* block;
|
||||
Block* before;
|
||||
};
|
||||
struct RemoveOperation {
|
||||
Block *block;
|
||||
Block *before;
|
||||
};
|
||||
|
||||
Track* track_;
|
||||
TimeRange range_;
|
||||
Track *track_;
|
||||
TimeRange range_;
|
||||
|
||||
TrimOperation trim_out_;
|
||||
QVector<RemoveOperation> removals_;
|
||||
TrimOperation trim_in_;
|
||||
Block* insert_previous_;
|
||||
bool allow_splitting_gaps_;
|
||||
|
||||
BlockSplitCommand* splice_split_command_;
|
||||
QVector<UndoCommand*> remove_block_commands_;
|
||||
TrimOperation trim_out_;
|
||||
QVector<RemoveOperation> removals_;
|
||||
TrimOperation trim_in_;
|
||||
Block *insert_previous_;
|
||||
bool allow_splitting_gaps_;
|
||||
|
||||
BlockSplitCommand *splice_split_command_;
|
||||
QVector<UndoCommand *> remove_block_commands_;
|
||||
};
|
||||
|
||||
class TrackListRippleRemoveAreaCommand : public UndoCommand
|
||||
{
|
||||
class TrackListRippleRemoveAreaCommand : public UndoCommand {
|
||||
public:
|
||||
TrackListRippleRemoveAreaCommand(TrackList* list, rational in, rational out) :
|
||||
list_(list),
|
||||
range_(in, out)
|
||||
{
|
||||
}
|
||||
TrackListRippleRemoveAreaCommand(TrackList *list, rational in, rational out)
|
||||
: list_(list)
|
||||
, range_(in, out)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TrackListRippleRemoveAreaCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
virtual ~TrackListRippleRemoveAreaCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return list_->parent()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return list_->parent()->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
TrackList* list_;
|
||||
TrackList *list_;
|
||||
|
||||
QList<Track*> working_tracks_;
|
||||
QList<Track *> working_tracks_;
|
||||
|
||||
TimeRange range_;
|
||||
|
||||
QVector<TrackRippleRemoveAreaCommand*> commands_;
|
||||
TimeRange range_;
|
||||
|
||||
QVector<TrackRippleRemoveAreaCommand *> commands_;
|
||||
};
|
||||
|
||||
class TimelineRippleRemoveAreaCommand : public MultiUndoCommand
|
||||
{
|
||||
class TimelineRippleRemoveAreaCommand : public MultiUndoCommand {
|
||||
public:
|
||||
TimelineRippleRemoveAreaCommand(Sequence* timeline, rational in, rational out);
|
||||
TimelineRippleRemoveAreaCommand(Sequence *timeline, rational in,
|
||||
rational out);
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->project();
|
||||
}
|
||||
|
||||
private:
|
||||
Sequence* timeline_;
|
||||
|
||||
Sequence *timeline_;
|
||||
};
|
||||
|
||||
class TrackListRippleToolCommand : public UndoCommand
|
||||
{
|
||||
class TrackListRippleToolCommand : public UndoCommand {
|
||||
public:
|
||||
struct RippleInfo {
|
||||
Block* block;
|
||||
bool append_gap;
|
||||
};
|
||||
struct RippleInfo {
|
||||
Block *block;
|
||||
bool append_gap;
|
||||
};
|
||||
|
||||
TrackListRippleToolCommand(TrackList* track_list,
|
||||
const QHash<Track*, RippleInfo>& info,
|
||||
const rational& ripple_movement,
|
||||
const Timeline::MovementMode& movement_mode);
|
||||
TrackListRippleToolCommand(TrackList *track_list,
|
||||
const QHash<Track *, RippleInfo> &info,
|
||||
const rational &ripple_movement,
|
||||
const Timeline::MovementMode &movement_mode);
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_list_->parent()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_list_->parent()->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
ripple(true);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
ripple(true);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
ripple(false);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
ripple(false);
|
||||
}
|
||||
|
||||
private:
|
||||
void ripple(bool redo);
|
||||
void ripple(bool redo);
|
||||
|
||||
TrackList* track_list_;
|
||||
TrackList *track_list_;
|
||||
|
||||
QHash<Track*, RippleInfo> info_;
|
||||
rational ripple_movement_;
|
||||
Timeline::MovementMode movement_mode_;
|
||||
QHash<Track *, RippleInfo> info_;
|
||||
rational ripple_movement_;
|
||||
Timeline::MovementMode movement_mode_;
|
||||
|
||||
struct WorkingData {
|
||||
GapBlock* created_gap = nullptr;
|
||||
Block* removed_gap_after;
|
||||
rational old_length;
|
||||
rational earliest_point_of_change;
|
||||
};
|
||||
struct WorkingData {
|
||||
GapBlock *created_gap = nullptr;
|
||||
Block *removed_gap_after;
|
||||
rational old_length;
|
||||
rational earliest_point_of_change;
|
||||
};
|
||||
|
||||
QHash<Track*, WorkingData> working_data_;
|
||||
|
||||
QObject memory_manager_;
|
||||
QHash<Track *, WorkingData> working_data_;
|
||||
|
||||
QObject memory_manager_;
|
||||
};
|
||||
|
||||
class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand
|
||||
{
|
||||
class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand {
|
||||
public:
|
||||
using RangeList = QVector<QPair<Track*, TimeRange> >;
|
||||
using RangeList = QVector<QPair<Track *, TimeRange>>;
|
||||
|
||||
TimelineRippleDeleteGapsAtRegionsCommand(Sequence* vo, const RangeList& regions) :
|
||||
timeline_(vo),
|
||||
regions_(regions)
|
||||
{
|
||||
}
|
||||
TimelineRippleDeleteGapsAtRegionsCommand(Sequence *vo,
|
||||
const RangeList ®ions)
|
||||
: timeline_(vo)
|
||||
, regions_(regions)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TimelineRippleDeleteGapsAtRegionsCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
virtual ~TimelineRippleDeleteGapsAtRegionsCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return timeline_->project();
|
||||
}
|
||||
|
||||
bool HasCommands() const
|
||||
{
|
||||
return !commands_.isEmpty();
|
||||
}
|
||||
bool HasCommands() const
|
||||
{
|
||||
return !commands_.isEmpty();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Sequence* timeline_;
|
||||
RangeList regions_;
|
||||
Sequence *timeline_;
|
||||
RangeList regions_;
|
||||
|
||||
QVector<UndoCommand*> commands_;
|
||||
|
||||
struct RemovalRequest {
|
||||
GapBlock *gap;
|
||||
TimeRange range;
|
||||
};
|
||||
QVector<UndoCommand *> commands_;
|
||||
|
||||
struct RemovalRequest {
|
||||
GapBlock *gap;
|
||||
TimeRange range;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -24,143 +24,151 @@
|
||||
#include "node/block/transition/transition.h"
|
||||
#include "node/nodeundo.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
//
|
||||
// BlockSplitCommand
|
||||
//
|
||||
void BlockSplitCommand::prepare()
|
||||
{
|
||||
reconnect_tree_command_ = new MultiUndoCommand();
|
||||
new_block_ = static_cast<Block*>(Node::CopyNodeInGraph(block_, reconnect_tree_command_));
|
||||
reconnect_tree_command_ = new MultiUndoCommand();
|
||||
new_block_ = static_cast<Block *>(
|
||||
Node::CopyNodeInGraph(block_, reconnect_tree_command_));
|
||||
}
|
||||
|
||||
void BlockSplitCommand::redo()
|
||||
{
|
||||
old_length_ = block_->length();
|
||||
old_length_ = block_->length();
|
||||
|
||||
Q_ASSERT(point_ > block_->in() && point_ < block_->out());
|
||||
Q_ASSERT(point_ > block_->in() && point_ < block_->out());
|
||||
|
||||
reconnect_tree_command_->redo_now();
|
||||
reconnect_tree_command_->redo_now();
|
||||
|
||||
// Determine our new lengths
|
||||
rational new_length = point_ - block_->in();
|
||||
rational new_part_length = block_->out() - point_;
|
||||
// Determine our new lengths
|
||||
rational new_length = point_ - block_->in();
|
||||
rational new_part_length = block_->out() - point_;
|
||||
|
||||
// Begin an operation
|
||||
Track* track = block_->track();
|
||||
// Begin an operation
|
||||
Track *track = block_->track();
|
||||
|
||||
// Set lengths
|
||||
block_->set_length_and_media_out(new_length);
|
||||
new_block()->set_length_and_media_in(new_part_length);
|
||||
// Set lengths
|
||||
block_->set_length_and_media_out(new_length);
|
||||
new_block()->set_length_and_media_in(new_part_length);
|
||||
|
||||
// Insert new block
|
||||
track->InsertBlockAfter(new_block(), block_);
|
||||
// Insert new block
|
||||
track->InsertBlockAfter(new_block(), block_);
|
||||
|
||||
if (ClipBlock *new_clip = dynamic_cast<ClipBlock*>(new_block_)) {
|
||||
ClipBlock *old_clip = static_cast<ClipBlock*>(block_);
|
||||
new_clip->AddCachePassthroughFrom(old_clip);
|
||||
}
|
||||
if (ClipBlock *new_clip = dynamic_cast<ClipBlock *>(new_block_)) {
|
||||
ClipBlock *old_clip = static_cast<ClipBlock *>(block_);
|
||||
new_clip->AddCachePassthroughFrom(old_clip);
|
||||
}
|
||||
|
||||
// If the block had an out transition, we move it to the new block
|
||||
moved_transition_ = NodeInput();
|
||||
// If the block had an out transition, we move it to the new block
|
||||
moved_transition_ = NodeInput();
|
||||
|
||||
TransitionBlock* potential_transition = dynamic_cast<TransitionBlock*>(new_block()->next());
|
||||
if (potential_transition) {
|
||||
for (const Node::OutputConnection& output : block_->output_connections()) {
|
||||
if (output.second.node() == potential_transition) {
|
||||
moved_transition_ = NodeInput(potential_transition, TransitionBlock::kOutBlockInput);
|
||||
Node::DisconnectEdge(block_, moved_transition_);
|
||||
Node::ConnectEdge(new_block(), moved_transition_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TransitionBlock *potential_transition =
|
||||
dynamic_cast<TransitionBlock *>(new_block()->next());
|
||||
if (potential_transition) {
|
||||
for (const Node::OutputConnection &output :
|
||||
block_->output_connections()) {
|
||||
if (output.second.node() == potential_transition) {
|
||||
moved_transition_ = NodeInput(potential_transition,
|
||||
TransitionBlock::kOutBlockInput);
|
||||
Node::DisconnectEdge(block_, moved_transition_);
|
||||
Node::ConnectEdge(new_block(), moved_transition_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlockSplitCommand::undo()
|
||||
{
|
||||
Track* track = block_->track();
|
||||
Track *track = block_->track();
|
||||
|
||||
if (moved_transition_.IsValid()) {
|
||||
Node::DisconnectEdge(new_block(), moved_transition_);
|
||||
Node::ConnectEdge(block_, moved_transition_);
|
||||
}
|
||||
if (moved_transition_.IsValid()) {
|
||||
Node::DisconnectEdge(new_block(), moved_transition_);
|
||||
Node::ConnectEdge(block_, moved_transition_);
|
||||
}
|
||||
|
||||
block_->set_length_and_media_out(old_length_);
|
||||
track->RippleRemoveBlock(new_block());
|
||||
block_->set_length_and_media_out(old_length_);
|
||||
track->RippleRemoveBlock(new_block());
|
||||
|
||||
// If we ran a reconnect command, disconnect now
|
||||
reconnect_tree_command_->undo_now();
|
||||
// If we ran a reconnect command, disconnect now
|
||||
reconnect_tree_command_->undo_now();
|
||||
}
|
||||
|
||||
//
|
||||
// BlockSplitPreservingLinksCommand
|
||||
//
|
||||
Block *BlockSplitPreservingLinksCommand::GetSplit(Block *original, int time_index) const
|
||||
Block *BlockSplitPreservingLinksCommand::GetSplit(Block *original,
|
||||
int time_index) const
|
||||
{
|
||||
if (time_index >= 0 && time_index < times_.size()) {
|
||||
int original_index = blocks_.indexOf(original);
|
||||
if (original_index != -1) {
|
||||
return splits_.at(time_index).at(original_index);
|
||||
}
|
||||
}
|
||||
if (time_index >= 0 && time_index < times_.size()) {
|
||||
int original_index = blocks_.indexOf(original);
|
||||
if (original_index != -1) {
|
||||
return splits_.at(time_index).at(original_index);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BlockSplitPreservingLinksCommand::prepare()
|
||||
{
|
||||
splits_.resize(times_.size());
|
||||
splits_.resize(times_.size());
|
||||
|
||||
for (int i=0;i<times_.size();i++) {
|
||||
const rational& time = times_.at(i);
|
||||
for (int i = 0; i < times_.size(); i++) {
|
||||
const rational &time = times_.at(i);
|
||||
|
||||
// FIXME: I realize this isn't going to work if the times aren't ordered. I'm lazy so rather
|
||||
// than writing in a sorting algorithm here, I'll just put an assert as a reminder
|
||||
// if this ever becomes an issue.
|
||||
Q_ASSERT(i == 0 || time > times_.at(i-1));
|
||||
// FIXME: I realize this isn't going to work if the times aren't ordered. I'm lazy so rather
|
||||
// than writing in a sorting algorithm here, I'll just put an assert as a reminder
|
||||
// if this ever becomes an issue.
|
||||
Q_ASSERT(i == 0 || time > times_.at(i - 1));
|
||||
|
||||
QVector<Block*> splits(blocks_.size());
|
||||
QVector<Block *> splits(blocks_.size());
|
||||
|
||||
for (int j=0;j<blocks_.size();j++) {
|
||||
Block* b = blocks_.at(j);
|
||||
for (int j = 0; j < blocks_.size(); j++) {
|
||||
Block *b = blocks_.at(j);
|
||||
|
||||
if (b->in() < time && b->out() > time) {
|
||||
BlockSplitCommand* split_command = new BlockSplitCommand(b, time);
|
||||
split_command->redo_now();
|
||||
splits.replace(j, split_command->new_block());
|
||||
commands_.append(split_command);
|
||||
} else {
|
||||
splits.replace(j, nullptr);
|
||||
}
|
||||
}
|
||||
if (b->in() < time && b->out() > time) {
|
||||
BlockSplitCommand *split_command =
|
||||
new BlockSplitCommand(b, time);
|
||||
split_command->redo_now();
|
||||
splits.replace(j, split_command->new_block());
|
||||
commands_.append(split_command);
|
||||
} else {
|
||||
splits.replace(j, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
splits_.replace(i, splits);
|
||||
}
|
||||
splits_.replace(i, splits);
|
||||
}
|
||||
|
||||
// Now that we've determined all the splits, we can relink everything
|
||||
for (int i=0;i<blocks_.size();i++) {
|
||||
Block* a = blocks_.at(i);
|
||||
// Now that we've determined all the splits, we can relink everything
|
||||
for (int i = 0; i < blocks_.size(); i++) {
|
||||
Block *a = blocks_.at(i);
|
||||
|
||||
for (int j=0;j<blocks_.size();j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < blocks_.size(); j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Block* b = blocks_.at(j);
|
||||
Block *b = blocks_.at(j);
|
||||
|
||||
if (Block::AreLinked(a, b)) {
|
||||
// These blocks are linked, ensure all the splits are linked too
|
||||
if (Block::AreLinked(a, b)) {
|
||||
// These blocks are linked, ensure all the splits are linked too
|
||||
|
||||
foreach (const QVector<Block*>& split_list, splits_) {
|
||||
NodeLinkCommand* blc = new NodeLinkCommand(split_list.at(i), split_list.at(j), true);
|
||||
blc->redo_now();
|
||||
commands_.append(blc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (const QVector<Block *> &split_list, splits_) {
|
||||
NodeLinkCommand *blc = new NodeLinkCommand(
|
||||
split_list.at(i), split_list.at(j), true);
|
||||
blc->redo_now();
|
||||
commands_.append(blc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -168,12 +176,12 @@ void BlockSplitPreservingLinksCommand::prepare()
|
||||
//
|
||||
void TrackSplitAtTimeCommand::prepare()
|
||||
{
|
||||
// Find Block that contains this time
|
||||
Block* b = track_->BlockContainingTime(point_);
|
||||
// Find Block that contains this time
|
||||
Block *b = track_->BlockContainingTime(point_);
|
||||
|
||||
if (b) {
|
||||
command_ = new BlockSplitCommand(b, point_);
|
||||
}
|
||||
if (b) {
|
||||
command_ = new BlockSplitCommand(b, point_);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,147 +23,146 @@
|
||||
|
||||
#include "node/output/track/track.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class BlockSplitCommand : public UndoCommand {
|
||||
public:
|
||||
BlockSplitCommand(Block* block, rational point) :
|
||||
block_(block),
|
||||
new_block_(nullptr),
|
||||
point_(point),
|
||||
reconnect_tree_command_(nullptr)
|
||||
{
|
||||
}
|
||||
BlockSplitCommand(Block *block, rational point)
|
||||
: block_(block)
|
||||
, new_block_(nullptr)
|
||||
, point_(point)
|
||||
, reconnect_tree_command_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BlockSplitCommand() override
|
||||
{
|
||||
delete reconnect_tree_command_;
|
||||
}
|
||||
virtual ~BlockSplitCommand() override
|
||||
{
|
||||
delete reconnect_tree_command_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Access the second block created as a result. Only valid after redo().
|
||||
*/
|
||||
Block* new_block()
|
||||
{
|
||||
return new_block_;
|
||||
}
|
||||
Block *new_block()
|
||||
{
|
||||
return new_block_;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
Block* block_;
|
||||
Block* new_block_;
|
||||
Block *block_;
|
||||
Block *new_block_;
|
||||
|
||||
rational old_length_;
|
||||
rational point_;
|
||||
rational old_length_;
|
||||
rational point_;
|
||||
|
||||
MultiUndoCommand* reconnect_tree_command_;
|
||||
|
||||
NodeInput moved_transition_;
|
||||
MultiUndoCommand *reconnect_tree_command_;
|
||||
|
||||
NodeInput moved_transition_;
|
||||
};
|
||||
|
||||
class BlockSplitPreservingLinksCommand : public UndoCommand {
|
||||
public:
|
||||
BlockSplitPreservingLinksCommand(const QVector<Block *> &blocks, const QList<rational>& times) :
|
||||
blocks_(blocks),
|
||||
times_(times)
|
||||
{
|
||||
}
|
||||
BlockSplitPreservingLinksCommand(const QVector<Block *> &blocks,
|
||||
const QList<rational> ×)
|
||||
: blocks_(blocks)
|
||||
, times_(times)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BlockSplitPreservingLinksCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
virtual ~BlockSplitPreservingLinksCommand() override
|
||||
{
|
||||
qDeleteAll(commands_);
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return blocks_.first()->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return blocks_.first()->project();
|
||||
}
|
||||
|
||||
Block *GetSplit(Block *original, int time_index) const;
|
||||
Block *GetSplit(Block *original, int time_index) const;
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override
|
||||
{
|
||||
for (int i=0; i<commands_.size(); i++) {
|
||||
commands_.at(i)->redo_now();
|
||||
}
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
for (int i = 0; i < commands_.size(); i++) {
|
||||
commands_.at(i)->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
for (int i=commands_.size()-1; i>=0; i--) {
|
||||
commands_.at(i)->undo_now();
|
||||
}
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
for (int i = commands_.size() - 1; i >= 0; i--) {
|
||||
commands_.at(i)->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QVector<Block *> blocks_;
|
||||
QVector<Block *> blocks_;
|
||||
|
||||
QList<rational> times_;
|
||||
QList<rational> times_;
|
||||
|
||||
QVector<UndoCommand*> commands_;
|
||||
|
||||
QVector< QVector<Block*> > splits_;
|
||||
QVector<UndoCommand *> commands_;
|
||||
|
||||
QVector<QVector<Block *>> splits_;
|
||||
};
|
||||
|
||||
class TrackSplitAtTimeCommand : public UndoCommand {
|
||||
public:
|
||||
TrackSplitAtTimeCommand(Track* track, rational point) :
|
||||
track_(track),
|
||||
point_(point),
|
||||
command_(nullptr)
|
||||
{
|
||||
}
|
||||
TrackSplitAtTimeCommand(Track *track, rational point)
|
||||
: track_(track)
|
||||
, point_(point)
|
||||
, command_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TrackSplitAtTimeCommand() override
|
||||
{
|
||||
delete command_;
|
||||
}
|
||||
virtual ~TrackSplitAtTimeCommand() override
|
||||
{
|
||||
delete command_;
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void prepare() override;
|
||||
virtual void prepare() override;
|
||||
|
||||
virtual void redo() override
|
||||
{
|
||||
if (command_) {
|
||||
command_->redo_now();
|
||||
}
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
if (command_) {
|
||||
command_->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
if (command_) {
|
||||
command_->undo_now();
|
||||
}
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
if (command_) {
|
||||
command_->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Track* track_;
|
||||
Track *track_;
|
||||
|
||||
rational point_;
|
||||
|
||||
UndoCommand* command_;
|
||||
rational point_;
|
||||
|
||||
UndoCommand *command_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "timelineundotrack.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -23,105 +23,102 @@
|
||||
|
||||
#include "node/output/track/track.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class TrackRippleRemoveBlockCommand : public UndoCommand
|
||||
namespace olive
|
||||
{
|
||||
public:
|
||||
TrackRippleRemoveBlockCommand(Track* track, Block* block) :
|
||||
track_(track),
|
||||
block_(block)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
class TrackRippleRemoveBlockCommand : public UndoCommand {
|
||||
public:
|
||||
TrackRippleRemoveBlockCommand(Track *track, Block *block)
|
||||
: track_(track)
|
||||
, block_(block)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
before_ = block_->previous();
|
||||
track_->RippleRemoveBlock(block_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
before_ = block_->previous();
|
||||
track_->RippleRemoveBlock(block_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
}
|
||||
|
||||
private:
|
||||
Track* track_;
|
||||
Track *track_;
|
||||
|
||||
Block* block_;
|
||||
|
||||
Block* before_;
|
||||
Block *block_;
|
||||
|
||||
Block *before_;
|
||||
};
|
||||
|
||||
class TrackPrependBlockCommand : public UndoCommand
|
||||
{
|
||||
class TrackPrependBlockCommand : public UndoCommand {
|
||||
public:
|
||||
TrackPrependBlockCommand(Track* track, Block* block) :
|
||||
track_(track),
|
||||
block_(block)
|
||||
{
|
||||
}
|
||||
TrackPrependBlockCommand(Track *track, Block *block)
|
||||
: track_(track)
|
||||
, block_(block)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
track_->PrependBlock(block_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
track_->PrependBlock(block_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->RippleRemoveBlock(block_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->RippleRemoveBlock(block_);
|
||||
}
|
||||
|
||||
private:
|
||||
Track* track_;
|
||||
Block* block_;
|
||||
Track *track_;
|
||||
Block *block_;
|
||||
};
|
||||
|
||||
class TrackInsertBlockAfterCommand : public UndoCommand
|
||||
{
|
||||
class TrackInsertBlockAfterCommand : public UndoCommand {
|
||||
public:
|
||||
TrackInsertBlockAfterCommand(Track* track, Block* block, Block* before) :
|
||||
track_(track),
|
||||
block_(block),
|
||||
before_(before)
|
||||
{
|
||||
}
|
||||
TrackInsertBlockAfterCommand(Track *track, Block *block, Block *before)
|
||||
: track_(track)
|
||||
, block_(block)
|
||||
, before_(before)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return block_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->RippleRemoveBlock(block_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->RippleRemoveBlock(block_);
|
||||
}
|
||||
|
||||
private:
|
||||
Track* track_;
|
||||
Track *track_;
|
||||
|
||||
Block* block_;
|
||||
Block *block_;
|
||||
|
||||
Block* before_;
|
||||
Block *before_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -129,37 +126,35 @@ private:
|
||||
*
|
||||
* Both blocks must have equal lengths.
|
||||
*/
|
||||
class TrackReplaceBlockCommand : public UndoCommand
|
||||
{
|
||||
class TrackReplaceBlockCommand : public UndoCommand {
|
||||
public:
|
||||
TrackReplaceBlockCommand(Track* track, Block* old, Block* replace) :
|
||||
track_(track),
|
||||
old_(old),
|
||||
replace_(replace)
|
||||
{
|
||||
}
|
||||
TrackReplaceBlockCommand(Track *track, Block *old, Block *replace)
|
||||
: track_(track)
|
||||
, old_(old)
|
||||
, replace_(replace)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return track_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
track_->ReplaceBlock(old_, replace_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
track_->ReplaceBlock(old_, replace_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->ReplaceBlock(replace_, old_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
track_->ReplaceBlock(replace_, old_);
|
||||
}
|
||||
|
||||
private:
|
||||
Track* track_;
|
||||
Block* old_;
|
||||
Block* replace_;
|
||||
|
||||
Track *track_;
|
||||
Block *old_;
|
||||
Block *replace_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "timelineundoworkarea.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -23,82 +23,83 @@
|
||||
|
||||
#include "node/project.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class WorkareaSetEnabledCommand : public UndoCommand {
|
||||
public:
|
||||
WorkareaSetEnabledCommand(Project *project, TimelineWorkArea* points, bool enabled) :
|
||||
project_(project),
|
||||
points_(points),
|
||||
old_enabled_(points_->enabled()),
|
||||
new_enabled_(enabled)
|
||||
{
|
||||
}
|
||||
WorkareaSetEnabledCommand(Project *project, TimelineWorkArea *points,
|
||||
bool enabled)
|
||||
: project_(project)
|
||||
, points_(points)
|
||||
, old_enabled_(points_->enabled())
|
||||
, new_enabled_(enabled)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return project_;
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return project_;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
points_->set_enabled(new_enabled_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
points_->set_enabled(new_enabled_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
points_->set_enabled(old_enabled_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
points_->set_enabled(old_enabled_);
|
||||
}
|
||||
|
||||
private:
|
||||
Project* project_;
|
||||
Project *project_;
|
||||
|
||||
TimelineWorkArea* points_;
|
||||
TimelineWorkArea *points_;
|
||||
|
||||
bool old_enabled_;
|
||||
|
||||
bool new_enabled_;
|
||||
bool old_enabled_;
|
||||
|
||||
bool new_enabled_;
|
||||
};
|
||||
|
||||
class WorkareaSetRangeCommand : public UndoCommand {
|
||||
public:
|
||||
WorkareaSetRangeCommand(TimelineWorkArea *workarea, const TimeRange& range, const TimeRange &old_range) :
|
||||
workarea_(workarea),
|
||||
old_range_(old_range),
|
||||
new_range_(range)
|
||||
{
|
||||
}
|
||||
WorkareaSetRangeCommand(TimelineWorkArea *workarea, const TimeRange &range,
|
||||
const TimeRange &old_range)
|
||||
: workarea_(workarea)
|
||||
, old_range_(old_range)
|
||||
, new_range_(range)
|
||||
{
|
||||
}
|
||||
|
||||
WorkareaSetRangeCommand(TimelineWorkArea *workarea, const TimeRange& range) :
|
||||
WorkareaSetRangeCommand(workarea, range, workarea->range())
|
||||
{
|
||||
}
|
||||
WorkareaSetRangeCommand(TimelineWorkArea *workarea, const TimeRange &range)
|
||||
: WorkareaSetRangeCommand(workarea, range, workarea->range())
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override
|
||||
{
|
||||
return Project::GetProjectFromObject(workarea_);
|
||||
}
|
||||
virtual Project *GetRelevantProject() const override
|
||||
{
|
||||
return Project::GetProjectFromObject(workarea_);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
workarea_->set_range(new_range_);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
workarea_->set_range(new_range_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
workarea_->set_range(old_range_);
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
workarea_->set_range(old_range_);
|
||||
}
|
||||
|
||||
private:
|
||||
TimelineWorkArea *workarea_;
|
||||
TimelineWorkArea *workarea_;
|
||||
|
||||
TimeRange old_range_;
|
||||
|
||||
TimeRange new_range_;
|
||||
TimeRange old_range_;
|
||||
|
||||
TimeRange new_range_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -22,95 +22,102 @@
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
const rational TimelineWorkArea::kResetIn = 0;
|
||||
const rational TimelineWorkArea::kResetOut = RATIONAL_MAX;
|
||||
|
||||
TimelineWorkArea::TimelineWorkArea(QObject *parent) :
|
||||
QObject(parent),
|
||||
workarea_enabled_(false)
|
||||
TimelineWorkArea::TimelineWorkArea(QObject *parent)
|
||||
: QObject(parent)
|
||||
, workarea_enabled_(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool TimelineWorkArea::enabled() const
|
||||
{
|
||||
return workarea_enabled_;
|
||||
return workarea_enabled_;
|
||||
}
|
||||
|
||||
void TimelineWorkArea::set_enabled(bool e)
|
||||
{
|
||||
workarea_enabled_ = e;
|
||||
emit EnabledChanged(workarea_enabled_);
|
||||
workarea_enabled_ = e;
|
||||
emit EnabledChanged(workarea_enabled_);
|
||||
}
|
||||
|
||||
const TimeRange &TimelineWorkArea::range() const
|
||||
{
|
||||
return workarea_range_;
|
||||
return workarea_range_;
|
||||
}
|
||||
|
||||
void TimelineWorkArea::set_range(const TimeRange &range)
|
||||
{
|
||||
workarea_range_ = range;
|
||||
emit RangeChanged(workarea_range_);
|
||||
workarea_range_ = range;
|
||||
emit RangeChanged(workarea_range_);
|
||||
}
|
||||
|
||||
bool TimelineWorkArea::load(QXmlStreamReader *reader)
|
||||
{
|
||||
rational range_in = this->in();
|
||||
rational range_out = this->out();
|
||||
rational range_in = this->in();
|
||||
rational range_out = this->out();
|
||||
|
||||
uint version = 0;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("version")) {
|
||||
version = attr.value().toUInt();
|
||||
}
|
||||
}
|
||||
Q_UNUSED(version)
|
||||
uint version = 0;
|
||||
XMLAttributeLoop(reader, attr)
|
||||
{
|
||||
if (attr.name() == QStringLiteral("version")) {
|
||||
version = attr.value().toUInt();
|
||||
}
|
||||
}
|
||||
Q_UNUSED(version)
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("enabled")) {
|
||||
this->set_enabled(reader->readElementText() != QStringLiteral("0"));
|
||||
} else if (reader->name() == QStringLiteral("in")) {
|
||||
range_in = rational::fromString(reader->readElementText().toStdString());
|
||||
} else if (reader->name() == QStringLiteral("out")) {
|
||||
range_out = rational::fromString(reader->readElementText().toStdString());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("enabled")) {
|
||||
this->set_enabled(reader->readElementText() != QStringLiteral("0"));
|
||||
} else if (reader->name() == QStringLiteral("in")) {
|
||||
range_in =
|
||||
rational::fromString(reader->readElementText().toStdString());
|
||||
} else if (reader->name() == QStringLiteral("out")) {
|
||||
range_out =
|
||||
rational::fromString(reader->readElementText().toStdString());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
TimeRange loaded_workarea(range_in, range_out);
|
||||
TimeRange loaded_workarea(range_in, range_out);
|
||||
|
||||
if (loaded_workarea != this->range()) {
|
||||
this->set_range(loaded_workarea);
|
||||
}
|
||||
if (loaded_workarea != this->range()) {
|
||||
this->set_range(loaded_workarea);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimelineWorkArea::save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
writer->writeAttribute(QStringLiteral("version"), QString::number(1));
|
||||
|
||||
writer->writeTextElement(QStringLiteral("enabled"), QString::number(this->enabled()));
|
||||
writer->writeTextElement(QStringLiteral("in"), QString::fromStdString(this->in().toString()));
|
||||
writer->writeTextElement(QStringLiteral("out"), QString::fromStdString(this->out().toString()));
|
||||
writer->writeTextElement(QStringLiteral("enabled"),
|
||||
QString::number(this->enabled()));
|
||||
writer->writeTextElement(QStringLiteral("in"),
|
||||
QString::fromStdString(this->in().toString()));
|
||||
writer->writeTextElement(QStringLiteral("out"),
|
||||
QString::fromStdString(this->out().toString()));
|
||||
}
|
||||
|
||||
const rational &TimelineWorkArea::in() const
|
||||
{
|
||||
return workarea_range_.in();
|
||||
return workarea_range_.in();
|
||||
}
|
||||
|
||||
const rational &TimelineWorkArea::out() const
|
||||
{
|
||||
return workarea_range_.out();
|
||||
return workarea_range_.out();
|
||||
}
|
||||
|
||||
const rational &TimelineWorkArea::length() const
|
||||
{
|
||||
return workarea_range_.length();
|
||||
return workarea_range_.length();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,41 +26,40 @@
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
using namespace core;
|
||||
|
||||
class TimelineWorkArea : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class TimelineWorkArea : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimelineWorkArea(QObject* parent = nullptr);
|
||||
TimelineWorkArea(QObject *parent = nullptr);
|
||||
|
||||
bool enabled() const;
|
||||
void set_enabled(bool e);
|
||||
bool enabled() const;
|
||||
void set_enabled(bool e);
|
||||
|
||||
const rational& in() const;
|
||||
const rational& out() const;
|
||||
const rational& length() const;
|
||||
const TimeRange& range() const;
|
||||
void set_range(const TimeRange& range);
|
||||
const rational &in() const;
|
||||
const rational &out() const;
|
||||
const rational &length() const;
|
||||
const TimeRange &range() const;
|
||||
void set_range(const TimeRange &range);
|
||||
|
||||
bool load(QXmlStreamReader *reader);
|
||||
void save(QXmlStreamWriter *writer) const;
|
||||
bool load(QXmlStreamReader *reader);
|
||||
void save(QXmlStreamWriter *writer) const;
|
||||
|
||||
static const rational kResetIn;
|
||||
static const rational kResetOut;
|
||||
static const rational kResetIn;
|
||||
static const rational kResetOut;
|
||||
|
||||
signals:
|
||||
void EnabledChanged(bool e);
|
||||
void EnabledChanged(bool e);
|
||||
|
||||
void RangeChanged(const TimeRange& r);
|
||||
void RangeChanged(const TimeRange &r);
|
||||
|
||||
private:
|
||||
bool workarea_enabled_;
|
||||
|
||||
TimeRange workarea_range_;
|
||||
bool workarea_enabled_;
|
||||
|
||||
TimeRange workarea_range_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user